58 mt = std::mt19937_64(
rd());
79 mt = std::mt19937_64(rd());
95 return energy + ham->getEconst();
100 this->max_angle = max_angle;
105 this->delta_angle = delta_angle;
110 this->start_temp = start_temp;
115 this->delta_temp = delta_temp;
125 std::uniform_real_distribution<double> dist_accept(0, 1);
131 double chance = std::exp((energy - e_new) / cur_temp);
133 if ( dist_accept(mt) * (1+chance) > chance)
147 method->BuildHam(*ham);
150 energy = method->getEnergy();
159 orbtrans->fillHamCI(*ham);
161 method->BuildHam(*ham);
164 return method->getEnergy();
172 std::uniform_int_distribution<int> dist(0, ham->getL()-1);
173 std::uniform_real_distribution<double> dist_angles(0, 1);
176 double lowest_energy = energy;
177 cur_temp = start_temp;
180 MPI_Comm_size(MPI_COMM_WORLD, &size);
181 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
183 std::stringstream out_name;
184 out_name << getenv(
"SAVE_H5_PATH") <<
"/output-" << rank <<
".txt";
186 std::ostream* fp = &std::cout;
190 fout.open(out_name.str(), std::ios::out | std::ios::app);
193 std::ostream &out = *fp;
199 for(
int i=0;i<ham->getL();i++)
200 for(
int j=i+1;j<ham->getL();j++)
201 if(ham->getOrbitalIrrep(i) != ham->getOrbitalIrrep(j))
202 sample_pairs(i,j) = sample_pairs(j,i) = -1;
206 for(
unsigned int i=0;i<max_steps;i++)
208 auto orb1 = dist(mt);
209 auto orb2 = dist(mt);
211 if(orb1 != orb2 && ham->getOrbitalIrrep(orb1) == ham->getOrbitalIrrep(orb2))
213 sample_pairs(orb1, orb2) += 1;
214 sample_pairs(orb2, orb1) += 1;
217 double cur_angle = max_angle * (dist_angles(mt) - dist_angles(mt));
219 out <<
"P=" << rank <<
"\t" << i <<
"\tT=" << cur_temp <<
"\tOrb1=" << orb1 <<
"\tOrb2=" << orb2 <<
" Over " << cur_angle << std::endl;
221 auto uni_copy = orbtrans->get_unitary();
222 orbtrans->get_unitary().jacobi_rotation(ham->getOrbitalIrrep(orb1), orb1, orb2, cur_angle);
224 auto new_energy = calc_new_energy();
226 if(new_energy < lowest_energy)
227 lowest_energy = new_energy;
229 out <<
"P=" << rank <<
"\t" << i <<
"\tT=" << cur_temp <<
"\tNew energy = " << new_energy + ham->getEconst() <<
"\t Old energy = " << get_energy();
231 if(accept_function(new_energy))
234 out <<
"\t=> Accepted" << std::endl;
239 out <<
"\t=> Unaccepted, " << unaccepted << std::endl;
241 orbtrans->get_unitary() = std::move(uni_copy);
244 cur_temp *= delta_temp;
245 max_angle *= delta_angle;
268 out <<
"Accuracy down to " << bp_meth->
get_tol_PD() << std::endl;
269 out <<
"Bottom was " << lowest_energy + ham->getEconst() << std::endl;
270 out <<
"Final energy = " << get_energy() << std::endl;
272 for(
int i=0;i<ham->getL();i++)
273 for(
int j=i+1;j<ham->getL();j++)
274 if(sample_pairs(i,j) >= 0)
275 out << ham->getOrbitalIrrep(i) <<
"\t" << i <<
"\t" << j <<
"\t" << sample_pairs(i,j) << std::endl;
283 return orbtrans->get_unitary();
342 MPI_Comm_size(MPI_COMM_WORLD, &size);
343 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
345 std::stringstream out_name;
346 out_name << getenv(
"SAVE_H5_PATH") <<
"/output-" << rank <<
".txt";
348 method->set_outfile(out_name.str());
349 std::ofstream myfile;
350 myfile.open(out_name.str(), std::ios::out | std::ios::trunc | std::ios::binary);
353 std::vector<double> energies(size);
366 auto start = std::chrono::high_resolution_clock::now();
370 auto end = std::chrono::high_resolution_clock::now();
372 MPI_Gather(&energy, 1, MPI_DOUBLE, energies.data(), 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
378 double energy_avg = std::accumulate(energies.begin(), energies.end(), 0.0) * 1.0/energies.size();
380 std::cout <<
"Avg energy = " << energy_avg + ham->getEconst() << std::endl;
381 std::cout <<
"Cur temp = " << cur_temp << std::endl;
385 for(
int i=0;i<size;i++)
387 std::cout << i <<
"\t" << energies[i] + ham->getEconst() <<
"\t" << fabs(energies[i]-energy_avg) << std::endl;
390 if(fabs(energies[i]-energy_avg) > 1e-5)
391 stop_running =
false;
393 if(energies[i] < energies[min_rank])
398 stop_running =
false;
401 std::cout <<
"Gonna stop!" << std::endl;
403 energy = energies[min_rank];
404 std::cout <<
"Rank " << min_rank <<
" has the lowest energy => " << get_energy() << std::endl;
407 MPI_Bcast(&energy, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
408 MPI_Bcast(&min_rank, 1, MPI_INT, 0, MPI_COMM_WORLD);
410 std::stringstream h5_name;
411 h5_name << getenv(
"SAVE_H5_PATH") <<
"/unitary-" << rank <<
"-" << count_iters*max_steps <<
".h5";
412 orbtrans->get_unitary().saveU(h5_name.str());
414 orbtrans->get_unitary().sendreceive(min_rank);
421 std::cout <<
"New max steps is " << max_steps << std::endl;
423 start_temp = cur_temp / delta_temp;
427 std::cout <<
"P=" << rank <<
"\tMPI Step runtime: " << std::fixed << std::chrono::duration_cast<std::chrono::duration<double,std::ratio<1>>>(end-start).count() <<
" s" << std::endl;
431 unsigned int total_unaccepted = 0;
432 MPI_Reduce(&unaccepted, &total_unaccepted, 1, MPI_UNSIGNED, MPI_SUM, 0, MPI_COMM_WORLD);
434 unsigned int min_unaccepted = 0;
435 MPI_Reduce(&unaccepted, &min_unaccepted, 1, MPI_UNSIGNED, MPI_MIN, 0, MPI_COMM_WORLD);
439 std::cout <<
"Total unaccepted = " << total_unaccepted << std::endl;
440 std::cout <<
"Minimal unaccepted = " << min_unaccepted << std::endl;
441 std::cout <<
"Run: " << count_iters << std::endl;
443 if(min_unaccepted > 1000)
447 MPI_Bcast(&stop_running, 1, MPI::BOOL, 0, MPI_COMM_WORLD);
451 MPI_Barrier(MPI_COMM_WORLD);
void UsePotentialReduction()
void Set_start_temp(double)
doci2DM::Method & getMethod() const
double get_energy() const
bool accept_function(double)
unsigned int steps
the number of steps done
OrbitalTransform & getOrbitalTf() const
std::unique_ptr< simanneal::OrbitalTransform > orbtrans
the actual orbital transform
void Set_delta_temp(double)
SimulatedAnnealing(const CheMPS2::Hamiltonian &)
unsigned int unaccepted
number of unaccepted steps
std::random_device rd
the real random input (hopefully)
std::unique_ptr< simanneal::UnitaryMatrix > opt_unitary
the current unitary
virtual ~SimulatedAnnealing()
doci2DM::BoundaryPoint & getMethod_BP() const
void Set_max_angle(double)
bool stop_running
bool to indicate if we should quite the optimalisation
void set_max_iter(unsigned int)
unsigned int max_steps
max number of steps
simanneal::UnitaryMatrix & get_Optimal_Unitary()
double get_tol_PD() const
std::mt19937_64 mt
our pseudo-random generator
doci2DM::PotentialReduction & getMethod_PR() const
std::unique_ptr< doci2DM::Method > method
double energy
energy of current iteration
void Set_delta_angle(double)
std::unique_ptr< CheMPS2::Hamiltonian > ham
Holds the current hamiltonian.
CheMPS2::Hamiltonian & getHam() const