00001
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;
00013 Object_t min_object (object), last_object (object);
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
00021 #ifdef GNUPLOT
00022 cout << i << "\t" << new_costs << '\n';
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
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
00035 } }
00036
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;
00047 Object_t min_object (object), last_object (object);
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
00055 #ifdef GNUPLOT
00056 cout << i << "\t" << new_costs << '\n';
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
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
00070 } } }
00071
00072 object= min_object;
00073 return min_costs;
00074 }
00075
00076
00077
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;
00087 if (el.size() > 0) {
00088 int nextn= angel::random (int (el.size()));
00089 El_spec_t next= el[nextn];
00090 return eh.elimination (next) > 0; } }
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;
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;
00110 if (!okay) return false; }
00111 return true;
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;
00126 if (el.size() > 0) {
00127 int nextn= angel::random (int (el.size()));
00128 El_spec_t next= el[nextn];
00129 return eh.elimination (next) > 0; } }
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
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;
00152 if (el.size() > 0) {
00153 int nextn= angel::random (int (el.size()));
00154 El_spec_t next= el[nextn];
00155 return eh.elimination (next) > 0; } }
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;
00164 eh_copy.seq.erase (it);
00165 reinsertable= eh_copy.rebuild_graph ();
00166
00167
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
00178
00179
00180 void gamma_adaption_max_t::operator() (int costs, double& gamma) {
00181 if (imp >= D) return;
00182 if (last_min == 0) {
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) {
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
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
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
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;
00241 Object_t min_object (object), last_object (object);
00242 GMPI::comm_ref_t<int, Object_t> comm_ref (last_object);
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
00254 #ifdef GNUPLOT
00255 log_file << i+ii << "\t" << new_costs << " # gnuplot \n";
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
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
00268 } }
00269
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 }
00275
00276 i+= inner_iter;
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 }
00284
00285
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);
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 }