crown  1.0.0
src/annealing.cpp
Go to the documentation of this file.
00001 /*
00002   Copyright 2015 Nicolas Melot
00003 
00004   This file is part of Crown.
00005 
00006   Crown is free software: you can redistribute it and/or modify
00007   it under the terms of the GNU General Public License as published by
00008   the Free Software Foundation, either version 3 of the License, or
00009   (at your option) any later version.
00010 
00011   Crown is distributed in the hope that it will be useful,
00012   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014   GNU General Public License for more details.
00015 
00016   You should have received a copy of the GNU General Public License
00017   along with Crown. If not, see <http://www.gnu.org/licenses/>.
00018 
00019 */
00020 
00021 
00022 #include <fstream>
00023 #include <set>
00024 
00025 #include <cstdlib>
00026 
00027 #include <crown/allocation.h>
00028 #include <crown/mapping.h>
00029 #include <crown/scaling.h>
00030 #include <crown/crown.h>
00031 
00032 #include <pelib/AmplInput.hpp>
00033 #include <pelib/AmplOutput.hpp>
00034 #include <pelib/Vector.hpp>
00035 #include <pelib/Matrix.hpp>
00036 #include <pelib/Set.hpp>
00037 
00038 #include <crown/allocation.h>
00039 #include <crown/CrownScheduler.hpp>
00040 
00041 #ifdef debug
00042 #undef debug
00043 #endif
00044 
00045 #if 01
00046 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << var << "\"" << endl;
00047 #else
00048 #define debug(var)
00049 #endif
00050 
00051 using namespace pelib;
00052 using namespace std;
00053 
00054 namespace pelib
00055 {
00056     namespace crown
00057     {
00058 
00059         Algebra
00060         neighbor_allocation(const Algebra &solution, float tasks, float cores)
00061         {
00062             Algebra schedule = solution;
00063             // distance == 1 -> change all neighbors by +- Wi processors
00064             // distance == 0 -> change only one neighbor by 1 processor
00065 
00066             map<int, float> vector_wi = schedule.find<Vector<int, float> >("wi")->getValues();
00067             int b = (int)schedule.find<Scalar<float> >("b")->getValue();
00068             int p = (int)schedule.find<Scalar<float> >("p")->getValue();
00069             const Vector<int, float> *Wi = schedule.find<Vector<int, float> >("Wi");
00070             map<int, float> vector_Wi = Wi->getValues();
00071             int n = vector_wi.size();
00072 
00073             int num_tasks = ((int)((float)rand() / (float)RAND_MAX * n * tasks));
00074             while (num_tasks > 0 && vector_Wi.size() > 0)
00075             {
00076                 int size = vector_Wi.size();
00077                 map<int, float>::iterator itask = vector_Wi.begin();
00078                 int index = rand() % size;
00079 
00080                 for(int i = 0; i < index; i++)
00081                 {
00082                     itask++;
00083                 }
00084 
00085                 // If a task is sequential, there is no neighbor to find there, remove that task from list and continue
00086                 if(itask->second < 2)
00087                 {
00088                     vector_Wi.erase(itask);
00089                     continue;
00090                 }
00091 
00092                 // Task maximal width > 1 (Wit > 0)
00093                 int task = itask->first;
00094                 int Wit = (int)vector_Wi[task];
00095                 Wit = Wit > p ? p : Wit;
00096                 Wit = (int)(log(Wit) / log(b));
00097 
00098                 // task current allocated width
00099                 int wi = (int)(log(vector_wi.find(task)->second) / log(b));
00100 
00101                 int amplitude = Wit * (int)cores; // + 1 to count the number of possibilities, -1 to remove the current allocation from possible new allocation
00102                 amplitude = amplitude < 1 ? 1 : amplitude; // Make sure at least one transformation is performed
00103 
00104                 // Count how many spots are available below and above current wi
00105                 int avail_lower = wi;
00106                 int avail_higher = Wit - wi;
00107         
00108                 // Cound how many spots we need below and above current wi
00109                 int wi_lower, wi_higher;
00110                 if(rand() % 2 == 0)
00111                 {
00112                     wi_lower = (int)floor((float)amplitude / 2);
00113                     wi_higher = (int)ceil((float)amplitude / 2);
00114                 }
00115                 else
00116                 {
00117                     wi_lower = (int)ceil((float)amplitude / 2);
00118                     wi_higher = (int)floor((float)amplitude / 2);
00119                 }
00120                 
00121                 int len_lower, len_higher;
00122                 if(avail_lower >= wi_lower && avail_higher >=wi_higher)
00123                 {
00124                     len_lower = wi_lower;
00125                     len_higher = wi_higher;
00126                 }
00127                 else if(avail_lower < wi_lower)
00128                 {
00129                     len_lower = avail_lower;
00130                     len_higher = wi_higher + (wi_lower - avail_lower);
00131                 }
00132                 else if(avail_higher < wi_higher)
00133                 {
00134                     len_higher = avail_higher;
00135                     len_lower = wi_lower + (wi_higher - avail_higher);
00136                 }
00137                 else
00138                 {
00139                     // Not enough space to fit the amplitude, aborting
00140                     cerr << "# Not enough allocation opportunities to fit the amplitude" << endl;
00141                     cerr << "# Task " << task << "; p = " << p << "; log2(Wi) = " << Wit << "; log2(wi) = " << wi << "; amplitude = " << amplitude << "; avail_lower = " << avail_lower << "; avail_higher = " << avail_higher << "; wi_lower = " << wi_lower << "; wi_higher = " << wi_higher << endl; 
00142                     abort();
00143                 }
00144 
00145                 int alternative = ((int)rand() % (amplitude)) + 1; // Start counting the new allocation number with 1
00146                 int new_wi = 0;
00147                 if(alternative <= len_lower)
00148                 {
00149                     new_wi = wi - (len_lower - alternative + 1);
00150                 }
00151                 else if(alternative <= len_lower + len_higher)
00152                 {
00153                     new_wi = wi + alternative - len_lower;
00154                 }
00155                 else
00156                 {
00157                     cerr << "# Chosen alternative is beyond the spots available" << endl;
00158                     cerr << "# Task " << task << "; p = " << p << "; log2(Wi) = " << Wit << "; log2(wi) = " << wi << "; amplitude = " << amplitude << "; avail_lower = " << avail_lower << "; avail_higher = " << avail_higher << "; wi_lower = " << wi_lower << "; wi_higher = " << wi_higher << "; alternative = " << alternative << endl; 
00159                     len_lower = avail_lower;
00160                     len_higher = wi_higher + (wi_lower - avail_lower);
00161                 }
00162                         
00163                 if(wi == new_wi || new_wi > Wit || new_wi < 0)
00164                 {
00165                     cerr << "# Task " << task << "; Wi " << Wit << "; wi " << wi << "; amplitude " << amplitude << "; new_wi " << new_wi << endl;
00166                     abort();
00167                 }
00168 
00169                 new_wi = (int)pow((double)b, (double)new_wi);
00170                 if(new_wi == 64)
00171                 {
00172                     cerr << "# Task " << task << "; Wi " << Wit << "; wi " << wi << "; amplitude " << amplitude << "; new_wi " << new_wi << endl;
00173                 }
00174                 vector_wi[task] = new_wi;
00175 
00176                 // Done with this task, continue with the next
00177                 vector_Wi.erase(itask);
00178                 num_tasks--;
00179 
00180             }
00181 
00182             Vector<int, float> wi("wi", vector_wi);
00183             schedule.insert(&wi);
00184 
00185             return schedule;
00186         }
00187 
00188         Algebra
00189         neighbor_allocation_full(const Algebra &solution, float distance)
00190         {
00191             return neighbor_allocation(solution, distance, distance);
00192         }
00193 
00194         Algebra
00195         neighbor_allocation_tasks(const Algebra &solution, float distance)
00196         {
00197             return neighbor_allocation(solution, distance, 0);
00198         }
00199 
00200         Algebra
00201         neighbor_allocation_cores(const Algebra &solution, float distance)
00202         {
00203             return neighbor_allocation(solution, 0, distance);
00204         }
00205 
00206         Algebra
00207         neighbor_efficiency(const Algebra &solution, float distance)
00208         {
00209             Algebra schedule = solution;
00210         
00211             const Scalar<float> *gemin = schedule.find<Scalar<float> >("gemin");
00212             if(gemin == NULL)
00213             {
00214                 gemin = new Scalar<float>("gemin", 0);
00215                 schedule.insert(gemin);
00216                 delete gemin;
00217                 gemin = schedule.find<Scalar<float> >("gemin");
00218             }
00219             float gemin_val = gemin->getValue();
00220 
00221             const Scalar<float> *gemax = schedule.find<Scalar<float> >("gemax");
00222             if(gemax == NULL)
00223             {
00224                 gemax = new Scalar<float>("gemax", 1);
00225                 schedule.insert(gemax);
00226                 delete gemax;
00227                 gemax = schedule.find<Scalar<float> >("gemax");
00228             }
00229             float gemax_val = gemax->getValue();
00230 
00231             // The whole universe we can vary the global minimal efficiency in 
00232             float universe = gemax_val - gemin_val;
00233 
00234             const Scalar<float> *geuse = schedule.find<Scalar<float> >("geuse");
00235             float geuse_val = 0;
00236             if(geuse == NULL)
00237             {
00238                 // The initial value is somewhere between gemin and gemax ( = gemin + rand() * universe )
00239                 geuse = new Scalar<float>("geuse", gemin_val + (universe * ((float)rand() / RAND_MAX)));
00240                 schedule.insert(geuse);
00241                 delete geuse;
00242                 geuse = schedule.find<Scalar<float> >("geuse");
00243             }
00244             else
00245             {
00246                 geuse_val = geuse->getValue();
00247                 float random = (float)rand() / RAND_MAX;
00248                 geuse_val = geuse_val + (random * universe * distance);
00249 
00250                 if(geuse_val < gemin_val)
00251                 {
00252                     geuse_val += gemin_val - geuse_val;
00253                 }
00254                 else if(geuse_val > gemax_val)
00255                 {
00256                     geuse_val -= geuse_val - gemax_val;
00257                 }
00258 
00259                 if (geuse_val < gemin_val || geuse_val > gemax_val)
00260                 {
00261                     // Something went terribly wrong
00262                     cerr << "Geuse val went off the chart despite (or because of) the out-of-universe problem fix" << endl;
00263                     cerr << "geuse_val = " << geuse_val << "; gemin = " << gemin_val << "; gemax = " << gemax_val << "; universe = " << universe << "; random = " << random << ";distance = " << distance << endl; 
00264                 }
00265             }
00266 
00267             // Reallocate
00268             return allocation_gemin(schedule, geuse_val);
00269         }
00270 
00271         float
00272         quality_simple(const Algebra &schedule)
00273         {
00274             //int n = schedule.find<Scalar<float> >("n")->getValue();
00275             int p = (int)schedule.find<Scalar<float> >("p")->getValue();
00276             float alpha = schedule.find<Scalar<float> >("alpha")->getValue();
00277             float zeta = schedule.find<Scalar<float> >("zeta")->getValue();
00278             float M = schedule.find<Scalar<float> >("M")->getValue();
00279             Vector<int, float> tau = schedule.find<Vector<int, float> >("Tau");
00280             Vector<int, float> Wi = schedule.find<Vector<int, float> >("Wi");
00281             Vector<int, float> wi = schedule.find<Vector<int, float> >("wi");
00282             Vector<int, float> frequency = schedule.find<Vector<int, float> >("frequency");
00283             Vector<int, float> group = schedule.find<Vector<int, float> >("group");
00284             Matrix<int, int, float> e = schedule.find<Matrix<int, int, float> >("e");
00285         
00286             double static_energy = M * p;
00287             double dynamic_energy = 0;
00288 
00289             // Now evaluate the quality of this schedule
00290             for(map<int, float>::const_iterator i = group.getValues().begin(); i != group.getValues().end(); i++)
00291             {
00292                 int task = i->first;
00293 
00294                 float tau_t = tau.find(task);
00295                 int width_t = (int)wi.find(task);
00296                 width_t = width_t > p ? p : width_t;
00297                 int f_t = (int)frequency.find(task);
00298 
00299                 double area = (double)tau_t / (double)(e.find(width_t, task)) / (double)frequency.find(task);
00300                 static_energy -= area;
00301                 dynamic_energy += area * pow(f_t, alpha);
00302             }
00303 
00304             return dynamic_energy + zeta * static_energy;
00305         }
00306 
00307         float
00308         energy_static_dynamic_busy_idle_active(const Algebra &solution)
00309         {
00310             Algebra rec = CrownScheduler::crownToSchedule(solution);
00311             int n = rec.find<Scalar<float> >("n")->getValue();
00312             int p = rec.find<Scalar<float> >("p")->getValue();
00313             float M = rec.find<Scalar<float> >("M")->getValue();
00314             float kappa = rec.find<Scalar<float> >("kappa")->getValue();
00315             float eta = rec.find<Scalar<float> >("eta")->getValue();
00316             float zeta = rec.find<Scalar<float> >("zeta")->getValue();
00317             float alpha = rec.find<Scalar<float> >("alpha")->getValue();
00318             Vector<int, float> tau = rec.find<Vector<int, float> >("Tau");
00319             const Vector<int, string> *nameptr = rec.find<Vector<int, string> >("name");
00320             Vector<int, string> name("name", nameptr != NULL ? nameptr->getValues() : map<int, string>());
00321         
00322             Vector<int, float> Wi = rec.find<Vector<int, float> >("Wi");
00323             Vector<int, float> frequency = rec.find<Vector<int, float> >("frequency");
00324             Set<float> F = rec.find<Set<float> >("F");
00325             Matrix<int, int, float> e = rec.find<Matrix<int, int, float> >("e");
00326             Matrix<int, int, float> schedule = rec.find<Matrix<int, int, float> >("schedule");
00327             Vector<int, float> wi = rec.find<Vector<int, float> >("wi");
00328             vector<double> busy_task(n, 0);
00329             vector<double> area_task(n, 0);
00330             vector<double> met_task(n, 0);
00331         
00332             float lowest_freq = *(F.getValues().begin());
00333             kappa = kappa * lowest_freq;
00334             eta = eta * (zeta * pow(lowest_freq, alpha) + (1 - zeta) * (lowest_freq + kappa)) / zeta;
00335             double idle_energy = p * M * pow(lowest_freq, alpha);
00336             double busy_energy = 0;
00337 
00338             map<float, int> core_active;
00339             for(size_t i = 0; i < (size_t)p; i++)
00340             {
00341                 core_active[i + 1] = 0;
00342             }
00343             int total_core_active = 0;
00344 
00345             // Iterate through all task names until we find the dummy task;
00346             vector<size_t> dummy_index;
00347             size_t index = 0;
00348             for(map<int, string>::const_iterator i = name.getValues().begin(); i != name.getValues().end(); i++, index++)
00349             {
00350                 stringstream ss;
00351                 ss << DUMMY_TASK << " " << index + 1;
00352                 if(string(i->second).compare(ss.str()) == 0)
00353                 {
00354                     dummy_index.push_back(index + 1);   
00355                 }
00356             }
00357 
00358             // Now evaluate the quality of this schedule
00359             float total_area = 0;
00360             for(map<int, map<int, float> >::const_iterator i = schedule.getValues().begin(); i != schedule.getValues().end(); i++)
00361             {
00362                 //int core = i->first;
00363                 for(map<int, float>::const_iterator j = i->second.begin(); j != i->second.end(); j++)
00364                 {
00365                     //int index = j->first;
00366                     int task = j->second;
00367                     //cout << "Core " << core << ", task " << task << endl;
00368 
00369                     // Check if the task index is a dummy task
00370                     bool dummy = false;
00371                     for(size_t k = 0; k < dummy_index.size(); k++)
00372                     {
00373                         if((size_t)task == dummy_index[k])
00374                         {
00375                             dummy = true;
00376                             break;
00377                         }
00378                     }
00379 
00380                     // We don't take dummy task power consumption into account
00381                     if(task > 0 && !dummy)
00382                     {
00383                         float width_t = wi.getValues().find(task)->second;
00384                         double time = (double)tau.find(task) / (width_t * e.find(width_t, task) * (double)frequency.find(task));
00385                         total_area += time;
00386                         float power = (zeta * pow(frequency.find(task), alpha) + (1 - zeta) * (frequency.find(task) + kappa)) / zeta;
00387                         busy_energy += time * power;
00388 
00389                         // Mark this core as active
00390                         if(core_active[i->first] == 0)
00391                         {
00392                             core_active[i->first] = 1;
00393                             total_core_active++;
00394                         }
00395                     }
00396                 }
00397             }
00398 
00399             idle_energy = (M * (total_core_active) - total_area) * eta;
00400 
00401             return zeta * busy_energy + (1 - zeta) * idle_energy;
00402         }
00403 
00404         static
00405         float
00406         energy_static_idle(const Algebra &schedule, float epsilon)
00407         {
00408             int p = (int)schedule.find<Scalar<float> >("p")->getValue();
00409             float alpha = schedule.find<Scalar<float> >("alpha")->getValue();
00410             float zeta = schedule.find<Scalar<float> >("zeta")->getValue();
00411             float minF = *(schedule.find<Set<float> >("F")->getValues().begin());
00412         
00413             float M;
00414             const Scalar<float> *float_M = schedule.find<Scalar<float> >("M");
00415             if(float_M != NULL)
00416             {
00417                 M = float_M->getValue();
00418             }
00419             else
00420             {
00421                 const Scalar<float> *int_M = schedule.find<Scalar<float> >("M");
00422                 M = int_M->getValue();
00423             }
00424 
00425             Vector<int, float> tau = schedule.find<Vector<int, float> >("Tau");
00426             Vector<int, float> Wi = schedule.find<Vector<int, float> >("Wi");
00427             Vector<int, float> wi = schedule.find<Vector<int, float> >("wi");
00428             Vector<int, float> frequency = schedule.find<Vector<int, float> >("frequency");
00429             Vector<int, float> group = schedule.find<Vector<int, float> >("group");
00430             Matrix<int, int, float> e = schedule.find<Matrix<int, int, float> >("e");
00431         
00432             double idle_energy = 0;
00433             double busy_energy = 0;
00434             double total_area = 0;
00435 
00436             // Now evaluate the quality of this schedule
00437             for(map<int, float>::const_iterator i = group.getValues().begin(); i != group.getValues().end(); i++)
00438             {
00439                 int task = i->first;
00440 
00441                 float tau_t = tau.find(task);
00442                 float width_t = wi.find(task);
00443                 width_t = width_t > p ? p : width_t;
00444                 //double e_wt = e.find(width_t, task);
00445                 float f_t = frequency.find(task);
00446 
00447                 double area = (double)tau_t / (double)(e.find((int)width_t, task)) / (double)frequency.find(task);
00448 
00449                 total_area += area;
00450                 busy_energy += area * pow(f_t, alpha) + zeta * f_t;
00451             }
00452             idle_energy = (p * M - total_area) * pow(minF, alpha) + zeta * minF;
00453 
00454             return busy_energy + epsilon * idle_energy;
00455         }
00456 
00457         float
00458         quality_generic(const Algebra &schedule)
00459         {
00460             int p = (int)schedule.find<Scalar<float> >("p")->getValue();
00461             float alpha = schedule.find<Scalar<float> >("alpha")->getValue();
00462             float alpha_static = schedule.find<Scalar<float> >("alpha-static")->getValue();
00463             float zeta = schedule.find<Scalar<float> >("zeta")->getValue();
00464             float epsilon = schedule.find<Scalar<float> >("epsilon")->getValue();
00465             float minF = *(schedule.find<Set<float> >("F")->getValues().begin());
00466         
00467             float M;
00468             const Scalar<float> *float_M = schedule.find<Scalar<float> >("M");
00469             if(float_M != NULL)
00470             {
00471                 M = float_M->getValue();
00472             }
00473             else
00474             {
00475                 const Scalar<float> *int_M = schedule.find<Scalar<float> >("M");
00476                 M = int_M->getValue();
00477             }
00478 
00479             Vector<int, float> tau = schedule.find<Vector<int, float> >("Tau");
00480             Vector<int, float> Wi = schedule.find<Vector<int, float> >("Wi");
00481             Vector<int, float> wi = schedule.find<Vector<int, float> >("wi");
00482             Vector<int, float> frequency = schedule.find<Vector<int, float> >("frequency");
00483             Vector<int, float> group = schedule.find<Vector<int, float> >("group");
00484             Matrix<int, int, float> e = schedule.find<Matrix<int, int, float> >("e");
00485         
00486             double idle_energy = 0;
00487             double busy_energy = 0;
00488             double total_area = 0;
00489 
00490             // Now evaluate the quality of this schedule
00491             for(map<int, float>::const_iterator i = group.getValues().begin(); i != group.getValues().end(); i++)
00492             {
00493                 int task = i->first;
00494 
00495                 float tau_t = tau.find(task);
00496                 float width_t = wi.find(task);
00497                 width_t = width_t > p ? p : width_t;
00498                 float f_t = frequency.find(task);
00499 
00500                 double area = (double)tau_t / (double)(e.find((int)width_t, task)) / (double)frequency.find(task);
00501 
00502                 total_area += area;
00503                 busy_energy += area * pow(f_t, alpha) + zeta * f_t;
00504             }
00505             idle_energy = (p * M - total_area) * pow(minF, alpha_static) + zeta * minF;
00506 
00507             return busy_energy + epsilon * idle_energy;
00508         }
00509 
00510         float
00511         quality_idle(const Algebra &schedule)
00512         {
00513             return energy_static_idle(schedule, 0.5);
00514         }
00515 
00516         float
00517         quality_off(const Algebra &schedule)
00518         {
00519             return energy_static_idle(schedule, 0);
00520         }
00521 
00522 // This is not possible now that we allow energy saving
00523 // by switchingu nused cores off
00524 #if RETURN_EARLY
00525 #define return_now_if_best(solution) if(solution.find<Scalar<float> >("all_sequential")->getValue() == 1 && solution.find<Scalar<float> >("frequency_optimal")->getValue() == 1) return solution
00526 #else
00527 #define return_now_if_best(solution)
00528 #endif
00529 
00530         Algebra
00531         annealing(const Algebra &initial, const Algebra &initial_best, float (*quality)(const Algebra &solution), Algebra (*neighbor)(const Algebra &solution, float distance), float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00532         {
00533             Algebra schedule = initial;
00534             schedule = neighbor(schedule, distance);
00535 
00536             float m;
00537             int counter = 0;
00538             float T = temperature;
00539 
00540             Algebra best = initial_best;
00541             float best_q = quality(best);
00542             Vector<int, float> *best_solution = initial_best.find<Vector<int, float> >("wi")->clone();
00543             float q = quality(schedule);
00544 
00545             while (T > final)
00546             {
00547                 int new_state = 0;
00548 
00549                 for(int i = 0; i < max_transform; i++)
00550                 {
00551                     // Keep track of the solution of last iteration
00552                     Vector<int, float> *old_solution = schedule.find<Vector<int, float> >("wi")->clone();
00553                     float old_q = q;
00554 
00555                     // Transform the solution
00556                     schedule = neighbor(schedule, distance);
00557                     schedule = mapping_ltlg(schedule);
00558                     schedule = frequency_height(schedule);
00559 
00560                     m = schedule.find<Scalar<float> >("m")->getValue();
00561                     q = quality(schedule);
00562                         
00563                     // If the new energy is lower than the previous one, then we accept this solution
00564                     if (q - old_q <= 0 && m >= 0)
00565                     {
00566                         delete old_solution;
00567 
00568                         // If this solution is better than the best found so far, then keep this best solution
00569                         if (q < best_q)
00570                         {
00571                             best_solution = schedule.find<Vector<int, float> >("wi")->clone();
00572                             best_q = q;
00573                         }
00574 
00575                         // One new state validated
00576                         new_state++;
00577                     }
00578                     else
00579                     {
00580                         // Randomly accept a degrading solution, more likely when the temperature is higher
00581                         if (rand() / RAND_MAX <= exp(-(q - old_q) / T) && m >= 0)
00582                         {
00583                             // Update current solution
00584                             delete old_solution;
00585 
00586                             // One new state validated
00587                             new_state++;
00588                         }
00589                         else
00590                         {
00591                             // Revert old solution 
00592                             schedule.insert(old_solution);
00593                             q = old_q;
00594                         }
00595                     }
00596                         
00597                     // Too much successful transformations
00598                     if(new_state == max_new_state) 
00599                     {
00600                         break;
00601                     }
00602                 }
00603         
00604                 T = T * cooling;
00605                 counter++;
00606             }
00607 
00608             schedule.insert(best_solution);
00609             schedule = mapping_ltlg(schedule);
00610             schedule = frequency_height(schedule);
00611 
00612             return schedule;
00613         }
00614 
00615         float
00616         annealing_complexity(float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00617         {
00618             return max_transform * ceil(log(temperature / final) / log(1 / cooling));
00619         }
00620 
00621     }
00622 }