58 std::random_device rd;
59 mt = std::mt19937(rd());
62 char *irreps_env = getenv(
"v2DM_DOCI_ALLOWED_IRREPS");
63 if(irreps_env && strlen(irreps_env) > 0)
65 std::string irreps_string = irreps_env;
66 const std::string delim =
",";
70 auto end = irreps_string.find(delim);
75 auto elem = irreps_string.substr(start, end - start);
79 int cur_irrep = std::stoi(elem);
81 if(cur_irrep >= 0 && cur_irrep < syminfo.getNumberOfIrreps())
84 start = end + delim.length();
86 if(end >= std::string::npos)
89 end = irreps_string.find(delim, start);
91 }
catch (std::exception& e) {
92 std::cout <<
"Invalid value in v2DM_DOCI_ALLOWED_IRREPS" << std::endl;
96 std::cout <<
"Allowed irreps: ";
98 std::cout << elem <<
" ";
99 std::cout << std::endl;
116 std::random_device rd;
117 mt = std::mt19937(rd());
127 return energy + ham->getEconst();
136 method->BuildHam(*ham);
139 energy = method->getEnergy();
148 orbtrans->fillHamCI(*ham);
150 method->BuildHam(*ham);
153 return method->getEnergy();
158 method->BuildHam(new_ham);
161 return method->getEnergy();
166 return orbtrans->get_unitary();
222 auto start = std::chrono::high_resolution_clock::now();
224 const auto& ham2 = *ham;
225 std::function<double(int,int)> getT = [&ham2] (
int a,
int b) ->
double {
return ham2.getTmat(a,b); };
226 std::function<double(int,int,int,int)> getV = [&ham2] (
int a,
int b,
int c,
int d) ->
double {
return ham2.getVmat(a,b,c,d); };
228 std::vector< std::tuple<int,int,double,double> > pos_rotations;
230 pos_rotations.reserve(ham->getL()*(ham->getL()-1)/2);
232 for(
int k_in=0;k_in<ham->getL();k_in++)
233 for(
int l_in=k_in+1;l_in<ham->getL();l_in++)
234 if(ham->getOrbitalIrrep(k_in) == ham->getOrbitalIrrep(l_in))
236 if(!allow_irreps.empty() && std::find(allow_irreps.begin(), allow_irreps.end(), ham->getOrbitalIrrep(k_in)) == allow_irreps.end() )
239 auto found = method->getRDM().find_min_angle(k_in,l_in,0.3,getT,getV);
243 found = method->getRDM().find_min_angle(k_in,l_in,0.01,getT,getV);
250 if(fabs(found.first)>M_PI/2.0)
253 double new_en = method->getRDM().calc_rotate(k_in,l_in,found.first,getT,getV);
255 assert(found.second &&
"Shit, maximum!");
257 pos_rotations.push_back(std::make_tuple(k_in,l_in,found.first,new_en));
260 auto end = std::chrono::high_resolution_clock::now();
262 std::cout <<
"Orbital scanning took: " << std::fixed << std::chrono::duration_cast<std::chrono::duration<double,std::ratio<1>>>(end-start).count() <<
" s" << std::endl;
264 assert(pos_rotations.size()>0);
266 return pos_rotations;
281 energy = calc_new_energy();
283 auto start = std::chrono::high_resolution_clock::now();
285 std::pair<int,int> prev_pair(0,0);
291 while(converged<conv_steps)
293 auto list_rots = scan_orbitals();
295 std::sort(list_rots.begin(), list_rots.end(),
296 [](
const std::tuple<int,int,double,double> & a,
const std::tuple<int,int,double,double> & b) ->
bool
298 return std::get<3>(a) < std::get<3>(b);
301 for(
auto& elem: list_rots)
302 std::cout << std::get<0>(elem) <<
"\t" << std::get<1>(elem) <<
"\t" << std::get<3>(elem)+ham->getEconst() <<
"\t" << std::get<2>(elem) << std::endl;
305 std::pair<int,int> tmp;
309 idx = choose_orbitalpair(list_rots);
311 tmp = std::make_pair(std::get<0>(list_rots[idx]), std::get<1>(list_rots[idx]));
314 idx = choose_orbitalpair(list_rots);
316 tmp = std::make_pair(std::get<0>(list_rots[idx]), std::get<1>(list_rots[idx]));
322 tmp = std::make_pair(std::get<0>(list_rots[idx]), std::get<1>(list_rots[idx]));
328 const auto& new_rot = list_rots[idx];
329 prev_pair = std::make_pair(std::get<0>(new_rot), std::get<1>(new_rot));
332 std::cout << iters <<
" (" << converged <<
") Chosen: " << idx << std::endl;
334 assert(ham->getOrbitalIrrep(std::get<0>(new_rot)) == ham->getOrbitalIrrep(std::get<1>(new_rot)));
336 orbtrans->DoJacobiRotation(*ham, std::get<0>(new_rot), std::get<1>(new_rot), std::get<2>(new_rot));
337 orbtrans->get_unitary().jacobi_rotation(ham->getOrbitalIrrep(std::get<0>(new_rot)), std::get<0>(new_rot), std::get<1>(new_rot), std::get<2>(new_rot));
341 if(obj_bp && iters%25==0)
343 std::cout <<
"Restarting from zero" << std::endl;
348 new_energy = calc_new_energy(*ham);
350 std::stringstream h5_name;
351 h5_name << getenv(
"SAVE_H5_PATH") <<
"/unitary-" << start_iters+iters <<
".h5";
352 orbtrans->get_unitary().saveU(h5_name.str());
355 h5_name << getenv(
"SAVE_H5_PATH") <<
"/ham-" << start_iters+iters <<
".h5";
356 ham->save2(h5_name.str());
359 h5_name << getenv(
"SAVE_H5_PATH") <<
"/rdm-" << start_iters+iters <<
".h5";
360 method->getRDM().WriteToFile(h5_name.str());
365 if((std::get<3>(new_rot) - new_energy) < -1e-5)
367 std::cout <<
"Restarting from zero because too much up: " << std::get<3>(new_rot) - new_energy << std::endl;
371 std::cout <<
"After restarting found: " << obj_bp->
getEnergy() <<
" vs " << new_energy <<
"\t" << obj_bp->
getEnergy()-new_energy << std::endl;
376 h5_name << getenv(
"SAVE_H5_PATH") <<
"/X-" << start_iters+iters <<
".h5";
380 h5_name << getenv(
"SAVE_H5_PATH") <<
"/Z-" << start_iters+iters <<
".h5";
384 if(method->FullyConverged())
386 if(fabs(energy-new_energy)<conv_crit)
390 std::cout << iters <<
" (" << converged <<
")\tRotation between " << std::get<0>(new_rot) <<
" " << std::get<1>(new_rot) <<
" over " << std::get<2>(new_rot) <<
" E_rot = " << std::get<3>(new_rot)+ham->getEconst() <<
" E = " << new_energy+ham->getEconst() <<
"\t" << fabs(energy-new_energy) << std::endl;
399 std::cout <<
"Done 1000 steps, quiting..." << std::endl;
407 auto end = std::chrono::high_resolution_clock::now();
409 std::cout <<
"Minimization took: " << std::fixed << std::chrono::duration_cast<std::chrono::duration<double,std::ratio<1>>>(end-start).count() <<
" s" << std::endl;
411 std::stringstream h5_name;
412 h5_name << getenv(
"SAVE_H5_PATH") <<
"/optimale-uni.h5";
413 get_Optimal_Unitary().saveU(h5_name.str());
441 std::uniform_real_distribution<double> dist(0, 1);
443 const double choice = dist(mt);
447 for(
auto &orb_pair: orbs)
448 norm += (energy - std::get<3>(orb_pair));
451 for(
int i=0;i<orbs.size();i++)
453 cum += (energy - std::get<3>(orbs[i]))/norm;
458 assert(0 &&
"Should never ever be reached!");
468 energy = calc_new_energy();
471 auto start = std::chrono::high_resolution_clock::now();
473 std::pair<int,int> prev_pair(0,0);
477 while(fabs(old_energy-energy)<stopcrit && converged<conv_steps)
481 auto list_rots = scan_orbitals();
483 std::sort(list_rots.begin(), list_rots.end(),
484 [](
const std::tuple<int,int,double,double> & a,
const std::tuple<int,int,double,double> & b) ->
bool
486 return std::get<3>(a) < std::get<3>(b);
489 for(
auto& elem: list_rots)
490 std::cout << std::get<0>(elem) <<
"\t" << std::get<1>(elem) <<
"\t" << std::get<3>(elem)+ham->getEconst() <<
"\t" << std::get<2>(elem) << std::endl;
493 std::pair<int,int> tmp;
495 tmp = std::make_pair(std::get<0>(list_rots[idx]), std::get<1>(list_rots[idx]));
501 const auto& new_rot = list_rots[idx];
502 prev_pair = std::make_pair(std::get<0>(new_rot), std::get<1>(new_rot));
504 assert(ham->getOrbitalIrrep(std::get<0>(new_rot)) == ham->getOrbitalIrrep(std::get<1>(new_rot)));
506 orbtrans->DoJacobiRotation(*ham, std::get<0>(new_rot), std::get<1>(new_rot), std::get<2>(new_rot));
507 orbtrans->get_unitary().jacobi_rotation(ham->getOrbitalIrrep(std::get<0>(new_rot)), std::get<0>(new_rot), std::get<1>(new_rot), std::get<2>(new_rot));
509 energy = std::get<3>(new_rot);
511 std::cout << iters <<
" (" << converged <<
")\tRotation between " << std::get<0>(new_rot) <<
" " << std::get<1>(new_rot) <<
" over " << std::get<2>(new_rot) <<
" E_rot = " << energy+ham->getEconst() <<
"\t" << old_energy-energy << std::endl;
515 assert(energy<old_energy &&
"No minimization ?!?");
517 if(fabs(old_energy-energy)<conv_crit)
522 std::cout <<
"Done 10000 steps, quiting..." << std::endl;
530 auto end = std::chrono::high_resolution_clock::now();
532 std::cout <<
"Minimization with optimization took: " << std::fixed << std::chrono::duration_cast<std::chrono::duration<double,std::ratio<1>>>(end-start).count() <<
" s" << std::endl;
534 std::stringstream h5_name;
535 h5_name << getenv(
"SAVE_H5_PATH") <<
"/optimale-uni-no-opt.h5";
536 get_Optimal_Unitary().saveU(h5_name.str());
546 const auto old_conv_crit = conv_crit;
547 const auto old_conv_steps = conv_steps;
548 const double switch_crit = 1e-1;
552 while(iters_noopt < 20)
554 conv_crit = switch_crit;
557 iters += Minimize(
false,iters);
559 conv_crit = old_conv_crit;
560 conv_steps = old_conv_steps;
562 iters_noopt = Minimize_noOpt(switch_crit);
565 iters += Minimize(
false,iters);
567 return iters + iters_noopt;
std::unique_ptr< simanneal::OrbitalTransform > orbtrans
the actual orbital transform
std::vector< std::tuple< int, int, double, double > > scan_orbitals()
int conv_steps
number of steps in convergence area
OrbitalTransform & getOrbitalTf() const
int Minimize_noOpt(double stopcrit)
simanneal::UnitaryMatrix & get_Optimal_Unitary()
sig_atomic_t stopping_min
void UsePotentialReduction()
doci2DM::BoundaryPoint & getMethod_BP() const
std::unique_ptr< CheMPS2::Hamiltonian > ham
Holds the current hamiltonian.
virtual ~LocalMinimizer()
void WriteToFile(std::string filename) const
void set_conv_crit(double)
double conv_crit
criteria for convergence of the minimizer
LocalMinimizer(const CheMPS2::Hamiltonian &)
doci2DM::PotentialReduction & getMethod_PR() const
int Minimize(bool dist_choice=false, int start_iters=0)
CheMPS2::Hamiltonian & getHam() const
std::vector< int > allow_irreps
only rotation within these irreps (if not empty)
int choose_orbitalpair(std::vector< std::tuple< int, int, double, double >> &)
doci2DM::Method & getMethod() const
std::unique_ptr< doci2DM::Method > method
std::mt19937 mt
our pseudo-random generator
double get_conv_crit() const
double get_energy() const