sa_impl.hpp

Go to the documentation of this file.
00001 // $Id: sa_impl.hpp,v 1.4 2004/04/23 12:59:11 gottschling Exp $
00002 
00003 #ifdef USE_MPI
00004 #include "angel_comm.hpp"
00005 #endif // USE_MPI
00006 
00007 namespace angel {
00008   using std::vector;
00009 
00010 template <class Object_t, class Neighbor_t, class Cost_t, class Temp_t>
00011 int SA (Object_t& object, Neighbor_t neighbor, Cost_t costs, Temp_t temp, int max_iter) {
00012   int min_costs= costs (object), last_costs= min_costs; // initial costs
00013   Object_t min_object (object), last_object (object); // corresponding objects
00014 
00015   for (int i= 0; i < max_iter; i++) {
00016     Object_t new_object (last_object);
00017     if (!neighbor (new_object)) {
00018       cout << "No neighbor found!"; return -1;}
00019     int new_costs= costs (new_object);
00020     // cout << "LSA costs: " << new_costs;
00021 #ifdef GNUPLOT
00022     cout << i << "\t" << new_costs << '\n'; // for gnuplot
00023 #endif
00024     if (new_costs < last_costs) {
00025       if (new_costs < min_costs) {
00026         min_costs= new_costs; min_object= new_object; }
00027       last_costs= new_costs; last_object= new_object; 
00028       // cout << " accepted due to improvement";
00029     } else {
00030       double acc= SA_acceptance (last_costs-new_costs, i, temp);
00031       double ra= angel::random (1.0);
00032       if (ra < acc) {
00033         last_costs= new_costs; last_object= new_object; 
00034         // cout << " accepted due to Metropolis";
00035       } } 
00036     // cout << '\n'; 
00037   }
00038   object= min_object;
00039   return min_costs;
00040 }
00041 
00042 template <class Object_t, class Neighbor_t, class Cost_t, class Adaption_t>
00043 int ALSA (Object_t& object, Neighbor_t neighbor, Cost_t costs, Adaption_t adaption,
00044           double& gamma, int max_iter) {
00045 
00046   int min_costs= costs (object), last_costs= min_costs; // initial costs
00047   Object_t min_object (object), last_object (object); // corresponding objects
00048 
00049   for (int i= 0; i < max_iter; i++) {
00050     Object_t new_object (last_object);
00051     if (!neighbor (new_object)) {
00052       cout << "No neighbor found!"; return -1;}
00053     int new_costs= costs (new_object);
00054     //cout << "LSA costs: " << new_costs << '\n';
00055 #ifdef GNUPLOT
00056     cout << i << "\t" << new_costs << '\n'; // for gnuplot
00057 #endif
00058     adaption (new_costs, gamma);
00059     if (new_costs < last_costs) {
00060       if (new_costs < min_costs) {
00061         min_costs= new_costs; min_object= new_object; }
00062       last_costs= new_costs; last_object= new_object; 
00063       // cout << "new configuration accepted due to improvement\n";
00064     } else {
00065       double acc= exp ((last_costs-new_costs) / gamma * log (double (i+2)));
00066       double ra= angel::random (1.0);
00067       if (ra < acc) {
00068         last_costs= new_costs; last_object= new_object; 
00069         // cout << "new configuration accepted due to Metropolis\n";
00070       } } }
00071 
00072   object= min_object;
00073   return min_costs;
00074 }
00075 
00076 // =====================================================
00077 // neighbourhoods
00078 // =====================================================
00079 
00080   template <class Ad_graph_t, class El_spec_t>
00081   bool neighbor_last_removable_t::operator() (elimination_history_t<Ad_graph_t, El_spec_t>& eh) {
00082     bool eliminate= eh.seq.size() == 0 || angel::random (1.0) < .5;
00083     if (eliminate) {
00084       vector<El_spec_t>   el;
00085       eliminatable_objects (eh.cg, el);
00086       if (el.empty() && eh.seq.empty()) return false; // graph was always bipartite
00087       if (el.size() > 0) {  // if nothing to eliminate -> re-insert
00088         int nextn= angel::random (int (el.size()));
00089         El_spec_t next= el[nextn];
00090         return eh.elimination (next) > 0; } } // elimination successful ?
00091     eh.seq.resize (eh.seq.size()-1);
00092     return eh.rebuild_graph (); 
00093   }
00094 
00095 // -------------------------------------------------------------------------
00096 
00097   template <class Ad_graph_t, class El_spec_t>
00098   bool neighbor_multi_step_t::operator() (elimination_history_t<Ad_graph_t, El_spec_t>& eh) {
00099     bool eliminate= eh.seq.size() == 0 || angel::random (1.0) < .5;
00100     int steps= angel::random (1, max_steps);
00101     if (eliminate) {
00102       for (int i= 0; i < steps; i++) {
00103         vector<El_spec_t>   el;
00104         eliminatable_objects (eh.cg, el);
00105         if (el.empty() && eh.seq.empty()) return false; // graph was always bipartite
00106         if (el.size() == 0) return true;
00107         int nextn= angel::random (int (el.size()));
00108         El_spec_t next= el[nextn];
00109         bool okay= eh.elimination (next) > 0; // elimination successful ?
00110         if (!okay) return false; }
00111       return true; // enough eliminations
00112     } else {
00113       eh.seq.resize (std::max (int (eh.seq.size())-steps, 0));
00114       return eh.rebuild_graph (); } 
00115   }
00116 
00117 // -------------------------------------------------------------------------
00118 
00119   template <class Ad_graph_t, class El_spec_t>
00120   bool neighbor_sequence_check_t::operator() (elimination_history_t<Ad_graph_t, El_spec_t>& eh) {
00121     bool eliminate= eh.seq.size() == 0 || angel::random (1.0) < .5;
00122     if (eliminate) {
00123       vector<El_spec_t>   el;
00124       eliminatable_objects (eh.cg, el);
00125       if (el.empty() && eh.seq.empty()) return false; // graph was always bipartite
00126       if (el.size() > 0) {  // if nothing to eliminate -> re-insert
00127         int nextn= angel::random (int (el.size()));
00128         El_spec_t next= el[nextn];
00129         return eh.elimination (next) > 0; } } // elimination successful ?
00130 
00131     int next_re_ins;
00132     bool reinsertable= false;
00133     for (int c= 1; !reinsertable; c++) {
00134       next_re_ins= angel::random_high (int (eh.seq.size()), c);
00135       vector<El_spec_t> seq_copy (eh.seq);
00136       typename vector<El_spec_t>::iterator it= eh.seq.begin() + next_re_ins;
00137       eh.seq.erase (it);
00138       reinsertable= eh.rebuild_graph ();
00139       // if reinsertion failed then restore old seq, cg is unchanged then
00140       if (!reinsertable) eh.seq.swap (seq_copy); }
00141     return true; }
00142 
00143 // -------------------------------------------------------------------------
00144 
00145   template <class Ad_graph_t, class El_spec_t>
00146   bool neighbor_check_meta_t::operator() (elimination_history_t<Ad_graph_t, El_spec_t>& eh) {
00147     bool eliminate= eh.seq.size() == 0 || angel::random (1.0) < .5;
00148     if (eliminate) {
00149       vector<El_spec_t>   el;
00150       eliminatable_objects (eh.cg, el);
00151       if (el.empty() && eh.seq.empty()) return false; // graph was always bipartite
00152       if (el.size() > 0) {  // if nothing to eliminate -> re-insert
00153         int nextn= angel::random (int (el.size()));
00154         El_spec_t next= el[nextn];
00155         return eh.elimination (next) > 0; } } // elimination successful ?
00156 
00157     int next_re_ins;
00158     bool reinsertable= false;
00159     for (int c= 1; !reinsertable; c++) {
00160       next_re_ins= angel::random_high (int (eh.seq.size()), c);
00161       elimination_history_t<Ad_graph_t, El_spec_t> eh_copy (eh);
00162       typename vector<El_spec_t>::iterator it= eh_copy.seq.begin() + next_re_ins;
00163       El_spec_t re= *it;  // removed elimination
00164       eh_copy.seq.erase (it);
00165       reinsertable= eh_copy.rebuild_graph ();
00166       // if successful check if new graph (eh_copy.cg) is predecessor of eh.cg
00167       // eh_copy.cg --re--> eh.cg
00168       if (reinsertable) {
00169         Ad_graph_t copy_copy (eh_copy.cg);
00170         angel::eliminate (re, copy_copy);
00171         reinsertable= eh.cg == copy_copy; }
00172       if (reinsertable) eh= eh_copy; }
00173     return true; }
00174 
00175 
00176 // =====================================================
00177 // Gamma adaption operators
00178 // =====================================================
00179 
00180   void gamma_adaption_max_t::operator() (int costs, double& gamma) {
00181     if (imp >= D) return;
00182     if (last_min == 0) { // very first iteration must be distinguished
00183       last_max= last_min= costs; return; }
00184     if (costs < last_min) {
00185       diff= last_max - costs; last_max= last_min= costs;
00186       if (diff > max_diff) max_diff= diff;
00187       if (++imp >= D) gamma= scaling * double (max_diff);
00188     } else if (costs > last_max) last_max= costs;
00189   }
00190 
00191   void gamma_adaption_average_t::operator() (int costs, double& gamma) {
00192     if (imp >= D) return;
00193     if (last_min == 0) { // very first iteration must be distinguished
00194       last_max= last_min= costs; return; }
00195     if (costs < last_min) {
00196       sum_diff+= last_max - costs; last_max= last_min= costs;
00197       if (++imp >= D) {gamma= scaling * double (sum_diff) / double (imp); }
00198     } else if (costs > last_max) last_max= costs;
00199   }
00200 
00201 // ============ Parallel computations only if USE_MPI is defined ====================
00202 
00203 #ifdef USE_MPI
00204 
00205 template <class Temp_t>
00206 int pick_processor_sa (int my_costs, int it, Temp_t temp, const GMPI::Intracomm& comm) {
00207   int          me= comm.Get_rank(), size= comm.Get_size(),  picked;
00208   vector<int>  all_costs (size);
00209   comm.Gather (&my_costs, 1, MPI::INT, &all_costs[0], 1, MPI::INT, 0);
00210   if (me == 0) {
00211     int min_costs= *min_element (all_costs.begin(), all_costs.end());
00212     // compute acceptance probs and their partial sums
00213     vector<double>  acc_probs (size), psum_probs (size);
00214     for (size_t c= 0; c < size; c++)
00215       acc_probs[c]= SA_acceptance (min_costs - all_costs[c], it, temp);
00216     partial_sum (acc_probs.begin(), acc_probs.end(), psum_probs.begin());
00217     // pick one according to probabilities
00218     double sum_probs= psum_probs[size-1], ra= angel::random (sum_probs);
00219     for (picked= 0; picked < size; picked++)
00220       if (ra < psum_probs[picked]) break;
00221     THROW_DEBUG_EXCEPT_MACRO (picked == size, consistency_exception, "No processor picked");
00222 #ifdef WRITE_LOG_FILE
00223     THROW_DEBUG_EXCEPT_MACRO (!log_file.is_open(), io_exception, "Log file not opened");    
00224     log_file << "pick_processor_sa at iteration " << it << endl;
00225     write_vector (log_file, "Processor's costs: ", all_costs);
00226     write_vector (log_file, "Accumulated probabilities: ", psum_probs);
00227     log_file << "Random value: " << ra << " --> picked processor " << picked << endl;
00228 #endif
00229   }
00230   comm.Bcast (&picked, 1, MPI::INT, 0);
00231   return picked;
00232 }
00233 
00234 template <class Object_t, class Neighbor_t, class Cost_t, class Inner_temp_t, class Outer_temp_t,
00235           class Pre_comm_t, class Post_comm_t>
00236 int parallel_SA (Object_t& object, Neighbor_t neighbor, Cost_t costs, 
00237                  Inner_temp_t inner_temp, Outer_temp_t outer_temp, int inner_iter, int max_iter,
00238                  const GMPI::Intracomm& comm, Pre_comm_t pre_comm, Post_comm_t post_comm) {
00239 
00240   int min_costs= costs (object), last_costs= min_costs; // initial costs
00241   Object_t min_object (object), last_object (object); // corresponding objects
00242   GMPI::comm_ref_t<int, Object_t> comm_ref (last_object); // reference used in communication
00243 
00244   for (int i= 0; i < max_iter; i++) {
00245 
00246     int ii; bool inner_completion;
00247     for (ii= 0, inner_completion= false; !inner_completion; ) {
00248 
00249       Object_t new_object (last_object);
00250       if (!neighbor (new_object)) {
00251         cout << "No neighbor found!"; return -1;}
00252       int new_costs= costs (new_object);
00253       // log_file << "LSA costs: " << new_costs;
00254 #ifdef GNUPLOT
00255       log_file << i+ii << "\t" << new_costs << "   # gnuplot \n"; // different files per proc with MPI
00256 #endif
00257       if (new_costs < last_costs) {
00258         if (new_costs < min_costs) {
00259           min_costs= new_costs; min_object= new_object; }
00260         last_costs= new_costs; last_object= new_object; 
00261         // log_file << " accepted due to improvement";
00262       } else {
00263         double acc= SA_acceptance (last_costs-new_costs, i, inner_temp);
00264         double ra= angel::random (1.0);
00265         if (ra < acc) {
00266           last_costs= new_costs; last_object= new_object; 
00267           // log_file << " accepted due to Metropolis";
00268         } } 
00269       // log_file << '\n'; 
00270       if (++ii == inner_iter) { 
00271         inner_completion= true;
00272         mark_completion (comm.mpi_comm_ref());
00273       } else inner_completion= test_completion (comm.mpi_comm_ref());
00274     } // inner for loop
00275 
00276     i+= inner_iter; // all proc are handled as having finished inner loop here
00277     if (i < max_iter) {
00278       clean_completion_messages (comm.mpi_comm_ref());
00279       pre_comm (last_object);
00280       int sa_root= pick_processor_sa (last_costs, i, outer_temp, comm);
00281       comm.Bcast (comm_ref, sa_root); 
00282       post_comm (last_object); }
00283   } // outer for loop
00284 
00285   // now look for global minimum
00286   int me= comm.Get_rank(); 
00287   std::pair<int,int> my_min_costs_rank (min_costs, me), min_costs_rank;
00288   comm.Allreduce (&my_min_costs_rank, &min_costs_rank, 1, MPI::TWOINT, MPI::MINLOC); 
00289   int min_root= min_costs_rank.second;
00290   GMPI::comm_ref_t<int, Object_t> min_comm_ref (min_object); // reference to min
00291   comm.Bcast (min_comm_ref, min_root);
00292 
00293   object= min_object;
00294   return min_root;
00295 }
00296 
00297 #endif // USE_MPI
00298 
00299 } // namespace angel

Generated on Wed Mar 11 10:33:11 2009 for angel by  doxygen 1.5.3