GeneticAlgorithm.cpp

Go to the documentation of this file.
00001 /** @file GeneticAlgorithm.cpp
00002 * @author Gabor Madl
00003 * @date Created 08/2005
00004 * @brief Genetic algorithm library.
00005 *
00006 *
00007 * =================================================================
00008 * DREAM License v2.0
00009 * 
00010 * DREAM - Distributed Real-time Embedded Analysis Method
00011 * http://dre.sourceforge.net.
00012 * Copyright (c) 2005-2007 Gabor Madl, All Rights Reserved.
00013 * 
00014 * This file is part of DREAM.
00015 * 
00016 * DREAM is free software; you can redistribute it and/or modify it
00017 * under the terms of the GNU General Public License version 2 as
00018 * published by the Free Software Foundation. No future versions of
00019 * the GPL license may be automatically applied to DREAM. It is in
00020 * the sole discretion of the copyright holder to determine whether
00021 * DREAM may be released under a different license or terms. There
00022 * are no restrictions on the use of DREAM for any purpose.
00023 * 
00024 * DREAM is distributed in the hope that it will be useful,
00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00027 * GNU General Public License for more details.
00028 * 
00029 * You should have received a copy of the GNU General Public License
00030 * along with this program; if not, write to the Free Software
00031 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00032 * MA 02110-1301, USA.
00033 * 
00034 * By submitting comments, suggestions, code, code snippets,
00035 * techniques (including that of usage), and algorithms, submitters
00036 * acknowledge that they have the right to do so, that any such
00037 * submissions are given freely and unreservedly, and that they
00038 * waive any claims to copyright or ownership. In addition,
00039 * submitters acknowledge that any such submission might become
00040 * part of the copyright maintained on the overall body of code,
00041 * which comprises DREAM. By making a submission, submitter agrees
00042 * to these terms. Furthermore, submitters acknowledge that the
00043 * incorporation or modification of such submissions is entirely
00044 * at the discretion of the moderators of the DREAM project.
00045 * 
00046 * DREAM links to the Libxml2 third party library. Please see 
00047 * COPYING-libxml for the copyright information of the libxml software.
00048 * =================================================================
00049 */
00050 
00051 #include "GeneticAlgorithm.h"
00052 
00053 namespace DREAM
00054 {
00055 
00056 std::ostream& operator<< (std::ostream& out, DREAM::Solution& solution)
00057 {
00058         TASK_AVLTREE::iterator task_iter;
00059         out << "f:" << solution.fitness_;
00060         for (task_iter = solution.task_avltree_.begin (); 
00061                 task_iter != solution.task_avltree_.end (); ++task_iter)
00062         {
00063                 out << " " << task_iter->second->subpriority ();
00064         }
00065         out << "\n";
00066         return out;
00067 }
00068 
00069 /////////////////////////////////////////////////////////////////////////////
00070 //
00071 // Solution
00072 //
00073 /////////////////////////////////////////////////////////////////////////////
00074 
00075 Solution::Solution (DREAM::System* system_ptr)
00076 : copy_ (false)
00077 {
00078         system_ptr_ = system_ptr;
00079         system_ptr->visitor_task_avltree (&task_avltree_);
00080 }
00081 
00082 Solution::~Solution ()
00083 {
00084         if (copy_)
00085                 task_avltree_.destroy ();
00086 }
00087 
00088 bool Solution::deterministic ()
00089 {
00090         std::map<uint, uint> subpriority_map;
00091         std::map<uint, uint>::iterator uint_iter;
00092         TASK_AVLTREE::iterator task_iter;
00093 
00094         for (task_iter = task_avltree_.begin (); 
00095                 task_iter != task_avltree_.end (); ++task_iter)
00096         {
00097                         uint_iter = subpriority_map.find (task_iter->second->subpriority ());
00098                         if (uint_iter != subpriority_map.end ())
00099                                 return false;
00100 
00101                         subpriority_map.insert (std::pair<uint, uint> (task_iter->second->subpriority (), 0));
00102         }
00103 
00104         return true;
00105 }
00106 
00107 double Solution::fitness (bool verbose, bool deterministic, double* endtoend)
00108 {
00109         double score = 0.0, priority_score, subpriority_score;
00110         DREAM::TASK_AVLTREE error_avltree;
00111 
00112         system_ptr_->visitor_update_task_avltree (&task_avltree_);
00113         system_ptr_->reset ();
00114         system_ptr_->simulate (verbose, deterministic, endtoend);
00115 
00116         system_ptr_->visitor_error_avltree (&error_avltree);
00117         
00118         if (error_avltree.empty ())
00119         {
00120                 fitness_ = 0;
00121                 return 0.0;
00122         }
00123 
00124         DREAM::TASK_AVLTREE::const_iterator error_iter;
00125         DREAM::Task* task_ptr;
00126 
00127         for (error_iter = error_avltree.begin (); error_iter != error_avltree.end (); error_iter++)
00128         {
00129                 task_ptr = error_iter->second;
00130                 priority_score = task_ptr->priority () + 1;
00131                 subpriority_score = task_ptr->subpriority () + 1;
00132                 
00133                 score += (2 * (1/priority_score)) + (1/subpriority_score);
00134         }
00135 
00136         fitness_ = score;
00137         return score;
00138 }
00139 
00140 void Solution::generate_priorities ()
00141 #ifdef DREAM_ENHANCED_EXCEPTION_CHECKING
00142         throw (DREAM::Exception)
00143 #endif
00144 {
00145         if (copy_)
00146         {
00147 #ifdef DREAM_ENHANCED_EXCEPTION_CHECKING
00148                 throw DREAM::Exception ("Solution::generate_priorities () may be called only once for a Solution.");
00149 #else
00150                 return;
00151 #endif
00152         }
00153 
00154         // Create a new copy of the tasks
00155         copy_ = true;
00156 
00157         TASK_AVLTREE::iterator iter;
00158 
00159         for (iter = task_avltree_.begin (); iter != task_avltree_.end (); iter++)
00160         {
00161                 iter->second = new DREAM::Task (*iter->second);
00162         }
00163 
00164         uint i = 0;
00165 
00166         // Assign subpriorities.
00167         for (iter = task_avltree_.begin (); iter != task_avltree_.end (); iter++)
00168         {
00169                 iter->second->subpriority (i++);
00170         }
00171 
00172         regenerate_priorities ();
00173 }
00174 
00175 void Solution::generate_subpriorities ()
00176 #ifdef DREAM_ENHANCED_EXCEPTION_CHECKING
00177         throw (DREAM::Exception)
00178 #endif
00179 {
00180         if (copy_)
00181         {
00182 #ifdef DREAM_ENHANCED_EXCEPTION_CHECKING
00183                 throw DREAM::Exception ("Solution::generate_priorities () may be called only once for a Solution.");
00184 #else
00185                 return;
00186 #endif
00187         }
00188 
00189         // Create a new copy of the tasks
00190         copy_ = true;
00191 
00192         TASK_AVLTREE::iterator iter;
00193 
00194         for (iter = task_avltree_.begin (); iter != task_avltree_.end (); iter++)
00195         {
00196                 iter->second = new DREAM::Task (*iter->second);
00197         }
00198 
00199         uint i = 0;
00200 
00201         // Assign subpriorities.
00202         for (iter = task_avltree_.begin (); iter != task_avltree_.end (); iter++)
00203         {
00204                 iter->second->subpriority (i++);
00205         }
00206 
00207         regenerate_subpriorities ();
00208 }
00209 
00210 void Solution::regenerate_priorities ()
00211 {
00212         // We need to manipulate both priorities and subpriorities
00213         // Generate random priorities - unlike sub-priorities, priorities are not expected to be unique
00214         // Iterator approach is a lot faster than looking up threads for tasks
00215 
00216         const DREAM::SCHEDULER_MAP* scheduler_map = system_ptr_->scheduler_map ();
00217         DREAM::SCHEDULER_MAP::const_iterator scheduler_iter;
00218 
00219         const DREAM::THREAD_MAP* thread_map;
00220         DREAM::THREAD_MAP::const_iterator thread_iter;
00221         DREAM::TASK_AVLTREE task_avltree;
00222         DREAM::TASK_AVLTREE::iterator task_iter;
00223         
00224         for (scheduler_iter = scheduler_map->begin (); scheduler_iter != scheduler_map->end (); scheduler_iter++)
00225         {
00226                 thread_map = scheduler_iter->second->thread_map ();
00227                 
00228                 // We extract threads to an AVLTree to allow fast lookups when assigning random priorities
00229                 // Reimplement this, not working
00230                 DREAM::AVLTree<uint, const DREAM::Thread*> thread_avltree;
00231 
00232                 for (thread_iter = thread_map->begin (); thread_iter != thread_map->end (); thread_iter++)
00233                 {
00234                         thread_avltree.insert (thread_iter->first, thread_iter->second);
00235                 }
00236 
00237                 // Let's assign the random priorities...
00238                 // Extract tasks for the current scheduler
00239                 scheduler_iter->second->visitor_task_avltree (&task_avltree);
00240 
00241                 for (task_iter = task_avltree.begin (); task_iter != task_avltree.end (); task_iter++)
00242                 {
00243                         // Get random priority lane index
00244                         uint index = (uint) random (scheduler_iter->second->threadpoolsize ());
00245                 
00246                         // Assign priority to tasks
00247                         task_iter->second->priority (task_avltree[index]->priority ());
00248                 }
00249         }
00250 
00251         // Generate random subpriorities
00252         regenerate_subpriorities ();
00253 }
00254 
00255 void Solution::regenerate_subpriorities ()
00256 {
00257         // Generate random but deterministic schedule efficiently
00258         for (uint i = 0; i < task_avltree_.size () - 1; i++)
00259         {
00260                 uint rand = (uint) random (task_avltree_.size () - i) + i;
00261                 uint subpriority_temp = task_avltree_[rand]->subpriority ();
00262                 task_avltree_[rand]->subpriority (task_avltree_[i]->subpriority ());
00263                 task_avltree_[i]->subpriority (subpriority_temp);               
00264         }
00265 
00266         fitness (false, true);
00267 }
00268 
00269 void Solution::visitor (std::string& out)
00270 {
00271         TASK_AVLTREE::iterator task_iter;
00272 
00273         for (task_iter = task_avltree_.begin (); 
00274                 task_iter != task_avltree_.end (); task_iter++)
00275         {
00276                 out << "\tTask " << task_iter->second->id () << " p: " << task_iter->second->priority () << " sp: " << task_iter->second->subpriority () << "\n";
00277         }
00278         out << "Fitness: ";
00279         
00280         char number[double_size];
00281         snprintf (number, double_size, "%.8f", fitness_);
00282         out << number << "\n";
00283 }
00284 
00285 /////////////////////////////////////////////////////////////////////////////
00286 //
00287 // GeneticOptimize
00288 //
00289 /////////////////////////////////////////////////////////////////////////////
00290 
00291 GeneticOptimize::GeneticOptimize ()
00292 {
00293 }
00294 
00295 void GeneticOptimize::mutate (DREAM::Solution* solution) const
00296 {
00297         // Generate random mutations with 30% probability - seems pretty good
00298         for (uint i = 0; i < solution->task_avltree_.size (); i++)
00299         {
00300                 uint rand = (uint) random (solution->task_avltree_.size () - i) + i;
00301 
00302                 if ((uint) random (2) == 0)
00303                 {
00304                         uint subpriority_temp = solution->task_avltree_[rand]->subpriority ();
00305                         solution->task_avltree_[rand]->subpriority (solution->task_avltree_[i]->subpriority ());
00306                         solution->task_avltree_[i]->subpriority (subpriority_temp);             
00307                 }
00308         }
00309 
00310         solution->fitness (false, true);
00311 }
00312 
00313 void GeneticOptimize::mutate (DREAM::Solution* father, DREAM::Solution* mother, DREAM::Solution* child) const
00314 {
00315         uint i;
00316         for (i = 0; i < father->task_avltree_.size (); i++)
00317         {
00318                 child->task_avltree_[i]->subpriority (father->task_avltree_[i]->subpriority ());
00319         }
00320 
00321         for (i = 0; i < child->task_avltree_.size (); i++)
00322         {
00323                 bool swap = false;
00324 
00325                 if (father->task_avltree_[i]->subpriority () == 
00326                         mother->task_avltree_[i]->subpriority ())
00327                 {
00328                         // 10% - the value is probably correct...
00329                         if ((uint) random (9) == 0)
00330                                 swap = true;
00331                 }
00332                 else
00333                 {
00334                         // 62.5% - the value is probably incorrect...
00335                         if ((uint) random (7) > 2)
00336                                 swap = true;
00337                 }
00338 
00339                 if (swap)
00340                 {
00341                         // We swap the value with the one present in the mother
00342                         uint j;
00343                         for (j = 0; mother->task_avltree_[j]->subpriority () != 
00344                                                 child->task_avltree_[i]->subpriority (); j++)
00345                         {
00346                                 // We shouldn't get an infinite loop here
00347                         }
00348 
00349                         // Swap
00350                         uint subpriority_temp = child->task_avltree_[i]->subpriority ();
00351                         child->task_avltree_[i]->subpriority (child->task_avltree_[j]->subpriority ());
00352                         child->task_avltree_[j]->subpriority (subpriority_temp);                
00353                 }
00354         }
00355 
00356         child->fitness (false, true);
00357 }
00358 
00359 void GeneticOptimize::thread_level (DREAM::System* system_ptr)
00360 {
00361         if (Option::optimization_space_ < 8)
00362                 Option::optimization_space_ = 8;
00363         bool perfect = false;
00364         time_t start_time;
00365         time (&start_time);
00366 
00367         std::cout << std::endl << "Thread-level scheduling optimization." << std::endl;
00368 
00369         // Initialize
00370         system_ptr_ = system_ptr;
00371         
00372         for (uint i = 0; i < Option::optimization_space_; i++)
00373         {
00374                 DREAM::Solution* solution_ptr = new DREAM::Solution (system_ptr);
00375                 solution_ptr->generate_subpriorities ();
00376                 solution_vector_.push_back (solution_ptr);
00377         }
00378 
00379         std::sort (solution_vector_.begin (), solution_vector_.end ());
00380 
00381         uint e;
00382         for (e = 0; e < Option::number_of_repetitions_; e++)
00383         {
00384                 uint i;
00385 
00386                 for (i = ((uint) solution_vector_.size () / 8*3); i < ((uint) solution_vector_.size () / 4 * 3); i++)
00387                 {
00388                         // Mutations from parents
00389                         uint father = (uint) random ((uint) solution_vector_.size () / 8 * 3);
00390                         uint mother = (uint) random ((uint) solution_vector_.size () / 8 * 3);
00391                         mutate (solution_vector_[father], solution_vector_[mother], solution_vector_[i]);
00392                 }
00393 
00394                 for (i = 1; i < ((uint) solution_vector_.size () / 8 * 3); i++)
00395                 {
00396                         // Mutations from single sources
00397                         mutate (solution_vector_[i]);
00398                 }
00399 
00400                 for (i = ((uint) solution_vector_.size () / 4 * 3); i < solution_vector_.size (); i++)
00401                 {
00402                         // Regenerations
00403                         solution_vector_[i]->regenerate_subpriorities ();
00404                 }
00405 
00406 /* This would show the whole design space.
00407 
00408                 std::cout << "Solution:\n";
00409                 for (i = 0; i < solution_vector_.size (); i++)
00410                 {
00411                         if (i == ((uint) solution_vector_.size () / 8 * 3))
00412                                 std::cout << "\n";
00413                         else if (i == ((uint) solution_vector_.size () / 4 * 3))
00414                                 std::cout << "\n";
00415 
00416                         std::cout << *solution_vector_[i];
00417                 }
00418                 std::cout << std::endl;
00419 */
00420                 std::sort (solution_vector_.begin (), solution_vector_.end (), sort_solutions ());
00421 
00422 /* This would show the best solution for every iteration.
00423                 std::cout << *solution_vector_[0];
00424 */
00425 
00426                 if (solution_vector_[0]->fitness_ == 0.0)
00427                 {
00428                         perfect = true;
00429                         break;
00430                 }
00431         }
00432 
00433         if (perfect)
00434         std::cout << "Optimal solution found in " 
00435                 << e << " iterations with optimization space "
00436                 << Option::optimization_space_ << ".\n";
00437         else
00438         std::cout << "Solution found in " 
00439                 << e << " iterations with optimization space "
00440                 << Option::optimization_space_ << ".\n";
00441 
00442         std::string message;
00443         solution_vector_[0]->visitor (message);
00444 
00445         // solution_vector_[0] contains the best solution, let's update the system...
00446         system_ptr_->visitor_update_task_avltree (&solution_vector_[0]->task_avltree_);
00447         system_ptr_->reset ();
00448 
00449         // Delete optimization space
00450         std::for_each (solution_vector_.begin (), solution_vector_.end (), delete_object ());
00451 
00452         solution_vector_.clear ();
00453 
00454         time_t end_time;
00455         time (&end_time);
00456         uint perf = end_time - start_time;
00457         std::cout << message << "\nEnd of priority assignment optimization." << std::endl
00458                 << "Analysis time: " << perf << " seconds." << std::endl;
00459 }
00460 
00461 void GeneticOptimize::CPU_level (DREAM::System* system_ptr)
00462 {
00463         if (Option::optimization_space_ < 8)
00464                 Option::optimization_space_ = 8;
00465         bool perfect = false;
00466         time_t start_time;
00467         time (&start_time);
00468 
00469         std::cout << std::endl << "CPU-level scheduling optimization started." << std::endl;
00470 
00471         // Initialize
00472         system_ptr_ = system_ptr;
00473         
00474         for (uint i = 0; i < Option::optimization_space_; i++)
00475         {
00476                 DREAM::Solution* solution_ptr = new DREAM::Solution (system_ptr);
00477                 solution_ptr->generate_subpriorities ();
00478                 solution_vector_.push_back (solution_ptr);
00479         }
00480 
00481         std::sort (solution_vector_.begin (), solution_vector_.end ());
00482 
00483         uint e;
00484         for (e = 0; e < Option::number_of_repetitions_; e++)
00485         {
00486                 uint i;
00487 
00488                 for (i = ((uint) solution_vector_.size () / 8*3); i < ((uint) solution_vector_.size () / 4 * 3); i++)
00489                 {
00490                         // Mutations from parents
00491                         uint father = (uint) random ((uint) solution_vector_.size () / 8 * 3);
00492                         uint mother = (uint) random ((uint) solution_vector_.size () / 8 * 3);
00493                         mutate (solution_vector_[father], solution_vector_[mother], solution_vector_[i]);
00494                 }
00495 
00496                 for (i = 1; i < ((uint) solution_vector_.size () / 8 * 3); i++)
00497                 {
00498                         // Mutations from single sources
00499                         mutate (solution_vector_[i]);
00500                 }
00501 
00502                 for (i = ((uint) solution_vector_.size () / 4 * 3); i < solution_vector_.size (); i++)
00503                 {
00504                         // Regenerations
00505                         solution_vector_[i]->regenerate_subpriorities ();
00506                 }
00507 
00508 /* This would show the whole design space.
00509 
00510                 std::cout << "Solution:\n";
00511                 for (i = 0; i < solution_vector_.size (); i++)
00512                 {
00513                         if (i == ((uint) solution_vector_.size () / 8 * 3))
00514                                 std::cout << "\n";
00515                         else if (i == ((uint) solution_vector_.size () / 4 * 3))
00516                                 std::cout << "\n";
00517 
00518                         std::cout << *solution_vector_[i];
00519                 }
00520                 std::cout << std::endl;
00521 */
00522                 std::sort (solution_vector_.begin (), solution_vector_.end (), sort_solutions ());
00523 
00524 /* This would show the best solution for every iteration.
00525                 std::cout << *solution_vector_[0];
00526 */
00527 
00528                 if (solution_vector_[0]->fitness_ == 0.0)
00529                 {
00530                         perfect = true;
00531                         break;
00532                 }
00533         }
00534 
00535         if (perfect)
00536         std::cout << "Optimal solution found in " 
00537                 << e << " iterations with optimization space "
00538                 << Option::optimization_space_ << ".\n";
00539         else
00540         std::cout << "Solution found in " 
00541                 << e << " iterations with optimization space "
00542                 << Option::optimization_space_ << ".\n";
00543 
00544         std::string message;
00545         solution_vector_[0]->visitor (message);
00546 
00547         // solution_vector_[0] contains the best solution, let's update the system...
00548         system_ptr_->visitor_update_task_avltree (&solution_vector_[0]->task_avltree_);
00549         system_ptr_->reset ();
00550 
00551         // Delete optimization space
00552         std::for_each (solution_vector_.begin (), solution_vector_.end (), delete_object ());
00553 
00554         solution_vector_.clear ();
00555 
00556         time_t end_time;
00557         time (&end_time);
00558         uint perf = end_time - start_time;
00559         std::cout << message << "\nEnd of priority assignment optimization." << std::endl
00560                 << "Analysis time: " << perf << " seconds." << std::endl;
00561 }
00562 
00563 };
00564 

Generated on Fri Jul 27 18:30:03 2007 for DREAM by  doxygen 1.5.1