VMPS++
Loading...
Searching...
No Matches
Mps.h
Go to the documentation of this file.
1#ifndef STRAWBERRY_MPS_WITH_Q
2#define STRAWBERRY_MPS_WITH_Q
3
5#include <set>
6#include <numeric>
7#include <algorithm>
8#include <ctime>
9#include <type_traits>
10#include <iostream>
11#include <fstream>
13
14#ifdef USE_HDF5_STORAGE
15 #include <HDF5Interface.h>
16 static double dump_Mps; // dump variable if energy value not saved
17#endif
18
20#include "DmrgJanitor.h"
21#include "MpsBoundaries.h"
22#include "Blocker.h"
23
24// Forward Declaration
25template<typename Symmetry, typename Scalar> class Mpo;
26template<typename Symmetry, typename Scalar> class TwoSiteGate;
27
37template<typename Symmetry, typename Scalar=double>
38class Mps : public DmrgJanitor<PivotMatrix1<Symmetry,Scalar,Scalar> >
39{
40 typedef Matrix<Scalar,Dynamic,Dynamic> MatrixType;
41 static constexpr size_t Nq = Symmetry::Nq;
42 typedef typename Symmetry::qType qType;
43
44 // Note: Cannot partially specialize template friends
45 template<typename Symmetry_, typename MpHamiltonian, typename Scalar_> friend class DmrgSolver;
46 template<typename Symmetry_, typename S1, typename S2> friend class MpsCompressor;
47 template<typename H, typename Symmetry_, typename S1, typename S2, typename V> friend class TDVPPropagator;
48 template<typename Symmetry_, typename S1, typename S2> friend
50 template<typename Symmetry_, typename S1, typename S2> friend
52 template<typename Symmetry_, typename S1, typename S2> friend
53 void OxV_exact (const Mpo<Symmetry_,S1> &H, const Mps<Symmetry_,S2> &Vin, Mps<Symmetry_,S2> &Vout, double tol_compr, DMRG::VERBOSITY::OPTION VERBOSITY, int max_halfsweeps, int min_halfsweeps, int Minit);
54
55 template<typename Symmetry_, typename S_> friend class Mps; // in order to exchange data between real & complex Mps
56
57public:
58
59 //---constructors---
60
62 Mps();
63
72 Mps (size_t L_input, vector<vector<qarray<Nq> > > qloc_input, qarray<Nq> Qtot_input, size_t N_phys_input, int Nqmax_input, bool TRIVIAL_BOUNDARIES=true);
73
81 template<typename Hamiltonian> Mps (const Hamiltonian &H, size_t Mmax, qarray<Nq> Qtot_input, int Nqmax_input);
82
91 Mps (size_t L_input, const vector<vector<Biped<Symmetry,MatrixType> > > &As,
92 const vector<vector<qarray<Nq> > > &qloc_input, qarray<Nq> Qtot_input, size_t N_phys_input);
93
94 #ifdef USE_HDF5_STORAGE
100 Mps (string filename) {load(filename);}
101 #endif //USE_HDF5_STORAGE
102
103 //---set and modify---
104
106
111 void setRandom();
112
114 void setRandom (size_t loc);
115
117 void setZero();
118
124
125 #ifdef USE_HDF5_STORAGE
127
134 void save (string filename, string info="none", double energy=std::nan("1"));
135
141 void load (string filename, double &energy=dump_Mps);
142 #endif //USE_HDF5_STORAGE
143
151 void outerResize (size_t L_input, vector<vector<qarray<Nq> > > qloc_input, qarray<Nq> Qtot_input, int Nqmax_input=500);
152
159 void outerResizeAll (size_t L_input, vector<vector<qarray<Nq> > > qloc_input, qarray<Nq> Qtot_input);
160
168 template<typename Hamiltonian> void outerResize (const Hamiltonian &H, qarray<Nq> Qtot_input, int Nqmax_input=500);
169
175 template<typename OtherMatrixType> void outerResize (const Mps<Symmetry,OtherMatrixType> &V);
176
182 void innerResize (size_t Mmax);
183
189 template<typename Hamiltonian> void setProductState (const Hamiltonian &H, const vector<qarray<Nq> > &config);
190
198 void mend();
199
205
206 void set_Qmultitarget (const vector<qarray<Nq> > &Qmulti_input) {Qmulti = Qmulti_input;};
207
209// /**
210// * Takes an Mpo and flattens/purifies it into this Mps (to do time propagation in the Heisenberg picture, for example).
211// * \param Op : the Mpo to be flattened
212// * \param USE_SQUARE : if \p true, takes the saved square of the Mpo
213// * \warning: Long time since this has been tested. Might be useful in the future, though.
214// */
215// template<size_t MpoNq> void setFlattenedMpo (const Mpo<MpoNq,Scalar> &Op, bool USE_SQUARE=false);
218
219 //---print infos---
220
222
228 string test_ortho (double tol=1e-8) const;
229
231 string info() const;
232
234 string Asizes() const;
235
241 string validate (string name="Mps") const;
242
248 void graph (string filename) const;
249
253 size_t calc_Mmax() const;
254
255 size_t get_Min (size_t loc) const;
256 size_t get_Mout (size_t loc) const;
257
261 size_t calc_fullMmax() const;
262
266 size_t calc_Dmax() const;
267
271 size_t calc_Nqmax() const;
272
273 size_t Nqout (size_t l) {return outbase[l].Nq();}
274
278 double calc_Nqavg() const;
279
281 double memory (MEMUNIT memunit=GB) const;
283
284 //---linear algebra operations---
285
287
294 template<typename OtherScalar> void addScale (OtherScalar alpha, const Mps<Symmetry,Scalar> &Vin, bool SVD_COMPRESS=false);
295
301
307
311 template<typename OtherScalar> Mps<Symmetry,Scalar>& operator*= (const OtherScalar &alpha);
312
316 template<typename OtherScalar> Mps<Symmetry,Scalar>& operator/= (const OtherScalar &alpha);
317
322
326 template<typename OtherScalar> Mps<Symmetry,OtherScalar> cast() const;
327
331 Scalar dot (const Mps<Symmetry,Scalar> &Vket) const;
332
336 double squaredNorm() const;
337
343 template<typename MpoScalar> Scalar locAvg (const Mpo<Symmetry,MpoScalar> &O, size_t distance=0) const;
344
345 //**Calculates the expectation value with a local operator at pivot and pivot+1.*/
346// template<typename MpoScalar> Scalar locAvg2 (const Mpo<Symmetry,MpoScalar> &O) const;
347
350
355
359 void collapse();
361
362 //---sweeping---
363
365
372 void rightSweepStep (size_t loc, DMRG::BROOM::OPTION BROOM, PivotMatrix1<Symmetry,Scalar,Scalar> *H = NULL, bool DISCARD_V=false);
373
381 void leftSweepStep (size_t loc, DMRG::BROOM::OPTION BROOM, PivotMatrix1<Symmetry,Scalar,Scalar> *H = NULL, bool DISCARD_U=false);
382
391 void calc_N (DMRG::DIRECTION::OPTION DIR, size_t loc, vector<Biped<Symmetry,MatrixType> > &N);
392
400 void sweepStep2 (DMRG::DIRECTION::OPTION DIR, size_t loc, const vector<Biped<Symmetry,MatrixType> > &Apair, bool SEPARATE_SV=false);
401
402
403 // * Performs a two-site sweep and writes the result into \p Al, \p Ar and \p C (useful for IDMRG).
404 // * \param DIR : direction of the sweep, either LEFT or RIGHT.
405 // * \param loc : site to perform the sweep on; afterwards the pivot is shifted to \p loc-1 or \p loc+1
406 // * \param Apair : pair of two Mps site tensors which are split via an SVD
407 // * \param Al : left-orthogonal part goes here
408 // * \param Ar : right-orthogonal part goes here
409 // * \param C : singular values go here
410 // * \param SEPARATE_SV: if \p true, the singular value matrix is discarded (iseful for IDMRG)
411 // void sweepStep2 (DMRG::DIRECTION::OPTION DIR, size_t loc, const vector<Biped<Symmetry,MatrixType> > &Apair,
412 // vector<Biped<Symmetry,MatrixType> > &Al, vector<Biped<Symmetry,MatrixType> > &Ar, Biped<Symmetry,MatrixType> &C,
413 // bool SEPARATE_SV);
414
419
424
433
434 //---return stuff---
435
437
438 inline qarray<Nq> Qtarget() const {return Qtot;};
439
441 inline vector<qarray<Nq> > Qmultitarget() const {return Qmulti;};
442
444 inline vector<qarray<Nq> > locBasis (size_t loc) const {return qloc[loc];}
445 inline vector<vector<qarray<Nq> > > locBasis() const {return qloc;}
446
448 inline Qbasis<Symmetry> inBasis (size_t loc) const {return inbase[loc];}
449 inline vector<Qbasis<Symmetry> > inBasis() const {return inbase;}
450
452 inline Qbasis<Symmetry> outBasis (size_t loc) const {return outbase[loc];}
453 inline vector<Qbasis<Symmetry> > outBasis() const {return outbase;}
454
456 const vector<Biped<Symmetry,MatrixType> > &A_at (size_t loc) const {return A[loc];};
457
459 vector<Biped<Symmetry,MatrixType> > &A_at (size_t loc) {return A[loc];};
460
462 inline int get_pivot() const {return this->pivot;};
463
465 inline ArrayXd get_truncWeight() const {return truncWeight;};
466
468 inline ArrayXd entropy() const {return S;};
469
471 inline vector<map<qarray<Nq>,ArrayXd> > entanglementSpectrum() const {return SVspec;};
472
474 std::pair<vector<qarray<Symmetry::Nq> >, ArrayXd> entanglementSpectrumLoc (size_t loc) const;
476
477// Tripod<Symmetry,Matrix<Scalar,Dynamic,Dynamic> > BoundaryL;
478// Tripod<Symmetry,Matrix<Scalar,Dynamic,Dynamic> > BoundaryR;
479// std::array<vector<vector<Biped<Symmetry,MatrixType> > >,2> A_LR;
480// vector<vector<qarray<Symmetry::Nq> > > qlocLR;
482
484 {
485 Boundaries.set_open_bc(Qtot);
486 }
487
489 {
490 if (usePower == 2ul)
491 {
492 if (DIR == DMRG::DIRECTION::LEFT) {return Boundaries.Lsq;}
493 else {return Boundaries.Rsq;}
494 }
495 else if (usePower == 1ul)
496 {
497 if (DIR == DMRG::DIRECTION::LEFT) {return Boundaries.L;}
498 else {return Boundaries.R;}
499 }
500 else
501 {
502 throw;
503 }
504 }
505
506 void elongate_hetero (size_t Nleft=0, size_t Nright=0)
507 {
508 if (Nleft>0 or Nright>0)
509 {
510 size_t Lcell = Boundaries.length();
511 size_t Lleft = Nleft * Lcell;
512 size_t Lright = Nright * Lcell;
513 size_t Lnew = this->N_sites + Lleft + Lright;
514
515 vector<vector<Biped<Symmetry,MatrixType> > > Anew(Lnew);
516 vector<vector<qarray<Nq> > > qloc_new(Lnew);
517
518// cout << "Lcell=" << Lcell << endl;
519// cout << "Nleft=" << Nleft << ", Nright=" << Nright << endl;
520 for (int l=0; l<Lleft; ++l)
521 {
522// cout << "adding AL at: l=" << l << " from cell index=" << l%Lcell << endl;
523 Anew [l] = Boundaries.A[0][l%Lcell];
524 qloc_new[l] = Boundaries.qloc[l%Lcell];
525 }
526 for (int l=0; l<this->N_sites; ++l)
527 {
528// cout << "using old A at: l=" << Lleft+l << " old index=" << l << endl;
529 Anew [Lleft+l] = A[l];
530 qloc_new[Lleft+l] = qloc[l];
531 }
532 for (int l=0; l<Lright; ++l)
533 {
534// cout << "adding AR at: l=" << Lleft+this->N_sites+l << " from cell index=" << l%Lcell << endl;
535 Anew [Lleft+this->N_sites+l] = Boundaries.A[1][l%Lcell];
536 qloc_new[Lleft+this->N_sites+l] = Boundaries.qloc[l%Lcell];
537 }
538// cout << endl;
539
540 A = Anew;
541 qloc = qloc_new;
542 this->N_sites = Lnew;
543
547 calc_Qlimits();
548 }
549 }
550
551 void shift_hetero (int Nshift=0)
552 {
553 if (Nshift!=0)
554 {
555 size_t Lcell = Boundaries.length();
556 size_t Lleft = (Nshift<0)? 0:Nshift*Lcell;
557 size_t Lright = (Nshift<0)? abs(Nshift)*Lcell:0;
558
559 vector<vector<Biped<Symmetry,MatrixType>>> Anew(this->N_sites);
560 vector<vector<qarray<Nq>>> qloc_new(this->N_sites);
561
562// cout << "Nshift=" << Nshift << endl;
563 for (size_t l=0; l<Lleft; ++l)
564 {
565// cout << "adding AL at: l=" << l << " from cell index=" << posmod(-l,Lcell) << endl;
566 Anew [l] = Boundaries.A[0][posmod(-l,Lcell)];
567 qloc_new[l] = Boundaries.qloc[posmod(-l,Lcell)];
568 }
569 for (size_t l=0; l<this->N_sites-abs(Nshift)*Lcell; ++l)
570 {
571// cout << "using old A at: l=" << Lleft+l << " old index=" << l+Lright << endl;
572 Anew [Lleft+l] = A[l+Lright];
573 qloc_new[Lleft+l] = qloc[l+Lright];
574 }
575 for (size_t l=0; l<Lright; ++l)
576 {
577// cout << "adding AR at: l=" << Lleft+this->N_sites-abs(Nshift)*Lcell+l << " from cell index=" << l%Lcell << endl;
578 Anew [Lleft+this->N_sites-abs(Nshift)*Lcell+l] = Boundaries.A[1][l%Lcell];
579 qloc_new[Lleft+this->N_sites-abs(Nshift)*Lcell+l] = Boundaries.qloc[l%Lcell];
580 }
581// cout << endl;
582
583 A = Anew;
584 qloc = qloc_new;
585
589 calc_Qlimits();
590 }
591 }
592
593 void transform_base (qarray<Symmetry::Nq> Qtot, int L, bool PRINT = false)
594 {
595 if (Qtot != Symmetry::qvacuum())
596 {
597 for (size_t l=0; l<qloc.size(); ++l)
598 for (size_t i=0; i<qloc[l].size(); ++i)
599 for (size_t q=0; q<Symmetry::Nq; ++q)
600 {
601 if (Symmetry::kind()[q] != Sym::KIND::S and Symmetry::kind()[q] != Sym::KIND::T) //Do not transform the base for non Abelian symmetries
602 {
603 qloc[l][i][q] = qloc[l][i][q] * L - Qtot[q];
604 }
605 }
606 }
607 };
608
609//private:
610
612 size_t N_phys;
613
615 vector<vector<qarray<Nq> > > qloc;
616
618 qarray<Nq> Qtot = Symmetry::qvacuum();
619
621 vector<qarray<Nq> > Qmulti;
622
624 vector<vector<Biped<Symmetry,MatrixType> > > A; // access: A[l][s].block[q]
625
627 ArrayXd truncWeight;
628
630 ArrayXd S;
631
632 vector<map<qarray<Nq>,ArrayXd> > SVspec;
633
635 vector<Qbasis<Symmetry> > inbase;
636 vector<Qbasis<Symmetry> > outbase;
637
639 vector<qarray<Nq> > QinTop;
640 vector<qarray<Nq> > QinBot;
641 vector<qarray<Nq> > QoutTop;
642 vector<qarray<Nq> > QoutBot;
643
648
650 void update_inbase (size_t loc);
651 void update_outbase (size_t loc);
652 void update_inbase() {for (size_t l=0; l<this->N_sites; l++) update_inbase(l);}
653 void update_outbase() {for (size_t l=0; l<this->N_sites; l++) update_outbase(l);}
654
658
660 template<typename OtherScalar> void add_site (size_t loc, OtherScalar alpha, const Mps<Symmetry,Scalar> &Vin);
661
665};
666
667template<typename Symmetry, typename Scalar>
669info() const
670{
671 stringstream ss;
672 ss << "Mps: ";
673 ss << "L=" << this->N_sites;
674 if (N_phys>this->N_sites) {ss << ",V=" << N_phys;}
675 ss << ", " << Symmetry::name() << ", ";
676
677 if (Nq != 0)
678 {
679 ss << "(";
680 for (size_t q=0; q<Nq; ++q)
681 {
682 ss << Symmetry::kind()[q];
683 if (q!=Nq-1) {ss << ",";}
684 }
685 ss << ")=(" << Sym::format<Symmetry>(Qtot) << "), ";
686 }
687
688 ss << "pivot=" << this->pivot << ", ";
689
690 ss << "Mmax=" << calc_Mmax() << " (";
691 if (Symmetry::NON_ABELIAN)
692 {
693 ss << "full=" << calc_fullMmax() << ", ";
694 }
695 ss << "Dmax=" << calc_Dmax() << "), ";
696 ss << "Nqmax=" << calc_Nqmax() << ", ";
697 ss << "Nqavg=" << calc_Nqavg() << ", ";
698 ss << "trunc_weight=" << truncWeight.sum();
699 ss << "(";
700 ss << "max=" << truncWeight.maxCoeff();
701 ss << ", eps=" << this->eps_truncWeight;
702 ss << ")";
703 ss << ", ";
704 int lSmax;
705 if (this->N_sites > 1)
706 {
707 S.maxCoeff(&lSmax);
708 if (!std::isnan(S(lSmax)) and S(lSmax) > 0)
709 {
710 ss << "Smax(l=" << lSmax << ")=" << S(lSmax) << ", ";
711 }
712 }
713 ss << "mem=" << round(memory(GB),3) << "GB";
714// ss << endl << " •ortho: " << test_ortho();
715// if (truncWeight.maxCoeff() > this->eps_truncWeight)
716// {
717// lout << termcolor::yellow << "Warning: max. local truncWeight=" << truncWeight.maxCoeff() << " is larger than the tolerance " << this->eps_truncWeight << "!" << termcolor::reset << endl;
718// }
719 return ss.str();
720}
721
722template<typename Symmetry, typename Scalar>
724Mps()
725:DmrgJanitor<PivotMatrix1<Symmetry,Scalar,Scalar>>()
726{}
727
728template<typename Symmetry, typename Scalar>
730Mps (size_t L_input, vector<vector<qarray<Nq> > > qloc_input, qarray<Nq> Qtot_input, size_t N_phys_input, int Qmax_input, bool TRIVIAL_BOUNDARIES)
731:DmrgJanitor<PivotMatrix1<Symmetry,Scalar,Scalar> >(L_input), qloc(qloc_input), Qtot(Qtot_input), N_phys(N_phys_input)
732{
733 if (TRIVIAL_BOUNDARIES) {set_open_bc();}
734 else {Boundaries.TRIVIAL_BOUNDARIES = false;}
735 Qmulti = vector<qarray<Nq> >(1,Qtot);
736 outerResize(L_input, qloc_input, Qtot_input, Qmax_input);
739}
740
741template<typename Symmetry, typename Scalar>
742template<typename Hamiltonian>
744Mps (const Hamiltonian &H, size_t Mmax, qarray<Nq> Qtot_input, int Nqmax_input)
745:DmrgJanitor<PivotMatrix1<Symmetry,Scalar,Scalar> >()
746{
747 set_open_bc();
748 N_phys = H.volume();
749 Qmulti = vector<qarray<Nq> >(1,Qtot);
750 outerResize(H.length(), H.locBasis(), Qtot_input, Nqmax_input);
751
754
755 if (max(Mmax,calc_Nqmax()) > Mmax) lout << "DmrgSolver: Adjusting Minit to match Qinit: " << Mmax << "→" << calc_Nqmax() << endl;
756 innerResize(max(Mmax,calc_Nqmax()));
757
758 for (size_t l=0; l<this->N_sites; ++l)
759 for (size_t s=0; s<qloc[l].size(); ++s)
760 {
761 A[l][s] = A[l][s].cleaned();
762 }
763
766}
767
768template<typename Symmetry, typename Scalar>
770Mps (size_t L_input, const vector<vector<Biped<Symmetry,Matrix<Scalar,Dynamic,Dynamic> > > > &As,
771 const vector<vector<qarray<Nq> > > &qloc_input, qarray<Nq> Qtot_input, size_t N_phys_input)
772:DmrgJanitor<PivotMatrix1<Symmetry,Scalar,Scalar> >(L_input), qloc(qloc_input), Qtot(Qtot_input), N_phys(N_phys_input), A(As)
773{
774 set_open_bc();
775 Qmulti = vector<qarray<Nq> >(1,Qtot);
776 assert(As.size() == L_input and qloc_input.size() == L_input);
780}
781
782template<typename Symmetry, typename Scalar>
783template<typename Hamiltonian>
785outerResize (const Hamiltonian &H, qarray<Nq> Qtot_input, int Nqmax_input)
786{
787 set_open_bc();
788 N_phys = H.volume();
789 outerResize(H.length(), H.locBasis(), Qtot_input, Nqmax_input);
790}
791
792template<typename Symmetry, typename Scalar>
793template<typename OtherMatrixType>
796{
797 this->N_sites = V.N_sites;
798 N_phys = V.N_phys;
799 qloc = V.qloc;
800 Qtot = V.Qtot;
801 set_open_bc();
802 Qmulti = V.Qmulti;
803
804 inbase = V.inbase;
805 outbase = V.outbase;
806
807 QoutTop = V.QoutTop;
808 QoutBot = V.QoutBot;
809 QinTop = V.QinTop;
810 QinBot = V.QinBot;
811
812 A.resize(this->N_sites);
813
814 truncWeight.resize(this->N_sites); truncWeight.setZero();
815 S.resize(this->N_sites-1); S.setConstant(numeric_limits<double>::quiet_NaN());
816 SVspec.resize(this->N_sites-1);
817
818 for (size_t l=0; l<V.N_sites; ++l)
819 {
820 A[l].resize(qloc[l].size());
821
822 for (size_t s=0; s<qloc[l].size(); ++s)
823 {
824 A[l][s].in = V.A[l][s].in;
825 A[l][s].out = V.A[l][s].out;
826 A[l][s].block.resize(V.A[l][s].dim);
827 A[l][s].dict = V.A[l][s].dict;
828 A[l][s].dim = V.A[l][s].dim;
829 }
830 }
831}
832
833template<typename Symmetry, typename Scalar>
836{
837 A.resize(this->N_sites);
838
839 for (size_t l=0; l<this->N_sites; ++l)
840 {
841 A[l].resize(qloc[l].size());
842 }
843
844 inbase.resize(this->N_sites);
845 outbase.resize(this->N_sites);
846
847 truncWeight.resize(this->N_sites); truncWeight.setZero();
848 S.resize(this->N_sites-1); S.setConstant(numeric_limits<double>::quiet_NaN());
849 SVspec.resize(this->N_sites-1);
850}
851
852template<typename Symmetry, typename Scalar>
855{
856 // workaround for empty band
857 bool NEED_WORKAROUND = false;
858 for (int q=0; q<Symmetry::Nq; ++q)
859 {
860 if (Symmetry::kind()[q] == Sym::KIND::N and Qtot[q] == 0)
861 {
862 NEED_WORKAROUND = true;
863 }
864 }
865
866 /*for (int q=0; q<Symmetry::Nq; ++q)
867 {
868 if (Symmetry::kind()[q] == Sym::KIND::K)
869 {
870 NEED_WORKAROUND = true;
871 }
872 }*/
873
874// if (Symmetry::kind()[0] == Sym::KIND::M and Symmetry::kind()[1] == Sym::KIND::N)
875// {
876// NEED_WORKAROUND = true;
877// }
878
879 if (NEED_WORKAROUND)
880 {
882 }
883 else
884 {
885 auto lowest_q = [] (const vector<qarray<Nq> > &qs) -> qarray<Nq>
886 {
887 qarray<Nq> out;
888 array<vector<int>,Nq> tmp;
889 for (size_t q=0; q<Nq; q++)
890 {
891 tmp[q].resize(qs.size());
892 for (size_t i=0; i<qs.size(); i++)
893 {
894 tmp[q][i] = qs[i][q];
895 }
896 }
897 for (size_t q=0; q<Nq; q++)
898 {
899 sort(tmp[q].begin(),tmp[q].end());
900 out[q] = tmp[q][0];
901 }
902 return out;
903 };
904
905 // For spins: calculate maximal S across the chain
906 size_t Smax = 1;
907 if (!Symmetry::IS_TRIVIAL)
908 {
909 for (size_t l=0; l<this->N_sites; ++l)
910 for (size_t s=0; s<qloc[l].size(); ++s)
911 {
912 if (ceil(0.5*(qloc[l][s][0]-1.)) > Smax) {Smax = ceil(0.5*(qloc[l][s][0]-1.));}
913 }
914 }
915// cout << "Smax=" << Smax << endl;
916
917 auto lowest_qs = [Smax] (const vector<qarray<Nq> > &qs) -> vector<qarray<Nq> >
918 {
919 if (Symmetry::IS_TRIVIAL)
920 {
921 vector<qarray<Nq> > out(1);
922 out[0] = Symmetry::qvacuum();
923 return out;
924 }
925
926// cout << "in:" << endl;
927// for (size_t i=0; i<qs.size(); ++i)
928// {
929// cout << qs[i] << ", ";
930// }
931// cout << endl;
932
933 // sort for every q and remove duplicates
934 array<vector<int>,Nq> tmp;
935 for (size_t q=0; q<Nq; q++)
936 {
937 tmp[q].resize(qs.size());
938 for (size_t i=0; i<qs.size(); i++)
939 {
940 tmp[q][i] = qs[i][q];
941 }
942 sort(tmp[q].begin(),tmp[q].end());
943 tmp[q].erase(unique(tmp[q].begin(), tmp[q].end()), tmp[q].end());
944 }
945
946 // Can have different resulting sizes depending on q...
947 Array<size_t,Dynamic,1> tmp_sizes(Nq);
948 for (size_t q=0; q<Nq; q++)
949 {
950 tmp_sizes(q) = tmp[q].size();
951 }
952 // cout << "sizes=" << tmp_sizes.transpose() << endl;
953 vector<qarray<Nq> > out(min(Smax+1, tmp_sizes.minCoeff()));
954
955 for (size_t q=0; q<Nq; q++)
956 for (size_t i=0; i<out.size(); ++i)
957 {
958 out[i][q] = tmp[q][i];
959 }
960
961// cout << "out:" << endl;
962// for (size_t i=0; i<out.size(); ++i)
963// {
964// cout << out[i] << ", ";
965// }
966// cout << endl;
967
968// cout << "returning lowest_qs, size=" << out.size() << endl;
969 return out;
970 };
971
972 auto highest_q = [] (const vector<qarray<Nq> > &qs) -> qarray<Nq>
973 {
974 qarray<Nq> out;
975 array<vector<int>,Nq> tmp;
976 for (size_t q=0; q<Nq; q++)
977 {
978 tmp[q].resize(qs.size());
979 for (size_t i=0; i<qs.size(); i++)
980 {
981 tmp[q][i] = qs[i][q];
982 }
983 }
984 for (size_t q=0; q<Nq; q++)
985 {
986 sort(tmp[q].begin(),tmp[q].end());
987 out[q] = tmp[q][qs.size()-1];
988 }
989 return out;
990 };
991
992 QinTop.resize(this->N_sites);
993 QinBot.resize(this->N_sites);
994 QoutTop.resize(this->N_sites);
995 QoutBot.resize(this->N_sites);
996
997 // If non-trivial boundaries: we have an infinite state with a heterogeneous section, no Qlimits
998 if (!Boundaries.IS_TRIVIAL())
999 {
1000 // cout << termcolor::red << "Boundaries.IS_TRIVIAL()==false, infinite limits" << termcolor::reset << endl;
1002 }
1003 else
1004 {
1005 vector<vector<qarray<Symmetry::Nq> > > QinBotRange(this->N_sites);
1006 vector<vector<qarray<Symmetry::Nq> > > QoutBotRange(this->N_sites);
1007
1008 QinTop[0] = Symmetry::qvacuum();
1009 QinBot[0] = Symmetry::qvacuum();
1010 QinBotRange[0] = {Symmetry::qvacuum()};
1011
1012 for (size_t l=1; l<this->N_sites; ++l)
1013 {
1014 auto new_tops = Symmetry::reduceSilent(qloc[l-1], QinTop[l-1]);
1015 auto new_bots = Symmetry::reduceSilent(qloc[l-1], QinBotRange[l-1], true);
1016// cout << "l=" << l << ", new_tops.size()=" << new_tops.size() << endl;
1017// cout << "l=" << l << ", new_bots.size()=" << new_bots.size() << endl;
1018
1019 QinTop[l] = highest_q(new_tops);
1020// cout << "highest done!" << endl;
1021 QinBot[l] = lowest_q(new_bots);
1022// cout << "lowest done!" << endl;
1023 QinBotRange[l] = lowest_qs(new_bots);
1024// cout << "a" << endl;
1025// cout << "l=" << l << ", QinBotRange.size()=" << QinBotRange.size() << endl;
1026 }
1027
1028// cout << "b" << endl;
1029 QoutTop[this->N_sites-1] = *max_element(Qmulti.begin(), Qmulti.end());
1030 QoutBot[this->N_sites-1] = *min_element(Qmulti.begin(), Qmulti.end());
1031 QoutBotRange[this->N_sites-1] = Qmulti; //{Qtot};
1032
1033 for (int l=this->N_sites-2; l>=0; --l)
1034 {
1035 vector<qarray<Symmetry::Nq> > qlocflip;
1036 for (size_t q=0; q<qloc[l+1].size(); ++q)
1037 {
1038 qlocflip.push_back(Symmetry::flip(qloc[l+1][q]));
1039 }
1040 auto new_tops = Symmetry::reduceSilent(qlocflip, QoutTop[l+1]);
1041 auto new_bots = Symmetry::reduceSilent(qlocflip, QoutBotRange[l+1]);
1042
1043 QoutTop[l] = highest_q(new_tops);
1044 QoutBot[l] = lowest_q(new_bots);
1045 QoutBotRange[l] = lowest_qs(new_bots);
1046 }
1047
1048 for (size_t l=0; l<this->N_sites; ++l)
1049 {
1050 if (l!=0)
1051 {
1052 for (size_t q=0; q<Nq; q++)
1053 {
1054 QinTop[l][q] = min(QinTop[l][q], QoutTop[l-1][q]);
1055 QinBot[l][q] = max(QinBot[l][q], QoutBot[l-1][q]);
1056 if (Symmetry::kind()[q] == Sym::KIND::K)
1057 {
1058 QinTop[l][q] = Symmetry::mod()[q]-1;
1059 QinBot[l][q] = 0;
1060 }
1061 }
1062 }
1063 if (l!=this->N_sites-1)
1064 {
1065 for (size_t q=0; q<Nq; q++)
1066 {
1067 QoutTop[l][q] = min(QoutTop[l][q], QinTop[l+1][q]);
1068 QoutBot[l][q] = max(QoutBot[l][q], QinBot[l+1][q]);
1069 if (Symmetry::kind()[q] == Sym::KIND::K)
1070 {
1071 QoutTop[l][q] = Symmetry::mod()[q]-1;
1072 QoutBot[l][q] = 0;
1073 }
1074 }
1075 }
1076
1077 /*cout << "l=" << l
1078 << ", QinTop[l]=" << QinTop[l] << ", QinBot[l]=" << QinBot[l]
1079 << ", QoutTop[l]=" << QoutTop[l] << ", QoutBot[l]=" << QoutBot[l]
1080 << endl;*/
1081 }
1082 }
1083 }
1084}
1085
1086template<typename Symmetry, typename Scalar>
1088{
1089 lout << termcolor::blue << "Setting Qlimits to infinity!" << termcolor::reset << endl;
1090 QinTop.resize(this->N_sites);
1091 QinBot.resize(this->N_sites);
1092 QoutTop.resize(this->N_sites);
1093 QoutBot.resize(this->N_sites);
1094
1095 for (size_t l=0; l<this->N_sites; ++l)
1096 for (size_t q=0; q<Nq; q++)
1097 {
1098 // A Z(N) quantum number can only go from 0 to N-1
1099 if (Symmetry::kind()[q] == Sym::KIND::K)
1100 {
1101 QinTop[l][q] = Symmetry::mod()[q]-1;
1102 QinBot[l][q] = 0;
1103 QoutTop[l][q] = Symmetry::mod()[q]-1;
1104 QoutBot[l][q] = 0;
1105 }
1106 else if (Symmetry::kind()[q] == Sym::KIND::N)
1107 {
1108 QinTop[l][q] = Qtot[q];
1109 QinBot[l][q] = 0;
1110 QoutTop[l][q] = Qtot[q];
1111 QoutBot[l][q] = 0;
1112 }
1113 else
1114 {
1115 QinTop[l][q] = std::numeric_limits<int>::max();
1116 QinBot[l][q] = std::numeric_limits<int>::min();
1117 QoutTop[l][q] = std::numeric_limits<int>::max();
1118 QoutBot[l][q] = std::numeric_limits<int>::min();
1119 }
1120 }
1121}
1122
1123template<typename Symmetry, typename Scalar>
1125outerResize (size_t L_input, vector<vector<qarray<Nq> > > qloc_input, qarray<Nq> Qtot_input, int Nqmax_input)
1126{
1127 if (Nqmax_input == -1)
1128 {
1129 outerResizeAll(L_input,qloc_input,Qtot_input);
1130 }
1131 else
1132 {
1133 this->N_sites = L_input;
1134 qloc = qloc_input;
1135 Qtot = Qtot_input;
1136 Qmulti = vector<qarray<Nq> >(1,Qtot);
1137 this->pivot = -1;
1138
1139 calc_Qlimits();
1140
1141 // take the first Nqmax_input quantum numbers from qs which have the smallerst distance to mean
1142 auto take_first_elems = [this,Nqmax_input] (const vector<qarray<Nq> > &qs, array<double,Nq> mean, const size_t &loc) -> vector<qarray<Nq> >
1143 {
1144 vector<qarray<Nq> > out = qs;
1145
1146 if (out.size() > Nqmax_input)
1147 {
1148 // sort the vector first according to the distance to mean
1149 sort(out.begin(),out.end(),[mean,loc,this] (qarray<Nq> q1, qarray<Nq> q2)
1150 {
1151 VectorXd dist_q1(Nq);
1152 VectorXd dist_q2(Nq);
1153 for (size_t q=0; q<Nq; q++)
1154 {
1155 if (Symmetry::kind()[q] == Sym::KIND::K)
1156 {
1157 double Delta = 0.5*Symmetry::mod()[q];
1158 dist_q1(q) = min( posmod(q1[q]-Qtot[q],Symmetry::mod()[q]), posmod(Qtot[q]-q1[q],Symmetry::mod()[q]) ) / Delta;
1159 dist_q2(q) = min( posmod(q2[q]-Qtot[q],Symmetry::mod()[q]), posmod(Qtot[q]-q2[q],Symmetry::mod()[q]) ) / Delta;
1160 // dist_q1(q) = 0.;
1161 // dist_q2(q) = 0.;
1162 }
1163 else
1164 {
1165 double Delta = QinTop[loc][q] - QinBot[loc][q];
1166 dist_q1(q) = (q1[q]-mean[q]) / Delta;
1167 dist_q2(q) = (q2[q]-mean[q]) / Delta;
1168 }
1169 }
1170 return (dist_q1.norm() < dist_q2.norm())? true:false;
1171 });
1172
1173 out.erase(out.begin()+Nqmax_input, out.end());
1174 }
1175 return out;
1176 };
1177
1178 // Qin_trunc contains the first Nqmax_input blocks (consistent with Qtot) for each site
1179 vector<vector<qarray<Nq> > > Qin_trunc(this->N_sites+1);
1180
1181 // fill Qin_trunc
1182 Qin_trunc[0].push_back(Symmetry::qvacuum());
1183 for (size_t l=1; l<this->N_sites; l++)
1184 {
1185 auto new_qs = Symmetry::reduceSilent(Qin_trunc[l-1], qloc[l-1], true);
1186
1187 // for (int i=0; i<new_qs.size(); ++i)
1188 // {
1189 // lout << "generated q=" << new_qs[i] << endl;
1190 // }
1191
1192 assert(new_qs.size() > 0);
1193 array<double,Nq> mean;
1194
1195 for (size_t q=0; q<Nq; q++)
1196 {
1197 mean[q] = static_cast<double>(Qtot[q])*static_cast<double>(l)/static_cast<double>(this->N_sites);
1198 //cout << "q=" << q << ", Qtot[q]=" << Qtot[q] << ", mean=" << mean[q] << endl;
1199 // Cast carefully, otherwise strange implicit cast of Qtot[q] to size_t for negative numbers that makes everything crash
1200 }
1201
1202 // check if within ranges (QinBot,QinTop) for all q:
1203 auto candidates = take_first_elems(new_qs,mean,l);
1204 assert(candidates.size() > 0);
1205 for (const auto &candidate:candidates)
1206 {
1207 //lout << "consider candidate: " << candidate << endl;
1208 array<bool,Nq> WITHIN_RANGE;
1209 for (size_t q=0; q<Nq; ++q)
1210 {
1211 //cout << "l=" << l << ", q=" << q << ", QinTop[l][q]=" << QinTop[l][q] << ", QinBot[l][q]=" << QinBot[l][q] << ", candidate[q]=" << candidate[q] << endl;
1212 WITHIN_RANGE[q] = (candidate[q] <= QinTop[l][q] and candidate[q] >= QinBot[l][q]);
1213 }
1214 if (all_of(WITHIN_RANGE.begin(), WITHIN_RANGE.end(), [] (bool x) {return x;}))
1215 {
1216 Qin_trunc[l].push_back(candidate);
1217 //lout << "push back candidate: " << candidate << endl;
1218 }
1219 }
1220 assert(Qin_trunc[l].size() > 0);
1221 }
1222 Qin_trunc[this->N_sites].push_back(Qtot);
1223
1224 if constexpr (Nq == 0)
1225 {
1227 }
1228 else
1229 {
1230 resize_arrays();
1231
1232 for (size_t l=0; l<this->N_sites; ++l)
1233 for (size_t s=0; s<qloc[l].size(); ++s)
1234 {
1235 for (size_t q=0; q<Qin_trunc[l].size(); ++q)
1236 {
1237 qarray<Nq> qin = Qin_trunc[l][q];
1238 auto qouts = Symmetry::reduceSilent(qloc[l][s],qin);
1239 for (const auto &qout:qouts)
1240 {
1241 auto it = find(Qin_trunc[l+1].begin(), Qin_trunc[l+1].end(), qout);
1242 if (it != Qin_trunc[l+1].end())
1243 {
1244 std::array<qType,2> qinout = {qin,qout};
1245 if (A[l][s].dict.find(qinout) == A[l][s].dict.end())
1246 {
1247 A[l][s].in.push_back(qin);
1248 A[l][s].out.push_back(qout);
1249 A[l][s].dict.insert({qinout,A[l][s].size()});
1250 A[l][s].plusplus();
1251 }
1252 }
1253 }
1254 }
1255
1256 A[l][s].block.resize(A[l][s].size());
1257 }
1258 }
1259 }
1260}
1261
1262template<typename Symmetry, typename Scalar>
1264outerResizeAll (size_t L_input, vector<vector<qarray<Nq> > > qloc_input, qarray<Nq> Qtot_input)
1265{
1266 this->N_sites = L_input;
1267 qloc = qloc_input;
1268 Qtot = Qtot_input;
1269 Qmulti = vector<qarray<Nq> >(1,Qtot);
1270 this->pivot = -1;
1271
1272 calc_Qlimits();
1273
1274 vector<vector<qarray<Nq> > > Qin(this->N_sites+1);
1275 Qin[0].push_back(Symmetry::qvacuum());
1276
1277 for (size_t l=1; l<this->N_sites; l++)
1278 {
1279 auto candidates = Symmetry::reduceSilent(Qin[l-1], qloc[l-1], true);
1280 assert(candidates.size() > 0);
1281
1282 for (const auto &candidate:candidates)
1283 {
1284 array<bool,Nq> WITHIN_RANGE;
1285 for (size_t q=0; q<Nq; ++q)
1286 {
1287 WITHIN_RANGE[q] = (candidate[q] <= QinTop[l][q] and candidate[q] >= QinBot[l][q]);
1288 }
1289 if (all_of(WITHIN_RANGE.begin(), WITHIN_RANGE.end(), [] (bool x) {return x;}))
1290 {
1291 Qin[l].push_back(candidate);
1292 }
1293 }
1294 }
1295 Qin[this->N_sites].push_back(Qtot);
1296
1297 vector<vector<qarray<Nq> > > Qin_(this->N_sites+1);
1298 Qin_[0].push_back(Symmetry::qvacuum());
1299 Qin_[this->N_sites].push_back(Qtot);
1300
1301 for (size_t l=this->N_sites-1; l>=1; l--)
1302 {
1303 set<qarray<Nq> > invalids;
1304
1305 for (size_t q=0; q<Qin[l].size(); ++q)
1306 {
1307 // Check if Qin[l]+qloc[l] == Qin[l+1] is fulfilled, otherwise Qin[l] is invalid
1308 auto qouts = Symmetry::reduceSilent(qloc[l],Qin[l][q]);
1309 for (const auto &qout:qouts)
1310 {
1311 if (find(Qin[l+1].begin(), Qin[l+1].end(), qout) != Qin[l+1].end())
1312 {
1313 Qin_[l].push_back(Qin[l][q]);
1314 }
1315 }
1316 }
1317 }
1318
1319 Qin = Qin_;
1320
1321 if constexpr (Nq == 0)
1322 {
1324 }
1325 else
1326 {
1327 resize_arrays();
1328
1329 for (size_t l=0; l<this->N_sites; ++l)
1330 for (size_t s=0; s<qloc[l].size(); ++s)
1331 {
1332 for (size_t q=0; q<Qin[l].size(); ++q)
1333 {
1334 qarray<Nq> qin = Qin[l][q];
1335 auto qouts = Symmetry::reduceSilent(qloc[l][s],qin);
1336 for (const auto &qout:qouts)
1337 {
1338 auto it = find(Qin[l+1].begin(), Qin[l+1].end(), qout);
1339 if (it != Qin[l+1].end())
1340 {
1341 std::array<qType,2> qinout = {qin,qout};
1342 if (A[l][s].dict.find(qinout) == A[l][s].dict.end())
1343 {
1344 A[l][s].in.push_back(qin);
1345 A[l][s].out.push_back(qout);
1346 A[l][s].dict.insert({qinout,A[l][s].size()});
1347 A[l][s].plusplus();
1348 }
1349 }
1350 }
1351 }
1352
1353 A[l][s].block.resize(A[l][s].size());
1354 }
1355 }
1356}
1357
1358template<typename Symmetry, typename Scalar>
1361{
1362 assert (Nq == 0 and "Must have Nq=0 to call outerResizeNoSymm!");
1363
1364 resize_arrays();
1365
1366 for (size_t l=0; l<this->N_sites; ++l)
1367 {
1368 for (size_t s=0; s<qloc[l].size(); ++s)
1369 {
1370 A[l][s].in.push_back(Symmetry::qvacuum());
1371 A[l][s].out.push_back(Symmetry::qvacuum());
1372 A[l][s].dict.insert({qarray2<Nq>{Symmetry::qvacuum(),Symmetry::qvacuum()}, A[l][s].dim});
1373 A[l][s].dim = 1;
1374 A[l][s].block.resize(1);
1375 }
1376 }
1377}
1378
1379template<typename Symmetry, typename Scalar>
1381innerResize (size_t Mmax)
1382{
1383 if constexpr (Nq == 0)
1384 {
1385 size_t Ml = qloc[0].size();
1386 size_t Mr = qloc[this->N_sites-1].size();
1387
1388 for (size_t s=0; s<Ml; ++s)
1389 {
1390 A[0][s].block[0].resize(1,min(Ml,Mmax));
1391 }
1392 for (size_t s=0; s<Mr; ++s)
1393 {
1394 A[this->N_sites-1][s].block[0].resize(min(Mr,Mmax),1);
1395 }
1396
1397 for (size_t l=1; l<this->N_sites/2; ++l)
1398 {
1399 size_t Ml = qloc[l].size();
1400 size_t Mr = qloc[this->N_sites-l-1].size();
1401
1402 size_t Nlrows = min(Mmax, (size_t)A[l-1][0].block[0].cols());
1403 size_t Nlcols = min(Mmax, Nlrows*Ml);
1404
1405 size_t Nrcols = min(Mmax, (size_t)A[this->N_sites-l][0].block[0].rows());
1406 size_t Nrrows = min(Mmax, Nrcols*Mr);
1407
1408 for (size_t s=0; s<Ml; ++s)
1409 {
1410 A[l][s].block[0].resize(Nlrows,Nlcols);
1411 }
1412 for (size_t s=0; s<Mr; ++s)
1413 {
1414 A[this->N_sites-l-1][s].block[0].resize(Nrrows,Nrcols);
1415 }
1416 }
1417
1418 // middle matrix for odd chain length:
1419 if (this->N_sites%2==1)
1420 {
1421 size_t centre = this->N_sites/2;
1422 int Nrows = A[centre-1][0].block[0].cols();
1423 int Ncols = A[centre+1][0].block[0].rows();
1424
1425 for (size_t s=0; s<qloc[centre].size(); ++s)
1426 {
1427 A[centre][s].block[0].resize(Nrows,Ncols);
1428 }
1429 }
1430 }
1431 else
1432 {
1433 vector<map<qarray<Nq>,size_t> > fromL(this->N_sites+1);
1434 vector<map<qarray<Nq>,size_t> > fromR(this->N_sites+1);
1435
1436 fromL[0].insert({Symmetry::qvacuum(),1});
1437 for (size_t l=1; l<this->N_sites+1; ++l)
1438 {
1439 assert(Mmax >= outbase[l-1].Nq() and "Choose a greater Minit to have at least one state per QN block.");
1440 assert(outbase[l-1].Nq() != 0 and "Probably failed to build correct quantum number graph!");
1441 size_t Dmax_in = Mmax / outbase[l-1].Nq();
1442 size_t Dmax_in_remainder = Mmax%outbase[l-1].Nq();
1443 for (size_t qout=0; qout<outbase[l-1].Nq(); ++qout)
1444 {
1445 fromL[l].insert({outbase[l-1][qout],0});
1446 for (size_t s=0; s<qloc[l-1].size(); ++s)
1447 for (size_t q=0; q<A[l-1][s].dim; ++q)
1448 {
1449 if (A[l-1][s].out[q] == outbase[l-1][qout])
1450 {
1451 qarray<Nq> qin = A[l-1][s].in[q];
1452 fromL[l][outbase[l-1][qout]] += fromL[l-1][qin];
1453 }
1454 }
1455 if (outbase[l-1][qout] == Symmetry::qvacuum())
1456 {
1457 fromL[l][outbase[l-1][qout]] = min(fromL[l][outbase[l-1][qout]], Dmax_in+Dmax_in_remainder);
1458 }
1459 else
1460 {
1461 fromL[l][outbase[l-1][qout]] = min(fromL[l][outbase[l-1][qout]], Dmax_in);
1462 }
1463 }
1464 }
1465// cout << "LEFT: " << endl;
1466// for (int l=0; l<this->N_sites+1; ++l)
1467// {
1468// cout << "l=" << l << endl;
1469// for (auto it=fromL[l].begin(); it!=fromL[l].end(); ++it)
1470// {
1471// cout << "q=" << it->first << ": " << it->second << endl;
1472// }
1473// }
1474// cout << endl;
1475
1476 for (const auto &Qval:Qmulti)
1477 {
1478 fromR[this->N_sites].insert({Qval,1});
1479 }
1480 for (size_t l=this->N_sites; l-->0;)
1481 {
1482 assert(Mmax >= inbase[l].Nq() and "Choose a greater Minit to have at least one state per QN block.");
1483 size_t Dmax_out = Mmax / inbase[l].Nq();
1484 size_t Dmax_out_remainder = Mmax%inbase[l].Nq();
1485
1486 for (size_t qin=0; qin<inbase[l].Nq(); ++qin)
1487 {
1488 fromR[l].insert({inbase[l][qin],0});
1489 for (size_t s=0; s<qloc[l].size(); ++s)
1490 for (size_t q=0; q<A[l][s].dim; ++q)
1491 {
1492 if (A[l][s].in[q] == inbase[l][qin])
1493 {
1494 qarray<Nq> qout = A[l][s].out[q];
1495 fromR[l][inbase[l][qin]] += fromR[l+1][qout];
1496 }
1497 }
1498 if (inbase[l][qin] == Symmetry::qvacuum())
1499 {
1500 fromR[l][inbase[l][qin]] = min(fromR[l][inbase[l][qin]], Dmax_out+Dmax_out_remainder);
1501 }
1502 else
1503 {
1504 fromR[l][inbase[l][qin]] = min(fromR[l][inbase[l][qin]], Dmax_out);
1505 }
1506 }
1507 }
1508 // cout << "RIGHT: " << endl;
1509 // for (size_t l=0; l<this->N_sites+1; ++l)
1510 // {
1511 // cout << "l=" << l << endl;
1512 // for (auto it=fromR[l].begin(); it!=fromR[l].end(); ++it)
1513 // {
1514 // cout << "q=" << it->first << ": " << it->second << endl;
1515 // }
1516 // }
1517
1518 vector<map<qarray<Nq>,size_t> > lrmin(this->N_sites+1);
1519 for (size_t l=0; l<this->N_sites+1; ++l)
1520 {
1521 for (auto it=fromL[l].begin(); it!=fromL[l].end(); ++it)
1522 {
1523 qarray<Nq> Qout = it->first;
1524 size_t Nql = it->second;
1525 size_t Nqr = fromR[l][Qout];
1526 lrmin[l].insert({Qout,min(Nql,Nqr)});
1527 }
1528 }
1529
1530 for (size_t l=0; l<this->N_sites; ++l)
1531 {
1532 size_t Dmax_out = Mmax / outbase[l].Nq();
1533 size_t Dmax_out_remainder = Mmax%outbase[l].Nq();
1534 size_t Dmax_in = Mmax / inbase[l].Nq();
1535 size_t Dmax_in_remainder = Mmax%inbase[l].Nq();
1536 for (size_t s=0; s<qloc[l].size(); ++s)
1537 for (size_t q=0; q<A[l][s].dim; ++q)
1538 {
1539 qarray<Nq> Qin = A[l][s].in[q];
1540 qarray<Nq> Qout = A[l][s].out[q];
1541 size_t Drow_lim=0; size_t Dcol_lim=0;
1542 if (Qin == Symmetry::qvacuum() and Qout == Symmetry::qvacuum())
1543 {
1544 Drow_lim = Dmax_in+Dmax_in_remainder;
1545 Dcol_lim = Dmax_out+Dmax_out_remainder;
1546 }
1547 else if (Qin == Symmetry::qvacuum() and Qout != Symmetry::qvacuum())
1548 {
1549 Drow_lim = Dmax_in+Dmax_in_remainder;
1550 Dcol_lim = Dmax_out;
1551 }
1552 else if (Qin != Symmetry::qvacuum() and Qout == Symmetry::qvacuum())
1553 {
1554 Drow_lim = Dmax_in;
1555 Dcol_lim = Dmax_out+Dmax_out_remainder;
1556 }
1557 else
1558 {
1559 Drow_lim = Dmax_in;
1560 Dcol_lim = Dmax_out;
1561 }
1562 size_t Nrows = min(lrmin[l][Qin], Drow_lim);
1563 size_t Ncols = min(lrmin[l+1][Qout], Dcol_lim);
1564 A[l][s].block[q].resize(Nrows,Ncols);
1565 }
1566 }
1567 }
1568
1569 update_inbase();
1571}
1572
1573template<typename Symmetry, typename Scalar>
1574template<typename Hamiltonian>
1576setProductState (const Hamiltonian &H, const vector<qarray<Nq> > &config)
1577{
1578 assert(H.length() == config.size());
1579 assert(!Symmetry::NON_ABELIAN);
1580
1581 this->N_sites = config.size();
1582 N_phys = H.volume();
1583 qloc = H.locBasis();
1584 Qtot = accumulate(config.begin(),config.end(),Symmetry::qvacuum());
1585 Qmulti = vector<qarray<Nq> >(1,Qtot);
1586 this->pivot = -1;
1587
1588 resize_arrays();
1589
1590 vector<qarray<Nq> > qouts(this->N_sites+1);
1591 qouts[0] = Symmetry::qvacuum();
1592 for (size_t l=0; l<this->N_sites; ++l)
1593 {
1594 qouts[l+1] = accumulate(config.begin(), config.begin()+l+1, Symmetry::qvacuum());
1595 }
1596
1597 for (size_t l=0; l<this->N_sites; ++l)
1598 {
1599 for (size_t s=0; s<qloc[l].size(); ++s)
1600 {
1601 qarray<Nq> qout = qouts[l+1];
1602 qarray<Nq> qin = Symmetry::reduceSilent(qout, Symmetry::flip(qloc[l][s]))[0];
1603
1604 if (qin == qouts[l])
1605 {
1606 std::array<qType,2> qinout = {qin,qout};
1607 if (A[l][s].dict.find(qinout) == A[l][s].dict.end())
1608 {
1609 A[l][s].in.push_back(qin);
1610 A[l][s].out.push_back(qout);
1611 A[l][s].dict.insert({qinout,A[l][s].size()});
1612 A[l][s].plusplus();
1613 }
1614
1615 A[l][s].block.resize(A[l][s].size());
1616 }
1617 }
1618 }
1619
1620 calc_Qlimits();
1621
1622 for (size_t l=0; l<this->N_sites; ++l)
1623 {
1624 update_inbase(l);
1625 update_outbase(l);
1626 }
1627
1628 for (size_t l=0; l<this->N_sites; ++l)
1629 for (size_t s=0; s<qloc[l].size(); ++s)
1630 for (size_t q=0; q<A[l][s].dim; ++q)
1631 {
1632 A[l][s].block[q].resize(1,1);
1633 A[l][s].block[q].setConstant(1.);
1634 }
1635}
1636
1637template<typename Symmetry, typename Scalar>
1639setRandom()
1640{
1641 for (size_t l=0; l<this->N_sites; ++l)
1642 for (size_t s=0; s<qloc[l].size(); ++s)
1643 for (size_t q=0; q<A[l][s].dim; ++q)
1644 for (size_t a1=0; a1<A[l][s].block[q].rows(); ++a1)
1645 for (size_t a2=0; a2<A[l][s].block[q].cols(); ++a2)
1646 {
1647 A[l][s].block[q](a1,a2) = threadSafeRandUniform<Scalar>(-1.,1.,true);
1648 }
1649
1650 this->pivot = -1;
1651}
1652
1653template<typename Symmetry, typename Scalar>
1655setRandom (size_t loc)
1656{
1657 for (size_t s=0; s<qloc[loc].size(); ++s)
1658 for (size_t q=0; q<A[loc][s].dim; ++q)
1659 for (size_t a1=0; a1<A[loc][s].block[q].rows(); ++a1)
1660 for (size_t a2=0; a2<A[loc][s].block[q].cols(); ++a2)
1661 {
1662 A[loc][s].block[q](a1,a2) = threadSafeRandUniform<Scalar>(-1.,1.,true);
1663 }
1664}
1665
1666template<typename Symmetry, typename Scalar>
1668setZero()
1669{
1670 for (size_t l=0; l<this->N_sites; ++l)
1671 for (size_t s=0; s<qloc[l].size(); ++s)
1672 for (size_t q=0; q<A[l][s].dim; ++q)
1673 {
1674 A[l][s].block[q].setZero();
1675 }
1676}
1677
1678template<typename Symmetry, typename Scalar>
1681{
1682 if (DIR == DMRG::DIRECTION::LEFT)
1683 {
1684 this->sweep(0, DMRG::BROOM::QR);
1686 }
1687 else
1688 {
1689 this->sweep(this->N_sites-1, DMRG::BROOM::QR);
1690 rightSweepStep(this->N_sites-1, DMRG::BROOM::QR);
1691 }
1692}
1693
1694#ifdef USE_HDF5_STORAGE
1695template<typename Symmetry, typename Scalar>
1697save (string filename, string info, double energy)
1698{
1699 assert(Boundaries.IS_TRIVIAL());
1700
1701 std::string append_str = ".h5";
1702 size_t pos = filename.rfind(append_str);
1703 if (pos == std::string::npos || pos != filename.size() - append_str.size())
1704 {
1705 filename += append_str;
1706 }
1707
1708 HDF5Interface target(filename, WRITE);
1709 target.create_group("mps");
1710 target.create_group("qloc");
1711 target.create_group("Qtot");
1712 target.create_group("Qmulti");
1713
1714 string DmaxLabel = "Dmax";
1715 string NqmaxLabel = "Nqmax";
1716 string eps_svdLabel = "eps_svd";
1717 string eps_truncWeightLabel = "eps_truncWeightLabel";
1718 string alpha_rsvdLabel = "alpha_rsvd";
1719 string add_infoLabel = "add_info";
1720
1721 // save scalar values
1722 if (!isnan(energy))
1723 {
1724 target.save_scalar(energy,"energy");
1725 }
1726 target.save_scalar(this->N_sites,"L");
1727 target.save_scalar(this->N_phys,"Nphys");
1728 for (size_t q=0; q<Nq; q++)
1729 {
1730 stringstream ss; ss << "q=" << q;
1731 target.save_scalar(this->Qtot[q],ss.str(),"Qtot");
1732 }
1733 target.save_scalar(Qmulti.size(),"QmultiSize");
1734 for (size_t i=0; i<Qmulti.size(); i++)
1735 for (size_t q=0; q<Nq; q++)
1736 {
1737 stringstream ss; ss << "q=" << q << ",i=" << i;
1738 target.save_scalar(this->Qmulti[i][q],ss.str(),"Qmulti");
1739 }
1740 target.save_scalar(this->calc_Dmax(),DmaxLabel);
1741 target.save_scalar(this->calc_Nqmax(),NqmaxLabel);
1742 target.save_scalar(this->min_Nsv,"min_Nsv");
1743 target.save_scalar(this->max_Nsv,"max_Nsv");
1744 target.save_scalar(this->eps_svd,eps_svdLabel);
1745 target.save_scalar(this->eps_truncWeight,eps_truncWeightLabel);
1746 target.save_scalar(this->alpha_rsvd,alpha_rsvdLabel);
1747 target.save_scalar(this->get_pivot(),"pivot");
1748 target.save_char(info,add_infoLabel.c_str());
1749
1750 //save qloc
1751 for (size_t l=0; l<this->N_sites; ++l)
1752 {
1753 stringstream ss; ss << "l=" << l;
1754 target.save_scalar(qloc[l].size(),ss.str(),"qloc");
1755 for (size_t s=0; s<qloc[l].size(); ++s)
1756 for (size_t q=0; q<Nq; q++)
1757 {
1758 stringstream tt; tt << "l=" << l << ",s=" << s << ",q=" << q;
1759 target.save_scalar((qloc[l][s])[q],tt.str(),"qloc");
1760 }
1761 }
1762
1763 //save the A-matrices
1764 string label;
1765 for (size_t l=0; l<this->N_sites; ++l)
1766 for (size_t s=0; s<qloc[l].size(); ++s)
1767 {
1768 stringstream tt; tt << "l=" << l << ",s=" << s;
1769 target.save_scalar(A[l][s].dim,tt.str());
1770 for (size_t q=0; q<A[l][s].dim; ++q)
1771 {
1772 for (size_t p=0; p<Nq; p++)
1773 {
1774 stringstream in; in << "in,l=" << l << ",s=" << s << ",q=" << q << ",p=" << p;
1775 stringstream out; out << "out,l=" << l << ",s=" << s << ",q=" << q << ",p=" << p;
1776 target.save_scalar((A[l][s].in[q])[p],in.str(),"mps");
1777 target.save_scalar((A[l][s].out[q])[p],out.str(),"mps");
1778 }
1779 stringstream ss;
1780 ss << l << "_" << s << "_" << "(" << A[l][s].in[q] << "," << A[l][s].out[q] << ")";
1781 label = ss.str();
1782 if constexpr (std::is_same<Scalar,complex<double>>::value)
1783 {
1784 MatrixXd Re = A[l][s].block[q].real();
1785 MatrixXd Im = A[l][s].block[q].imag();
1786 target.save_matrix(Re,label+"Re","mps");
1787 target.save_matrix(Im,label+"Im","mps");
1788 }
1789 else
1790 {
1791 target.save_matrix(A[l][s].block[q],label,"mps");
1792 }
1793 }
1794 }
1795 target.close();
1796}
1797
1798template<typename Symmetry, typename Scalar>
1800load (string filename, double &energy)
1801{
1802 std::string append_str = ".h5";
1803 size_t pos = filename.rfind(append_str);
1804 if (pos == std::string::npos || pos != filename.size() - append_str.size())
1805 {
1806 filename += append_str;
1807 }
1808 HDF5Interface source(filename, READ);
1809
1810 string eps_svdLabel = "eps_svd";
1811 string eps_truncWeightLabel = "eps_truncWeightLabel";
1812 string alpha_rsvdLabel = "alpha_rsvd";
1813 size_t QmultiSize;
1814
1815 //load the scalars
1816 if (source.CHECK("energy"))
1817 {
1818 source.load_scalar(energy,"energy");
1819 }
1820 source.load_scalar(this->N_sites,"L");
1821 source.load_scalar(this->N_phys,"Nphys");
1822 for (size_t q=0; q<Nq; q++)
1823 {
1824 stringstream ss; ss << "q=" << q;
1825 source.load_scalar(this->Qtot[q],ss.str(),"Qtot");
1826 }
1827 source.load_scalar(QmultiSize,"QmultiSize");
1828// cout << "QmultiSize=" << QmultiSize << endl;
1829 this->Qmulti.resize(QmultiSize);
1830 for (size_t i=0; i<QmultiSize; i++)
1831 for (size_t q=0; q<Nq; q++)
1832 {
1833 stringstream ss; ss << "q=" << q << ",i=" << i;
1834// cout << "q=" << q << ", i=" << i << endl;
1835 source.load_scalar(this->Qmulti[i][q],ss.str(),"Qmulti");
1836 }
1837 source.load_scalar(this->eps_svd,eps_svdLabel);
1838 // To ensure older files can be loaded, make check here
1839 // HAS_GROUP is the same for groups and single objects
1840 if (source.HAS_GROUP(eps_truncWeightLabel)) source.load_scalar(this->eps_truncWeight,eps_truncWeightLabel);
1841 source.load_scalar(this->alpha_rsvd,alpha_rsvdLabel);
1842 source.load_scalar(this->pivot,"pivot");
1843 source.load_scalar(this->min_Nsv,"min_Nsv");
1844 source.load_scalar(this->max_Nsv,"max_Nsv");
1845
1846 //load qloc
1847 qloc.resize(this->N_sites);
1848 for (size_t l=0; l<this->N_sites; ++l)
1849 {
1850 stringstream ss; ss << "l=" << l;
1851 size_t qloc_size;
1852 source.load_scalar(qloc_size,ss.str(),"qloc");
1853 qloc[l].resize(qloc_size);
1854 for (size_t s=0; s<qloc[l].size(); ++s)
1855 for (size_t q=0; q<Nq; q++)
1856 {
1857 stringstream tt; tt << "l=" << l << ",s=" << s << ",q=" << q;
1858 int Q;
1859 source.load_scalar(Q,tt.str(),"qloc");
1860 (qloc[l][s])[q] = Q;
1861 }
1862 }
1863 resize_arrays();
1864
1865 //load the A-matrices
1866 string label;
1867 for (size_t l=0; l<this->N_sites; ++l)
1868 for (size_t s=0; s<qloc[l].size(); ++s)
1869 {
1870 size_t Asize;
1871 stringstream tt; tt << "l=" << l << ",s=" << s;
1872 source.load_scalar(Asize,tt.str());
1873 for (size_t q=0; q<Asize; ++q)
1874 {
1875 qarray<Nq> qin,qout;
1876 for (size_t p=0; p<Nq; p++)
1877 {
1878 stringstream in; in << "in,l=" << l << ",s=" << s << ",q=" << q << ",p=" << p;
1879 stringstream out; out << "out,l=" << l << ",s=" << s << ",q=" << q << ",p=" << p;
1880 source.load_scalar(qin[p],in.str(),"mps");
1881 source.load_scalar(qout[p],out.str(),"mps");
1882 }
1883 stringstream ss;
1884 ss << l << "_" << s << "_" << "(" << qin << "," << qout << ")";
1885 label = ss.str();
1886 MatrixType mat;
1887 if constexpr (std::is_same<Scalar,complex<double>>::value)
1888 {
1889 MatrixXd Re, Im;
1890 source.load_matrix(Re, label+"Re", "mps");
1891 source.load_matrix(Im, label+"Im", "mps");
1892 mat = Re+1.i*Im;
1893 }
1894 else
1895 {
1896 source.load_matrix(mat, label, "mps");
1897 }
1898 A[l][s].push_back(qin,qout,mat);
1899 }
1900 }
1901 source.close();
1902 update_inbase();
1904 calc_Qlimits();
1905 Boundaries.set_open_bc(Qtot);
1906}
1907#endif
1908
1909template<typename Symmetry, typename Scalar>
1910std::size_t Mps<Symmetry,Scalar>::
1911calc_Mmax () const
1912{
1913 size_t res = 0;
1914 for (size_t l=0; l<this->N_sites; ++l)
1915 {
1916 if (inbase[l].M() > res) {res = inbase[l].M();}
1917 if (outbase[l].M() > res) {res = outbase[l].M();}
1918 }
1919 return res;
1920}
1921
1922template<typename Symmetry, typename Scalar>
1923std::size_t Mps<Symmetry,Scalar>::
1924get_Min (size_t loc) const
1925{
1926 return inbase[loc].M();
1927}
1928
1929template<typename Symmetry, typename Scalar>
1930std::size_t Mps<Symmetry,Scalar>::
1931get_Mout (size_t loc) const
1932{
1933 return outbase[loc].M();
1934}
1935
1936template<typename Symmetry, typename Scalar>
1937std::size_t Mps<Symmetry,Scalar>::
1938calc_fullMmax () const
1939{
1940 size_t res = 0;
1941 for (size_t l=0; l<this->N_sites; ++l)
1942 {
1943 if (inbase[l].fullM() > res) {res = inbase[l].fullM();}
1944 if (outbase[l].fullM() > res) {res = outbase[l].fullM();}
1945 }
1946 return res;
1947}
1948
1949template<typename Symmetry, typename Scalar>
1951calc_Dmax() const
1952{
1953 size_t res = 0;
1954 for (size_t l=0; l<this->N_sites; ++l)
1955 {
1956 if (inbase[l].Dmax() > res) {res = inbase[l].Dmax();}
1957 if (outbase[l].Dmax() > res) {res = outbase[l].Dmax();}
1958 }
1959 return res;
1960}
1961
1962template<typename Symmetry, typename Scalar>
1964calc_Nqmax() const
1965{
1966 size_t res = 0;
1967 for (size_t l=0; l<this->N_sites; ++l)
1968 {
1969 if (inbase[l].Nq() > res) {res = inbase[l].Nq();}
1970 if (outbase[l].Nq() > res) {res = outbase[l].Nq();}
1971 }
1972 return res;
1973}
1974
1975template<typename Symmetry, typename Scalar>
1977calc_Nqavg() const
1978{
1979 double res = 0.;
1980 for (size_t l=0; l<this->N_sites; ++l)
1981 {
1982 res += outbase[l].Nq();
1983 }
1984 return res/this->N_sites;
1985}
1986
1987template<typename Symmetry, typename Scalar>
1989update_inbase (size_t loc)
1990{
1991 inbase[loc].clear();
1992 inbase[loc].pullData(A[loc],0);
1993}
1994
1995template<typename Symmetry, typename Scalar>
1997update_outbase (size_t loc)
1998{
1999 outbase[loc].clear();
2000 outbase[loc].pullData(A[loc],1);
2001
2002// if (loc == this->N_sites-1)
2003// {
2004// vector<qarray<Symmetry::Nq> > Qtot_vector;
2005// Qtot_vector.push_back(Symmetry::flip(Qtot));
2006// Qbasis<Symmetry> Qtot_flow_out(Qtot_vector);
2007// outbase[loc].add(Qtot_flow_out);
2008// Qtot = Symmetry::qvacuum();
2009// }
2010}
2011
2012template<typename Symmetry, typename Scalar>
2014leftSweepStep (size_t loc, DMRG::BROOM::OPTION TOOL, PivotMatrix1<Symmetry,Scalar,Scalar> *H, bool DISCARD_U)
2015{
2016 if (TOOL == DMRG::BROOM::RICH_SVD)
2017 {
2018 enrich_left(loc,H);
2019 }
2020 ArrayXd truncWeightSub(inbase[loc].Nq()); truncWeightSub.setZero();
2021 ArrayXd entropySub(inbase[loc].Nq()); entropySub.setZero();
2022 if (loc != 0) {SVspec[loc-1].clear();}
2023
2024 vector<Biped<Symmetry,MatrixType> > Aloc;
2025 Aloc.resize(qloc[loc].size());
2026 vector<Biped<Symmetry,MatrixType> > Aprev;
2027 if (loc != 0 and DISCARD_U == false)
2028 {
2029 Aprev.resize(qloc[loc-1].size());
2030 }
2031
2032 Blocker<Symmetry,Scalar> Jim(A[loc],qloc[loc],inbase[loc],outbase[loc]);
2033 auto Aclump = Jim.Aclump(DMRG::DIRECTION::RIGHT);
2034
2035 bool RETURN_SPEC = false;
2036 if (loc != 0) RETURN_SPEC = true;
2037
2038 double entropy;
2039 map<qarray<Nq>,ArrayXd> SVspec_;
2040 Biped<Symmetry,MatrixType> left,right;
2041 if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::RICH_SVD or TOOL == DMRG::BROOM::BRUTAL_SVD)
2042 {
2043 auto [U,Sigma,Vdag] = Aclump.truncateSVD(this->min_Nsv, this->max_Nsv, this->eps_truncWeight, truncWeight(loc), entropy, SVspec_, false, RETURN_SPEC); //false: DONT PRESERVE MULTIPLETS
2044 if (loc != 0)
2045 {
2046 S(loc-1) = entropy;
2047 // cout << "loc=" << loc << ", entropy in leftSweepStep: " << S(loc-1) << endl;
2048 SVspec[loc-1] = SVspec_;
2049 }
2050 right = Vdag;
2051 left = U.contract(Sigma);
2052 }
2053 else if (TOOL == DMRG::BROOM::QR)
2054 {
2055 auto [Q,R] = Aclump.adjoint().QR(true); //true: receive LQ decomposition by taking adjoint of QR
2056 left = R;
2057 right = Q;
2058 }
2059
2060 Aloc = Jim.reblock(right, DMRG::DIRECTION::RIGHT);
2061 if (loc != 0 and DISCARD_U == false)
2062 {
2063 for (size_t s=0; s<qloc[loc-1].size(); ++s)
2064 for (size_t q=0; q<A[loc-1][s].dim; ++q)
2065 {
2066 MatrixType Mtmp;
2067 auto itleft = left.dict.find({A[loc-1][s].out[q],A[loc-1][s].out[q]});
2068 if (itleft != left.dict.end())
2069 {
2070 Mtmp = A[loc-1][s].block[q] * left.block[itleft->second];
2071 auto it = Aprev[s].dict.find(qarray2<Nq>{A[loc-1][s].in[q], A[loc-1][s].out[q]});
2072 if (Mtmp.size() != 0)
2073 {
2074 Aprev[s].try_push_back(A[loc-1][s].in[q], A[loc-1][s].out[q], Mtmp);
2075 }
2076 }
2077 }
2078 }
2079 // A[loc-1] = Jim.reblock(U.contract(S), DMRG::DIRECTION::RIGHT);
2080// #ifndef DMRG_DONT_USE_OPENMP
2081// #pragma omp parallel for
2082// #endif
2083// for (size_t qin=0; qin<inbase[loc].Nq(); ++qin)
2084// {
2085// // determine how many A's to glue together
2086// vector<size_t> svec, qvec, Ncolsvec;
2087// for (size_t s=0; s<qloc[loc].size(); ++s)
2088// for (size_t q=0; q<A[loc][s].dim; ++q)
2089// {
2090// if (A[loc][s].in[q] == inbase[loc][qin] and
2091// A[loc][s].block[q].rows() > 0 and
2092// A[loc][s].block[q].cols() > 0)
2093// {
2094// svec.push_back(s);
2095// qvec.push_back(q);
2096// Ncolsvec.push_back(A[loc][s].block[q].cols());
2097// }
2098// }
2099
2100// if (Ncolsvec.size() > 0)
2101// {
2102// // do the glue
2103// size_t Nrows = A[loc][svec[0]].block[qvec[0]].rows();
2104// // if (Qtot[0] == 5)
2105// // {
2106// // for (size_t i=0; i<svec.size(); ++i)
2107// // {
2108// // cout << "loc=" << loc << ", i=" << i << ", A[loc][svec[i]].block[qvec[i]].rows()=" << A[loc][svec[i]].block[qvec[i]].rows()
2109// // << ", in=" << A[loc][svec[i]].in[qvec[i]] << ", out=" << A[loc][svec[i]].out[qvec[i]] << endl;
2110// // }
2111// // cout << endl;
2112// // }
2113// for (size_t i=1; i<svec.size(); ++i) assert(A[loc][svec[i]].block[qvec[i]].rows() == Nrows);
2114// size_t Ncols = accumulate(Ncolsvec.begin(), Ncolsvec.end(), 0);
2115
2116// MatrixType Aclump(Nrows,Ncols);
2117// size_t stitch = 0;
2118// for (size_t i=0; i<svec.size(); ++i)
2119// {
2120// Aclump.block(0,stitch, Nrows,Ncolsvec[i]) = A[loc][svec[i]].block[qvec[i]]*
2121// Symmetry::coeff_leftSweep(
2122// A[loc][svec[i]].out[qvec[i]],
2123// A[loc][svec[i]].in[qvec[i]]);
2124// // Aclump.block(0,stitch, Nrows,Ncolsvec[i]) = A[loc][svec[i]].block[qvec[i]]*
2125// // Symmetry::coeff_leftSweep2(
2126// // A[loc][svec[i]].out[qvec[i]],
2127// // A[loc][svec[i]].in[qvec[i]],
2128// // qloc[loc][svec[i]]);
2129// stitch += Ncolsvec[i];
2130// }
2131
2132// #ifdef DONT_USE_BDCSVD
2133// JacobiSVD<MatrixType> Jack; // standard SVD
2134// #else
2135// BDCSVD<MatrixType> Jack; // "Divide and conquer" SVD (only available in Eigen)
2136// #endif
2137
2138// HouseholderQR<MatrixType> Quirinus; MatrixType Qmatrix, Rmatrix; // QR
2139
2140// size_t Nret = Nrows; // retained states
2141
2142// if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::BRUTAL_SVD or TOOL == DMRG::BROOM::RICH_SVD)
2143// {
2144// Jack.compute(Aclump,ComputeThinU|ComputeThinV);
2145// ArrayXd SV = Jack.singularValues();
2146// // sqrt(Symmetry::degeneracy(inbase[loc][qin]))
2147
2148// if (loc != 0) {SVspec[loc-1].insert(pair<qarray<Symmetry::Nq>,ArrayXd>(outbase[loc][qin],SV));}
2149
2150// if (TOOL == DMRG::BROOM::BRUTAL_SVD)
2151// {
2152// Nret = min(static_cast<size_t>(SV.rows()), this->max_Nsv);
2153// }
2154// else
2155// {
2156// Nret = (SV > this->eps_svd).count();
2157// }
2158// Nret = max(Nret, this->min_Nsv);
2159// Nret = min(Nret, this->max_Nsv);
2160// Nret = min(Nret, static_cast<size_t>(Jack.singularValues().rows()));
2161// truncWeightSub(qin) = Symmetry::degeneracy(inbase[loc][qin]) * SV.tail(SV.rows()-Nret).cwiseAbs2().sum();
2162
2163// // calculate entropy
2164// size_t Nnz = (SV > 0.).count();
2165// entropySub(qin) = -Symmetry::degeneracy(inbase[loc][qin]) *
2166// (SV.head(Nnz).array().square() * SV.head(Nnz).array().square().log()).sum();
2167// }
2168// else if (TOOL == DMRG::BROOM::QR)
2169// {
2170// Quirinus.compute(Aclump.adjoint());
2171// Qmatrix = (Quirinus.householderQ() * MatrixType::Identity(Aclump.cols(),Aclump.rows())).adjoint();
2172// Rmatrix = (MatrixType::Identity(Aclump.rows(),Aclump.cols()) * Quirinus.matrixQR().template triangularView<Upper>()).adjoint();
2173// }
2174
2175// if (Nret > 0)
2176// {
2177// // update A[loc]
2178// stitch = 0;
2179// for (size_t i=0; i<svec.size(); ++i)
2180// {
2181// MatrixType Mtmp;
2182
2183// if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::BRUTAL_SVD or TOOL == DMRG::BROOM::RICH_SVD)
2184// {
2185// Mtmp = Jack.matrixV().adjoint().block(0,stitch, Nret,Ncolsvec[i])*
2186// Symmetry::coeff_leftSweep(
2187// A[loc][svec[i]].in[qvec[i]],
2188// A[loc][svec[i]].out[qvec[i]]);
2189// // Mtmp = Jack.matrixV().adjoint().block(0,stitch, Nret,Ncolsvec[i])*
2190// // Symmetry::coeff_leftSweep3(
2191// // A[loc][svec[i]].in[qvec[i]],
2192// // A[loc][svec[i]].out[qvec[i]],
2193// // qloc[loc][svec[i]]);
2194// }
2195// else if (TOOL == DMRG::BROOM::QR)
2196// {
2197// Mtmp = Qmatrix.block(0,stitch, Nrows,Ncolsvec[i])*
2198// Symmetry::coeff_leftSweep(
2199// A[loc][svec[i]].in[qvec[i]],
2200// A[loc][svec[i]].out[qvec[i]]);
2201// // Mtmp = Qmatrix.block(0,stitch, Nret,Ncolsvec[i])*
2202// // Symmetry::coeff_leftSweep3(
2203// // A[loc][svec[i]].in[qvec[i]],
2204// // A[loc][svec[i]].out[qvec[i]],
2205// // qloc[loc][svec[i]]);
2206// }
2207
2208// if (Mtmp.size() != 0)
2209// {
2210// Aloc[svec[i]].push_back(A[loc][svec[i]].in[qvec[i]], A[loc][svec[i]].out[qvec[i]], Mtmp);
2211// }
2212// stitch += Ncolsvec[i];
2213// }
2214
2215// // update A[loc-1]
2216// if (loc != 0 and DISCARD_U == false)
2217// {
2218// for (size_t s=0; s<qloc[loc-1].size(); ++s)
2219// for (size_t q=0; q<A[loc-1][s].dim; ++q)
2220// {
2221// if (A[loc-1][s].out[q] == inbase[loc][qin])
2222// {
2223// MatrixType Mtmp;
2224
2225// if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::BRUTAL_SVD or TOOL == DMRG::BROOM::RICH_SVD)
2226// {
2227// Mtmp = A[loc-1][s].block[q] *
2228// Jack.matrixU().leftCols(Nret) *
2229// Jack.singularValues().head(Nret).asDiagonal();
2230// }
2231// else if (TOOL == DMRG::BROOM::QR)
2232// {
2233// Mtmp = A[loc-1][s].block[q] * Rmatrix;
2234// }
2235
2236// auto it = Aprev[s].dict.find(qarray2<Nq>{A[loc-1][s].in[q], A[loc-1][s].out[q]});
2237// if (Mtmp.size() != 0)
2238// {
2239// Aprev[s].try_push_back(A[loc-1][s].in[q], A[loc-1][s].out[q], Mtmp);
2240// }
2241// }
2242// }
2243// }
2244// }
2245// }
2246// }
2247 for (size_t s=0; s<qloc[loc].size(); ++s)
2248 {
2249 A[loc][s] = Aloc[s].cleaned();
2250 }
2251 if (loc != 0 and DISCARD_U == false)
2252 {
2253 for (size_t s=0; s<qloc[loc-1].size(); ++s)
2254 {
2255 A[loc-1][s] = Aprev[s].cleaned();
2256 }
2257 }
2258
2259 update_inbase(loc);
2260 if (loc != 0 and DISCARD_U == false)
2261 {
2262 update_outbase(loc-1);
2263 }
2264
2265 // if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::RICH_SVD)
2266 // {
2267 // truncWeight(loc) = truncWeightSub.sum();
2268 // }
2269
2270 // entropy
2271 // if (TOOL == DMRG::BROOM::SVD or
2272 // (TOOL == DMRG::BROOM::RICH_SVD and this->alpha_rsvd == 0.))
2273 // {
2274 // int bond = (loc==0)? -1 : loc;
2275 // if (bond != -1)
2276 // {
2277 // S(loc-1) = entropySub.sum();
2278 // }
2279 // }
2280 this->pivot = (loc==0)? 0 : loc-1;
2281}
2282
2283template<typename Symmetry, typename Scalar>
2285rightSweepStep (size_t loc, DMRG::BROOM::OPTION TOOL, PivotMatrix1<Symmetry,Scalar,Scalar> *H, bool DISCARD_V)
2286{
2287 if (TOOL == DMRG::BROOM::RICH_SVD)
2288 {
2289 enrich_right(loc,H);
2290 }
2291
2292 ArrayXd truncWeightSub(outbase[loc].Nq()); truncWeightSub.setZero();
2293 ArrayXd entropySub(outbase[loc].Nq()); entropySub.setZero();
2294 if (loc != this->N_sites-1) {SVspec[loc].clear();}
2295 map<qarray<Nq>,ArrayXd> SVspec_;
2296 double entropy;
2297
2298 vector<Biped<Symmetry,MatrixType> > Aloc(qloc[loc].size());
2299 vector<Biped<Symmetry,MatrixType> > Anext;
2300 if (loc != this->N_sites-1 and DISCARD_V == false)
2301 {
2302 Anext.resize(qloc[loc+1].size());
2303 }
2304
2305 Blocker<Symmetry,Scalar> Jim(A[loc],qloc[loc],inbase[loc],outbase[loc]);
2306 auto Aclump = Jim.Aclump(DMRG::DIRECTION::LEFT);
2307 Biped<Symmetry,MatrixType> left, right;
2308 if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::RICH_SVD or TOOL == DMRG::BROOM::BRUTAL_SVD)
2309 {
2310 auto [U,Sigma,Vdag] = Aclump.truncateSVD(this->min_Nsv, this->max_Nsv, this->eps_truncWeight, truncWeight(loc), entropy, SVspec_, false); //false: DONT PRESERVE MULTIPLETS
2311 if (loc != this->N_sites-1)
2312 {
2313 S(loc) = entropy;
2314 SVspec[loc] = SVspec_;
2315 }
2316 left = U;
2317 right = Sigma.contract(Vdag);
2318 }
2319 else if (TOOL == DMRG::BROOM::QR)
2320 {
2321 auto [Q,R] = Aclump.QR();
2322 left = Q;
2323 right = R;
2324 }
2325
2326 // cout << "loc=" << loc << ", entropy in rightSweepStep: " << S(loc) << endl;
2327 Aloc = Jim.reblock(left, DMRG::DIRECTION::LEFT);
2328 if (loc != this->N_sites-1 and DISCARD_V == false)
2329 {
2330 for (size_t s=0; s<qloc[loc+1].size(); ++s)
2331 for (size_t q=0; q<A[loc+1][s].dim; ++q)
2332 {
2333 MatrixType Mtmp;
2334 auto itright = right.dict.find({A[loc+1][s].in[q],A[loc+1][s].in[q]});
2335 if (itright != right.dict.end())
2336 {
2337 Mtmp = right.block[itright->second] * A[loc+1][s].block[q];
2338 auto it = Anext[s].dict.find(qarray2<Nq>{A[loc+1][s].in[q], A[loc+1][s].out[q]});
2339 if (Mtmp.size() != 0)
2340 {
2341 Anext[s].try_push_back(A[loc+1][s].in[q], A[loc+1][s].out[q], Mtmp);
2342 }
2343 }
2344 }
2345 }
2346
2347 // #ifndef DMRG_DONT_USE_OPENMP
2348 // #pragma omp parallel for
2349 // #endif
2350 // for (size_t qout=0; qout<outbase[loc].Nq(); ++qout)
2351 // {
2352 // // determine how many A's to glue together
2353 // vector<size_t> svec, qvec, Nrowsvec;
2354 // for (size_t s=0; s<qloc[loc].size(); ++s)
2355 // for (size_t q=0; q<A[loc][s].dim; ++q)
2356 // {
2357 // if (A[loc][s].out[q] == outbase[loc][qout] and
2358 // A[loc][s].block[q].rows() > 0 and
2359 // A[loc][s].block[q].cols() > 0)
2360 // {
2361 // svec.push_back(s);
2362 // qvec.push_back(q);
2363 // Nrowsvec.push_back(A[loc][s].block[q].rows());
2364 // }
2365 // }
2366
2367 // if (Nrowsvec.size() > 0)
2368 // {
2369 // // do the glue
2370 // size_t Ncols = A[loc][svec[0]].block[qvec[0]].cols();
2371 // for (size_t i=1; i<svec.size(); ++i) {assert(A[loc][svec[i]].block[qvec[i]].cols() == Ncols);}
2372 // size_t Nrows = accumulate(Nrowsvec.begin(),Nrowsvec.end(),0);
2373
2374 // MatrixType Aclump(Nrows,Ncols);
2375 // Aclump.setZero();
2376 // size_t stitch = 0;
2377 // for (size_t i=0; i<svec.size(); ++i)
2378 // {
2379 // Aclump.block(stitch,0, Nrowsvec[i],Ncols) = A[loc][svec[i]].block[qvec[i]];
2380 // stitch += Nrowsvec[i];
2381 // }
2382
2383 // #ifdef DONT_USE_BDCSVD
2384 // JacobiSVD<MatrixType> Jack; // standard SVD
2385 // #else
2386 // BDCSVD<MatrixType> Jack; // "Divide and conquer" SVD (only in Eigen available)
2387 // #endif
2388
2389 // HouseholderQR<MatrixType> Quirinus; MatrixType Qmatrix, Rmatrix; // Eigen QR
2390
2391 // size_t Nret = Ncols; // retained states
2392
2393 // if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::BRUTAL_SVD or TOOL == DMRG::BROOM::RICH_SVD)
2394 // {
2395 // Jack.compute(Aclump,ComputeThinU|ComputeThinV);
2396 // ArrayXd SV = Jack.singularValues();
2397 // // sqrt(Symmetry::degeneracy(outbase[loc][qout]))
2398
2399 // SVspec[loc].insert(pair<qarray<Symmetry::Nq>,ArrayXd>(outbase[loc][qout],SV));
2400
2401 // if (TOOL == DMRG::BROOM::BRUTAL_SVD)
2402 // {
2403 // Nret = min(static_cast<size_t>(SV.rows()), this->max_Nsv);
2404 // }
2405 // else
2406 // {
2407 // Nret = (SV > this->eps_svd).count();
2408 // }
2409 // Nret = max(Nret, this->min_Nsv);
2410 // Nret = min(Nret, this->max_Nsv);
2411 // Nret = min(Nret, static_cast<size_t>(Jack.singularValues().rows()));
2412 // truncWeightSub(qout) = Symmetry::degeneracy(outbase[loc][qout]) * SV.tail(SV.rows()-Nret).cwiseAbs2().sum();
2413
2414 // // calculate entropy
2415 // size_t Nnz = (SV > 0.).count();
2416 // entropySub(qout) = -Symmetry::degeneracy(outbase[loc][qout]) *
2417 // (SV.head(Nnz).array().square() * SV.head(Nnz).array().square().log()).sum();
2418 // }
2419 // else if (TOOL == DMRG::BROOM::QR)
2420 // {
2421 // Quirinus.compute(Aclump);
2422 // Qmatrix = Quirinus.householderQ() * MatrixType::Identity(Aclump.rows(),Aclump.cols());
2423 // Rmatrix = MatrixType::Identity(Aclump.cols(),Aclump.rows()) * Quirinus.matrixQR().template triangularView<Upper>();
2424 // }
2425
2426 // if (Nret > 0)
2427 // {
2428 // // update A[loc]
2429 // stitch = 0;
2430 // for (size_t i=0; i<svec.size(); ++i)
2431 // {
2432 // MatrixType Mtmp;
2433 // if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::BRUTAL_SVD or TOOL == DMRG::BROOM::RICH_SVD)
2434 // {
2435 // // A[loc][svec[i]].block[qvec[i]]
2436 // Mtmp = Jack.matrixU().block(stitch,0, Nrowsvec[i],Nret);
2437 // }
2438 // else if (TOOL == DMRG::BROOM::QR)
2439 // {
2440 // Mtmp = Qmatrix.block(stitch,0, Nrowsvec[i],Ncols);
2441 // }
2442
2443 // if (Mtmp.size() != 0)
2444 // {
2445 // Aloc[svec[i]].push_back(A[loc][svec[i]].in[qvec[i]], A[loc][svec[i]].out[qvec[i]], Mtmp);
2446 // }
2447 // stitch += Nrowsvec[i];
2448 // }
2449
2450 // // update A[loc+1]
2451 // if (loc != this->N_sites-1 and DISCARD_V == false)
2452 // {
2453 // for (size_t s=0; s<qloc[loc+1].size(); ++s)
2454 // for (size_t q=0; q<A[loc+1][s].dim; ++q)
2455 // {
2456 // if (A[loc+1][s].in[q] == outbase[loc][qout])
2457 // {
2458 // MatrixType Mtmp;
2459
2460 // if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::BRUTAL_SVD or TOOL == DMRG::BROOM::RICH_SVD)
2461 // {
2462 // Mtmp = Jack.singularValues().head(Nret).asDiagonal() *
2463 // Jack.matrixV().adjoint().topRows(Nret) *
2464 // A[loc+1][s].block[q];
2465 // }
2466 // else if (TOOL == DMRG::BROOM::QR)
2467 // {
2468 // Mtmp = Rmatrix * A[loc+1][s].block[q];
2469 // }
2470
2471 // auto it = Anext[s].dict.find(qarray2<Nq>{A[loc+1][s].in[q], A[loc+1][s].out[q]});
2472 // if (Mtmp.size() != 0)
2473 // {
2474 // Anext[s].try_push_back(A[loc+1][s].in[q], A[loc+1][s].out[q], Mtmp);
2475 // }
2476 // }
2477 // }
2478 // }
2479 // }
2480 // }
2481 // }
2482
2483 for (size_t s=0; s<qloc[loc].size(); ++s)
2484 {
2485 A[loc][s] = Aloc[s].cleaned();
2486 }
2487 if (loc != this->N_sites-1 and DISCARD_V == false)
2488 {
2489 for (size_t s=0; s<qloc[loc+1].size(); ++s)
2490 {
2491 A[loc+1][s] = Anext[s].cleaned();
2492 }
2493 }
2494
2495 update_outbase(loc);
2496 if (loc != this->N_sites-1 and DISCARD_V == false)
2497 {
2498 update_inbase(loc+1);
2499 }
2500
2501 // if (TOOL == DMRG::BROOM::SVD or TOOL == DMRG::BROOM::RICH_SVD)
2502 // {
2503 // truncWeight(loc) = truncWeightSub.sum();
2504 // }
2505
2506 // entropy
2507 // if (TOOL == DMRG::BROOM::SVD or
2508 // (TOOL == DMRG::BROOM::RICH_SVD and this->alpha_rsvd == 0.))
2509 // {
2510 // int bond = (loc==this->N_sites-1)? -1 : loc;
2511 // if (bond != -1)
2512 // {
2513 // S(loc) = entropySub.sum();
2514 // }
2515 // }
2516 this->pivot = (loc==this->N_sites-1)? this->N_sites-1 : loc+1;
2517}
2518
2519template<typename Symmetry, typename Scalar>
2521calc_N (DMRG::DIRECTION::OPTION DIR, size_t loc, vector<Biped<Symmetry,MatrixType> > &N)
2522{
2523 N.clear();
2524 N.resize(qloc[loc].size());
2525
2526 if (DIR == DMRG::DIRECTION::LEFT)
2527 {
2528 for (size_t qin=0; qin<inbase[loc].Nq(); ++qin)
2529 {
2530 // determine how many A's to glue together
2531 vector<size_t> svec, qvec, Ncolsvec;
2532 for (size_t s=0; s<qloc[loc].size(); ++s)
2533 for (size_t q=0; q<A[loc][s].dim; ++q)
2534 {
2535 if (A[loc][s].in[q] == inbase[loc][qin])
2536 {
2537 svec.push_back(s);
2538 qvec.push_back(q);
2539 Ncolsvec.push_back(A[loc][s].block[q].cols());
2540 }
2541 }
2542
2543 if (Ncolsvec.size() > 0)
2544 {
2545 // do the glue
2546 size_t Nrows = A[loc][svec[0]].block[qvec[0]].rows();
2547 for (size_t i=1; i<svec.size(); ++i) {assert(A[loc][svec[i]].block[qvec[i]].rows() == Nrows);}
2548 size_t Ncols = accumulate(Ncolsvec.begin(), Ncolsvec.end(), 0);
2549
2550 MatrixType Aclump(Nrows,Ncols);
2551 size_t stitch = 0;
2552 for (size_t i=0; i<svec.size(); ++i)
2553 {
2554 Aclump.block(0,stitch, Nrows,Ncolsvec[i]) = A[loc][svec[i]].block[qvec[i]]*
2555 Symmetry::coeff_leftSweep(
2556 A[loc][svec[i]].out[qvec[i]],
2557 A[loc][svec[i]].in[qvec[i]]);
2558 stitch += Ncolsvec[i];
2559 }
2560
2561 HouseholderQR<MatrixType> Quirinus(Aclump.adjoint());
2562 MatrixType Qmatrix = Quirinus.householderQ().adjoint();
2563 size_t Nret = Nrows; // retained states
2564
2565 // fill N
2566 stitch = 0;
2567 for (size_t i=0; i<svec.size(); ++i)
2568 {
2569 if (Qmatrix.rows() > Nret)
2570 {
2571 size_t Nnull = Qmatrix.rows()-Nret;
2572 MatrixType Mtmp = Qmatrix.block(Nret,stitch, Nnull,Ncolsvec[i])*
2573 Symmetry::coeff_leftSweep(
2574 A[loc][svec[i]].in[qvec[i]],
2575 A[loc][svec[i]].out[qvec[i]]);
2576 N[svec[i]].try_push_back(A[loc][svec[i]].in[qvec[i]], A[loc][svec[i]].out[qvec[i]], Mtmp);
2577 }
2578 stitch += Ncolsvec[i];
2579 }
2580 }
2581 }
2582 }
2583 else if (DIR == DMRG::DIRECTION::RIGHT)
2584 {
2585 for (size_t qout=0; qout<outbase[loc].Nq(); ++qout)
2586 {
2587 // determine how many A's to glue together
2588 vector<size_t> svec, qvec, Nrowsvec;
2589 for (size_t s=0; s<qloc[loc].size(); ++s)
2590 for (size_t q=0; q<A[loc][s].dim; ++q)
2591 {
2592 if (A[loc][s].out[q] == outbase[loc][qout])
2593 {
2594 svec.push_back(s);
2595 qvec.push_back(q);
2596 Nrowsvec.push_back(A[loc][s].block[q].rows());
2597 }
2598 }
2599
2600 if (Nrowsvec.size() > 0)
2601 {
2602 // do the glue
2603 size_t Ncols = A[loc][svec[0]].block[qvec[0]].cols();
2604 for (size_t i=1; i<svec.size(); ++i) {assert(A[loc][svec[i]].block[qvec[i]].cols() == Ncols);}
2605 size_t Nrows = accumulate(Nrowsvec.begin(),Nrowsvec.end(),0);
2606
2607 MatrixType Aclump(Nrows,Ncols);
2608 Aclump.setZero();
2609 size_t stitch = 0;
2610 for (size_t i=0; i<svec.size(); ++i)
2611 {
2612 Aclump.block(stitch,0, Nrowsvec[i],Ncols) = A[loc][svec[i]].block[qvec[i]];
2613 stitch += Nrowsvec[i];
2614 }
2615
2616 HouseholderQR<MatrixType> Quirinus(Aclump);
2617 MatrixType Qmatrix = Quirinus.householderQ();
2618 size_t Nret = Ncols; // retained states
2619
2620 // fill N
2621 stitch = 0;
2622 for (size_t i=0; i<svec.size(); ++i)
2623 {
2624 if (Qmatrix.cols() > Nret)
2625 {
2626 size_t Nnull = Qmatrix.cols()-Nret;
2627// N[loc][svec[i]].block[qvec[i]] = Qmatrix.block(stitch,Nret, Nrowsvec[i],Nnull);
2628 MatrixType Mtmp = Qmatrix.block(stitch,Nret, Nrowsvec[i],Nnull);
2629 N[svec[i]].try_push_back(A[loc][svec[i]].in[qvec[i]], A[loc][svec[i]].out[qvec[i]], Mtmp);
2630 }
2631 stitch += Nrowsvec[i];
2632 }
2633 }
2634 }
2635 }
2636}
2637
2638template<typename Symmetry, typename Scalar>
2641{
2642// #ifndef DMRG_DONT_USE_OPENMP
2643// #pragma omp parallel for
2644// #endif
2645 for (size_t qin=0; qin<inbase[loc].Nq(); ++qin)
2646 {
2647 // determine how many A's to glue together
2648 vector<size_t> svec, qvec, Ncolsvec;
2649 for (size_t s=0; s<qloc[loc].size(); ++s)
2650 for (size_t q=0; q<A[loc][s].dim; ++q)
2651 {
2652 if (A[loc][s].in[q] == inbase[loc][qin])
2653 {
2654 svec.push_back(s);
2655 qvec.push_back(q);
2656 Ncolsvec.push_back(A[loc][s].block[q].cols());
2657 }
2658 }
2659
2660 if (svec.size() > 0)
2661 {
2662 // do the glue
2663 size_t Nrows = A[loc][svec[0]].block[qvec[0]].rows();
2664 for (size_t i=1; i<svec.size(); ++i) {assert(A[loc][svec[i]].block[qvec[i]].rows() == Nrows);}
2665 size_t Ncols = accumulate(Ncolsvec.begin(), Ncolsvec.end(), 0);
2666
2667 MatrixType Aclump(Nrows,Ncols);
2668 size_t stitch = 0;
2669 for (size_t i=0; i<svec.size(); ++i)
2670 {
2671 Aclump.block(0,stitch, Nrows,Ncolsvec[i]) = A[loc][svec[i]].block[qvec[i]] *
2672 Symmetry::coeff_leftSweep(A[loc][svec[i]].out[qvec[i]],
2673 A[loc][svec[i]].in[qvec[i]]);
2674 stitch += Ncolsvec[i];
2675 }
2676
2677 HouseholderQR<MatrixType> Quirinus; MatrixType Qmatrix, Rmatrix; // Eigen QR
2678
2679 Quirinus.compute(Aclump.adjoint());
2680 Qmatrix = (Quirinus.householderQ() * MatrixType::Identity(Aclump.cols(),Aclump.rows())).adjoint();
2681 Rmatrix = (MatrixType::Identity(Aclump.rows(),Aclump.cols()) * Quirinus.matrixQR().template triangularView<Upper>()).adjoint();
2682
2683 // update A[loc]
2684 stitch = 0;
2685 for (size_t i=0; i<svec.size(); ++i)
2686 {
2687 A[loc][svec[i]].block[qvec[i]] = Qmatrix.block(0,stitch, Nrows,Ncolsvec[i])*
2688 Symmetry::coeff_leftSweep(A[loc][svec[i]].in[qvec[i]],
2689 A[loc][svec[i]].out[qvec[i]]);
2690 stitch += Ncolsvec[i];
2691 }
2692
2693 // write to C
2694 qarray2<Nq> quple = {inbase[loc][qin], inbase[loc][qin]};
2695 auto qC = C.dict.find(quple);
2696
2697 if (qC != C.dict.end())
2698 {
2699 C.block[qC->second] += Rmatrix;
2700 }
2701 else
2702 {
2703 C.push_back(quple,Rmatrix);
2704 }
2705 }
2706 }
2707
2708 this->pivot = (loc==0)? 0 : loc-1;
2709}
2710
2711template<typename Symmetry, typename Scalar>
2714{
2715// #ifndef DMRG_DONT_USE_OPENMP
2716// #pragma omp parallel for
2717// #endif
2718 for (size_t qout=0; qout<outbase[loc].Nq(); ++qout)
2719 {
2720 // determine how many A's to glue together
2721 vector<size_t> svec, qvec, Nrowsvec;
2722 for (size_t s=0; s<qloc[loc].size(); ++s)
2723 for (size_t q=0; q<A[loc][s].dim; ++q)
2724 {
2725 if (A[loc][s].out[q] == outbase[loc][qout])
2726 {
2727 svec.push_back(s);
2728 qvec.push_back(q);
2729 Nrowsvec.push_back(A[loc][s].block[q].rows());
2730 }
2731 }
2732
2733 if (svec.size() > 0)
2734 {
2735 // do the glue
2736 size_t Ncols = A[loc][svec[0]].block[qvec[0]].cols();
2737 for (size_t i=1; i<svec.size(); ++i) {assert(A[loc][svec[i]].block[qvec[i]].cols() == Ncols);}
2738 size_t Nrows = accumulate(Nrowsvec.begin(),Nrowsvec.end(),0);
2739
2740 MatrixType Aclump(Nrows,Ncols);
2741 Aclump.setZero();
2742 size_t stitch = 0;
2743 for (size_t i=0; i<svec.size(); ++i)
2744 {
2745 Aclump.block(stitch,0, Nrowsvec[i],Ncols) = A[loc][svec[i]].block[qvec[i]];
2746 stitch += Nrowsvec[i];
2747 }
2748
2749 HouseholderQR<MatrixType> Quirinus; MatrixType Qmatrix, Rmatrix; // Eigen QR
2750
2751 Quirinus.compute(Aclump);
2752 Qmatrix = Quirinus.householderQ() * MatrixType::Identity(Aclump.rows(),Aclump.cols());
2753 Rmatrix = MatrixType::Identity(Aclump.cols(),Aclump.rows()) * Quirinus.matrixQR().template triangularView<Upper>();
2754
2755 // update A[loc]
2756 stitch = 0;
2757 for (size_t i=0; i<svec.size(); ++i)
2758 {
2759 A[loc][svec[i]].block[qvec[i]] = Qmatrix.block(stitch,0, Nrowsvec[i],Ncols);
2760 stitch += Nrowsvec[i];
2761 }
2762
2763 // write to C
2764 qarray2<Nq> quple = {outbase[loc][qout], outbase[loc][qout]};
2765 auto qC = C.dict.find(quple);
2766
2767 if (qC != C.dict.end())
2768 {
2769 C.block[qC->second] += Rmatrix;
2770 }
2771 else
2772 {
2773 C.push_back(quple,Rmatrix);
2774 }
2775 }
2776 }
2777
2778 this->pivot = (loc==this->N_sites-1)? this->N_sites-1 : loc+1;
2779}
2780
2781template<typename Symmetry, typename Scalar>
2784{
2785 for (size_t qC=0; qC<C.dim; ++qC)
2786 {
2787 if (DIR == DMRG::DIRECTION::RIGHT)
2788 {
2789 for (size_t s=0; s<qloc[loc].size(); ++s)
2790 for (size_t q=0; q<A[loc][s].dim; ++q)
2791 {
2792 if (A[loc][s].in[q] == C.out[qC])
2793 {
2794 A[loc][s].block[q] = C.block[qC] * A[loc][s].block[q];
2795 }
2796 }
2797 }
2798 else
2799 {
2800 for (size_t s=0; s<qloc[loc].size(); ++s)
2801 for (size_t q=0; q<A[loc][s].dim; ++q)
2802 {
2803 if (A[loc][s].out[q] == C.in[qC])
2804 {
2805 A[loc][s].block[q] = A[loc][s].block[q] * C.block[qC];
2806 }
2807 }
2808 }
2809 }
2810}
2811
2812template<typename Symmetry, typename Scalar>
2814sweepStep2 (DMRG::DIRECTION::OPTION DIR, size_t loc, const vector<Biped<Symmetry,MatrixType> > &Apair, bool SEPARATE_SV)
2815{
2817 double entropy;
2818 map<qarray<Nq>,ArrayXd> SV;
2819
2820 Qbasis<Symmetry> qloc_l, qloc_r;
2821 qloc_l.pullData(locBasis(loc)); qloc_r.pullData(locBasis((loc+1)));
2822 auto combined_basis = qloc_l.combine(qloc_r);
2823
2824 //cout << "begin splitAA" << endl;
2825 split_AA2(DIR, combined_basis, Apair, qloc[loc], A[loc], qloc[loc+1], A[loc+1],
2826 QoutTop[loc], QoutBot[loc],
2827 Cdump, false, truncWeight(loc), entropy, SV,
2828 this->eps_truncWeight, this->min_Nsv, this->max_Nsv);
2829 //cout << "end splitAA" << endl;
2830
2831 // Warning: uses eps_svd
2832 // split_AA(DIR, Apair, qloc[loc], A[loc], qloc[loc+1], A[loc+1],
2833 // QoutTop[loc], QoutBot[loc],
2834 // Cdump, false, truncWeight(loc), entropy,
2835 // this->eps_svd, this->min_Nsv, this->max_Nsv);
2836 update_outbase(loc);
2837 update_inbase(loc+1);
2838
2839 if (DIR == DMRG::DIRECTION::RIGHT)
2840 {
2841 this->pivot = (loc==this->N_sites-1)? this->N_sites-1 : loc+1;
2842 }
2843 else
2844 {
2845 this->pivot = (loc==0)? 0 : loc;
2846 }
2847 if (DIR == DMRG::DIRECTION::RIGHT)
2848 {
2849 int bond = (loc==this->N_sites-1)? -1 : loc;
2850 if (bond != -1)
2851 {
2852 S(loc) = entropy;
2853 SVspec[loc] = SV;
2854 }
2855 }
2856 else
2857 {
2858 int bond = (loc==0)? -1 : loc;
2859 if (bond != -1)
2860 {
2861 S(loc-1) = entropy;
2862 SVspec[loc-1] = SV;
2863 }
2864 }
2865}
2866
2867// template<typename Symmetry, typename Scalar>
2868// void Mps<Symmetry,Scalar>::
2869// sweepStep2 (DMRG::DIRECTION::OPTION DIR, size_t loc, const vector<Biped<Symmetry,MatrixType> > &Apair,
2870// vector<Biped<Symmetry,MatrixType> > &Al, vector<Biped<Symmetry,MatrixType> > &Ar, Biped<Symmetry,MatrixType> &C,
2871// bool SEPARATE_SV)
2872// {
2873// vector<qarray<Symmetry::Nq> > midset = calc_qsplit(Al, qloc[loc], Ar, qloc[loc+1], QoutTop[loc], QoutBot[loc]);
2874
2875// for (size_t s=0; s<qloc[loc].size(); ++s)
2876// {
2877// Al[s].clear();
2878// }
2879// for (size_t s=0; s<qloc[loc+1].size(); ++s)
2880// {
2881// Ar[s].clear();
2882// }
2883
2884// ArrayXd truncWeightSub(midset.size()); truncWeightSub.setZero();
2885// ArrayXd entropySub(midset.size()); entropySub.setZero();
2886
2887// auto tensor_basis = Symmetry::tensorProd(qloc[loc], qloc[loc+1]);
2888
2889// #ifndef DMRG_DONT_USE_OPENMP
2890// #pragma omp parallel for
2891// #endif
2892// for (size_t qmid=0; qmid<midset.size(); ++qmid)
2893// {
2894// map<pair<size_t,qarray<Symmetry::Nq> >,vector<pair<size_t,qarray<Symmetry::Nq> > > > s13map;
2895// map<tuple<size_t,qarray<Symmetry::Nq>,size_t,qarray<Symmetry::Nq> >,vector<Scalar> > cgcmap;
2896// map<tuple<size_t,qarray<Symmetry::Nq>,size_t,qarray<Symmetry::Nq> >,vector<size_t> > q13map;
2897// map<tuple<size_t,qarray<Symmetry::Nq>,size_t,qarray<Symmetry::Nq> >,vector<size_t> > s1s3map;
2898
2899// for (size_t s1=0; s1<qloc[loc].size(); ++s1)
2900// for (size_t s3=0; s3<qloc[loc+1].size(); ++s3)
2901// {
2902// auto qmerges = Symmetry::reduceSilent(qloc[loc][s1], qloc[loc+1][s3]);
2903
2904// for (const auto &qmerge:qmerges)
2905// {
2906// auto qtensor = make_tuple(qloc[loc][s1], s1, qloc[loc+1][s3], s3, qmerge);
2907// auto s1s3 = distance(tensor_basis.begin(), find(tensor_basis.begin(), tensor_basis.end(), qtensor));
2908
2909// for (size_t q13=0; q13<Apair[s1s3].dim; ++q13)
2910// {
2911// auto qlmids = Symmetry::reduceSilent(Apair[s1s3].in[q13], qloc[loc][s1]);
2912// auto qrmids = Symmetry::reduceSilent(Apair[s1s3].out[q13], Symmetry::flip(qloc[loc+1][s3]));
2913
2914// for (const auto &qlmid:qlmids)
2915// for (const auto &qrmid:qrmids)
2916// {
2917// if (qlmid == midset[qmid] and qrmid == midset[qmid])
2918// {
2919// s13map[make_pair(s1,Apair[s1s3].in[q13])].push_back(make_pair(s3,Apair[s1s3].out[q13]));
2920
2921// Scalar factor_cgc = Symmetry::coeff_Apair(Apair[s1s3].in[q13], qloc[loc][s1], midset[qmid],
2922// qloc[loc+1][s3], Apair[s1s3].out[q13], qmerge);
2923// if (DIR==DMRG::DIRECTION::LEFT)
2924// {
2925// factor_cgc *= sqrt(Symmetry::coeff_rightOrtho(Apair[s1s3].out[q13], midset[qmid]));
2926// }
2927
2928// cgcmap[make_tuple(s1,Apair[s1s3].in[q13],s3,Apair[s1s3].out[q13])].push_back(factor_cgc);
2929// q13map[make_tuple(s1,Apair[s1s3].in[q13],s3,Apair[s1s3].out[q13])].push_back(q13);
2930// s1s3map[make_tuple(s1,Apair[s1s3].in[q13],s3,Apair[s1s3].out[q13])].push_back(s1s3);
2931// }
2932// }
2933// }
2934// }
2935// }
2936
2937// if (s13map.size() != 0)
2938// {
2939// map<pair<size_t,qarray<Symmetry::Nq> >,MatrixType> Aclumpvec;
2940// size_t istitch = 0;
2941// size_t jstitch = 0;
2942// vector<size_t> get_s3;
2943// vector<size_t> get_Ncols;
2944// vector<qarray<Symmetry::Nq> > get_qr;
2945// bool COLS_ARE_KNOWN = false;
2946
2947// for (size_t s1=0; s1<qloc[loc].size(); ++s1)
2948// {
2949// auto qls = Symmetry::reduceSilent(midset[qmid], Symmetry::flip(qloc[loc][s1]));
2950
2951// for (const auto &ql:qls)
2952// {
2953// for (size_t s3=0; s3<qloc[loc+1].size(); ++s3)
2954// {
2955// auto qrs = Symmetry::reduceSilent(midset[qmid], qloc[loc+1][s3]);
2956
2957// for (const auto &qr:qrs)
2958// {
2959// auto s3block = find(s13map[make_pair(s1,ql)].begin(), s13map[make_pair(s1,ql)].end(), make_pair(s3,qr));
2960
2961// if (s3block != s13map[make_pair(s1,ql)].end())
2962// {
2963// MatrixType Mtmp;
2964// for (size_t i=0; i<q13map[make_tuple(s1,ql,s3,qr)].size(); ++i)
2965// {
2966// size_t q13 = q13map[make_tuple(s1,ql,s3,qr)][i];
2967// size_t s1s3 = s1s3map[make_tuple(s1,ql,s3,qr)][i];
2968
2969// if (Mtmp.size() == 0)
2970// {
2971// Mtmp = cgcmap[make_tuple(s1,ql,s3,qr)][i] * Apair[s1s3].block[q13];
2972// }
2973// else if (Mtmp.size() > 0 and Apair[s1s3].block[q13].size() > 0)
2974// {
2975// Mtmp += cgcmap[make_tuple(s1,ql,s3,qr)][i] * Apair[s1s3].block[q13];
2976// }
2977// }
2978// if (Mtmp.size() == 0) {continue;}
2979
2980// addRight(Mtmp, Aclumpvec[make_pair(s1,ql)]);
2981
2982// if (COLS_ARE_KNOWN == false)
2983// {
2984// get_s3.push_back(s3);
2985// get_Ncols.push_back(Mtmp.cols());
2986// get_qr.push_back(qr);
2987// }
2988// }
2989// }
2990// }
2991// if (get_s3.size() != 0) {COLS_ARE_KNOWN = true;}
2992// }
2993// }
2994
2995// vector<size_t> get_s1;
2996// vector<size_t> get_Nrows;
2997// vector<qarray<Symmetry::Nq> > get_ql;
2998// MatrixType Aclump;
2999// for (size_t s1=0; s1<qloc[loc].size(); ++s1)
3000// {
3001// auto qls = Symmetry::reduceSilent(midset[qmid], Symmetry::flip(qloc[loc][s1]));
3002
3003// for (const auto &ql:qls)
3004// {
3005// size_t Aclump_rows_old = Aclump.rows();
3006
3007// // If cols don't match, it means that zeros were cut, restore them
3008// // (happens in MpsCompressor::polyCompress):
3009// if (Aclumpvec[make_pair(s1,ql)].cols() < Aclump.cols())
3010// {
3011// size_t dcols = Aclump.cols() - Aclumpvec[make_pair(s1,ql)].cols();
3012// Aclumpvec[make_pair(s1,ql)].conservativeResize(Aclumpvec[make_pair(s1,ql)].rows(), Aclump.cols());
3013// Aclumpvec[make_pair(s1,ql)].rightCols(dcols).setZero();
3014// }
3015// else if (Aclumpvec[make_pair(s1,ql)].cols() > Aclump.cols())
3016// {
3017// size_t dcols = Aclumpvec[make_pair(s1,ql)].cols() - Aclump.cols();
3018// Aclump.conservativeResize(Aclump.rows(), Aclump.cols()+dcols);
3019// Aclump.rightCols(dcols).setZero();
3020// }
3021
3022// addBottom(Aclumpvec[make_pair(s1,ql)], Aclump);
3023
3024// if (Aclump.rows() > Aclump_rows_old)
3025// {
3026// get_s1.push_back(s1);
3027// get_Nrows.push_back(Aclump.rows()-Aclump_rows_old);
3028// get_ql.push_back(ql);
3029// }
3030// }
3031// }
3032// if (Aclump.size() == 0)
3033// {
3034// // if (DIR == DMRG::DIRECTION::RIGHT)
3035// // {
3036// // this->pivot = (loc==this->N_sites-1)? this->N_sites-1 : loc+1;
3037// // }
3038// // else
3039// // {
3040// // this->pivot = (loc==0)? 0 : loc;
3041// // }
3042// continue;
3043// }
3044
3045// #ifdef DONT_USE_BDCSVD
3046// JacobiSVD<MatrixType> Jack; // standard SVD
3047// #else
3048// BDCSVD<MatrixType> Jack; // "Divide and conquer" SVD (only available in Eigen)
3049// #endif
3050// Jack.compute(Aclump,ComputeThinU|ComputeThinV);
3051// VectorXd SV = Jack.singularValues();
3052
3053// // retained states:
3054// size_t Nret = (SV.array().abs() > this->eps_svd).count();
3055// Nret = max(Nret, this->min_Nsv);
3056// Nret = min(Nret, this->max_Nsv);
3057// truncWeightSub(qmid) = Symmetry::degeneracy(midset[qmid]) * SV.tail(SV.rows()-Nret).cwiseAbs2().sum();
3058// size_t Nnz = (Jack.singularValues().array() > 0.).count();
3059// entropySub(qmid) = -Symmetry::degeneracy(midset[qmid]) *
3060// (SV.head(Nnz).array().square() * SV.head(Nnz).array().square().log()).sum();
3061
3062// MatrixType Aleft, Aright, Cmatrix;
3063// if (DIR == DMRG::DIRECTION::RIGHT)
3064// {
3065// Aleft = Jack.matrixU().leftCols(Nret);
3066// if (SEPARATE_SV)
3067// {
3068// Aright = Jack.matrixV().adjoint().topRows(Nret);
3069// Cmatrix = Jack.singularValues().head(Nret).asDiagonal();
3070// }
3071// else
3072// {
3073// Aright = Jack.singularValues().head(Nret).asDiagonal() * Jack.matrixV().adjoint().topRows(Nret);
3074// }
3075// // this->pivot = (loc==this->N_sites-1)? this->N_sites-1 : loc+1;
3076// }
3077// else
3078// {
3079// Aright = Jack.matrixV().adjoint().topRows(Nret);
3080// if (SEPARATE_SV)
3081// {
3082// Aleft = Jack.matrixU().leftCols(Nret);
3083// Cmatrix = Jack.singularValues().head(Nret).asDiagonal();
3084// }
3085// else
3086// {
3087// Aleft = Jack.matrixU().leftCols(Nret) * Jack.singularValues().head(Nret).asDiagonal();
3088// }
3089// // this->pivot = (loc==0)? 0 : loc;
3090// }
3091
3092// // update Al
3093// istitch = 0;
3094// for (size_t i=0; i<get_s1.size(); ++i)
3095// {
3096// size_t s1 = get_s1[i];
3097// size_t Nrows = get_Nrows[i];
3098
3099// qarray2<Nq> quple = {get_ql[i], midset[qmid]};
3100// auto q = Al[s1].dict.find(quple);
3101// if (q != Al[s1].dict.end())
3102// {
3103// Al[s1].block[q->second] += Aleft.block(istitch,0, Nrows,Nret);
3104// }
3105// else
3106// {
3107// Al[s1].push_back(get_ql[i], midset[qmid], Aleft.block(istitch,0, Nrows,Nret));
3108// }
3109// istitch += Nrows;
3110// }
3111
3112// // update Ar
3113// jstitch = 0;
3114// for (size_t i=0; i<get_s3.size(); ++i)
3115// {
3116// size_t s3 = get_s3[i];
3117// size_t Ncols = get_Ncols[i];
3118
3119// qarray2<Nq> quple = {midset[qmid], get_qr[i]};
3120// auto q = Ar[s3].dict.find(quple);
3121// Scalar factor_cgc3 = (DIR==DMRG::DIRECTION::LEFT)? sqrt(Symmetry::coeff_rightOrtho(midset[qmid], get_qr[i])):1.;
3122// if (q != Ar[s3].dict.end())
3123// {
3124// Ar[s3].block[q->second] += factor_cgc3 * Aright.block(0,jstitch, Nret,Ncols);
3125// }
3126// else
3127// {
3128// Ar[s3].push_back(midset[qmid], get_qr[i], factor_cgc3 * Aright.block(0,jstitch, Nret,Ncols));
3129// }
3130// jstitch += Ncols;
3131// }
3132
3133// if (SEPARATE_SV)
3134// {
3135// qarray2<Nq> quple = {midset[qmid], midset[qmid]};
3136// auto q = C.dict.find(quple);
3137// if (q != C.dict.end())
3138// {
3139// C.block[q->second] += Cmatrix;
3140// }
3141// else
3142// {
3143// C.push_back(midset[qmid], midset[qmid], Cmatrix);
3144// }
3145// }
3146// }
3147// }
3148
3149// // remove unwanted zero-sized blocks
3150// for (size_t s=0; s<qloc[loc].size(); ++s)
3151// {
3152// Al[s] = Al[s].cleaned();
3153// }
3154// for (size_t s=0; s<qloc[loc+1].size(); ++s)
3155// {
3156// Ar[s] = Ar[s].cleaned();
3157// }
3158
3159// truncWeight(loc) = truncWeightSub.sum();
3160
3161// if (DIR == DMRG::DIRECTION::RIGHT)
3162// {
3163// int bond = (loc==this->N_sites-1)? -1 : loc;
3164// if (bond != -1)
3165// {
3166// S(loc) = entropySub.sum();
3167// }
3168// }
3169// else
3170// {
3171// int bond = (loc==0)? -1 : loc;
3172// if (bond != -1)
3173// {
3174// S(loc-1) = entropySub.sum();
3175// }
3176// }
3177// }
3178
3179template<typename Symmetry, typename Scalar>
3182{
3183 if (this->alpha_rsvd > mynumeric_limits<Scalar>::epsilon())
3184 {
3185 std::vector<Biped<Symmetry,MatrixType> > P(qloc[loc].size());
3186
3187// Qbasis<Symmetry> QbasisW;
3188// QbasisW.pullData(H->W,0);
3189// auto QbasisP = inbase[loc].combine(QbasisW);
3190//
3191// // create tensor P
3192// #ifndef DMRG_DONT_USE_OPENMP
3193// #pragma omp parallel for
3194// #endif
3195// for (size_t s1=0; s1<qloc[loc].size(); ++s1)
3196// for (size_t s2=0; s2<qloc[loc].size(); ++s2)
3197// for (size_t k=0; k<H->qOp.size(); ++k)
3198// {
3199// if (H->W[s1][s2][k].size() == 0) {continue;}
3200// for (size_t qR=0; qR<H->R.size(); ++qR)
3201// {
3202// auto qAs = Symmetry::reduceSilent(H->R.in(qR),Symmetry::flip(qloc[loc][s2]));
3203// for (const auto& qA : qAs)
3204// {
3205// qarray2<Symmetry::Nq> quple1 = {qA, H->R.in(qR)};
3206// auto itA = A[loc][s2].dict.find(quple1);
3207//
3208// if (itA != A[loc][s2].dict.end())
3209// {
3210// auto qWs = Symmetry::reduceSilent(H->R.mid(qR), Symmetry::flip(H->qOp[k]));
3211//
3212// for (const auto& qW : qWs)
3213// {
3214// auto qPs = Symmetry::reduceSilent(qA,qW);
3215//
3216// for (const auto& qP : qPs)
3217// {
3218// if (qP > QinTop[loc] or qP < QinBot[loc]) {continue;}
3219//
3220// Scalar factor_cgc = Symmetry::coeff_HPsi(A[loc][s2].in[itA->second], qloc[loc][s2], A[loc][s2].out[itA->second],
3221// qW, H->qOp[k], H->R.mid(qR),
3222// qP, qloc[loc][s1], H->R.out(qR));
3223//
3224// if (std::abs(factor_cgc) < std::abs(mynumeric_limits<Scalar>::epsilon())) {continue;}
3225//
3226// auto dict_entry = H->W[s1][s2][k].dict.find({qW,H->R.mid(qR)});
3227// if(dict_entry == H->W[s1][s2][k].dict.end()) continue;
3228// for (int spInd=0; spInd<H->W[s1][s2][k].block[dict_entry->second].outerSize(); ++spInd)
3229// for (typename SparseMatrix<Scalar>::InnerIterator iW(H->W[s1][s2][k].block[dict_entry->second],spInd); iW; ++iW)
3230// {
3231// size_t a = iW.row();
3232// size_t b = iW.col();
3233// size_t Prows = QbasisP.inner_dim(qP);
3234// if(Prows==0) { continue;}
3235// size_t Pcols = H->R.block[qR][b][0].cols();
3236// if(Pcols==0) { continue;}
3237// size_t Arows = A[loc][s2].block[itA->second].rows();
3238// size_t stitch = QbasisP.leftAmount(qP,{qA,qW});
3239//
3240// MatrixType Mtmp(Prows,Pcols);
3241// Mtmp.setZero();
3242//
3243// if (stitch >= Prows) {continue;}
3244// if (H->R.block[qR][b][0].size() != 0)
3245// {
3246// Mtmp.block(stitch + a*Arows,0, Arows,Pcols) += (this->alpha_rsvd *
3247// factor_cgc *
3248// iW.value()) *
3249// A[loc][s2].block[itA->second] *
3250// H->R.block[qR][b][0];
3251// }
3252//
3253//
3254// // VectorXd norms = Mtmp.rowwise().norm();
3257// // sort(indices.begin(), indices.end(), [norms](int i, int j){return norms(i) > norms(j);});
3258//
3259// // int Nret = min(static_cast<int>(0.1*Prows),20);
3260// // Nret = max(Nret,1);
3261// // Nret = min(Mtmp.rows(), Nret);
3262// int Nret = (this->max_Nrich<0)? Mtmp.rows():
3263// min(static_cast<int>(Mtmp.rows()), this->max_Nrich);
3264//
3270// if( Nret < Mtmp.rows() ) { Mtmp = Mtmp.topRows(Nret).eval(); }
3271// if (Mtmp.size() != 0)
3272// {
3273// qarray2<Symmetry::Nq> qupleP = {qP, H->R.out(qR)};
3274// auto it = P[s1].dict.find(qupleP);
3275// if (it != P[s1].dict.end())
3276// {
3277// if (P[s1].block[it->second].rows() == 0)
3278// {
3279// P[s1].block[it->second] = Mtmp;
3280// }
3281// else
3282// {
3283// P[s1].block[it->second] += Mtmp;
3284// }
3285// }
3286// else
3287// {
3288// P[s1].push_back(qupleP, Mtmp);
3289// }
3290// }
3291// }
3292// }
3293// }
3294// }
3295// }
3296// }
3297// }
3298
3299 vector<vector<Biped<Symmetry,MatrixType> > > Pt(H->Terms.size());
3300 for (size_t t=0; t<H->Terms.size(); ++t)
3301 {
3302 Pt[t].resize(qloc[loc].size());
3303 }
3304
3305 for (size_t t=0; t<H->Terms.size(); ++t)
3306 {
3307 Qbasis<Symmetry> QbasisW;
3308 QbasisW.pullData(H->Terms[t].W,0);
3309 auto QbasisP = inbase[loc].combine(QbasisW);
3310
3311 for (size_t s1=0; s1<qloc[loc].size(); ++s1)
3312 for (size_t s2=0; s2<qloc[loc].size(); ++s2)
3313 for (size_t k=0; k<H->Terms[t].qOp.size(); ++k)
3314 {
3315 if (H->Terms[t].W[s1][s2][k].size() == 0) {continue;}
3316 for (size_t qR=0; qR<H->Terms[t].R.size(); ++qR)
3317 {
3318 auto qAs = Symmetry::reduceSilent(H->Terms[t].R.in(qR),Symmetry::flip(qloc[loc][s2]));
3319 for (const auto& qA : qAs)
3320 {
3321 qarray2<Symmetry::Nq> quple1 = {qA, H->Terms[t].R.in(qR)};
3322 auto itA = A[loc][s2].dict.find(quple1);
3323
3324 if (itA != A[loc][s2].dict.end())
3325 {
3326 auto qWs = Symmetry::reduceSilent(H->Terms[t].R.mid(qR), Symmetry::flip(H->Terms[t].qOp[k]));
3327
3328 for (const auto& qW : qWs)
3329 {
3330 auto qPs = Symmetry::reduceSilent(qA,qW);
3331
3332 for (const auto& qP : qPs)
3333 {
3334 if (qP > QinTop[loc] or qP < QinBot[loc]) {continue;}
3335
3336 Scalar factor_cgc = Symmetry::coeff_HPsi(A[loc][s2].in[itA->second], qloc[loc][s2], A[loc][s2].out[itA->second],
3337 qW, H->Terms[t].qOp[k], H->Terms[t].R.mid(qR),
3338 qP, qloc[loc][s1], H->Terms[t].R.out(qR));
3339
3340 if (std::abs(factor_cgc) < std::abs(mynumeric_limits<Scalar>::epsilon())) {continue;}
3341
3342 auto dict_entry = H->Terms[t].W[s1][s2][k].dict.find({qW,H->Terms[t].R.mid(qR)});
3343 if(dict_entry == H->Terms[t].W[s1][s2][k].dict.end()) continue;
3344 for (int spInd=0; spInd<H->Terms[t].W[s1][s2][k].block[dict_entry->second].outerSize(); ++spInd)
3345 for (typename SparseMatrix<Scalar>::InnerIterator iW(H->Terms[t].W[s1][s2][k].block[dict_entry->second],spInd); iW; ++iW)
3346 {
3347 size_t a = iW.row();
3348 size_t b = iW.col();
3349 size_t Prows = QbasisP.inner_dim(qP);
3350 if(Prows==0) { continue;}
3351 size_t Pcols = H->Terms[t].R.block[qR][b][0].cols();
3352 if(Pcols==0) { continue;}
3353 size_t Arows = A[loc][s2].block[itA->second].rows();
3354 size_t stitch = QbasisP.leftAmount(qP,{qA,qW});
3355
3356 MatrixType Mtmp(Prows,Pcols);
3357 Mtmp.setZero();
3358
3359 if (stitch >= Prows) {continue;}
3360 if (H->Terms[t].R.block[qR][b][0].size() != 0)
3361 {
3362 Mtmp.block(stitch + a*Arows,0, Arows,Pcols) += (this->alpha_rsvd *
3363 factor_cgc *
3364 iW.value()) *
3365 A[loc][s2].block[itA->second] *
3366 H->Terms[t].R.block[qR][b][0];
3367 }
3368
3369 int Nret = (this->max_Nrich<0)? Mtmp.rows():
3370 min(static_cast<int>(Mtmp.rows()), this->max_Nrich);
3371
3372 if( Nret < Mtmp.rows() ) { Mtmp = Mtmp.topRows(Nret).eval(); }
3373 if (Mtmp.size() != 0)
3374 {
3375 qarray2<Symmetry::Nq> qupleP = {qP, H->Terms[t].R.out(qR)};
3376 auto it = Pt[t][s1].dict.find(qupleP);
3377 if (it != Pt[t][s1].dict.end())
3378 {
3379 if (Pt[t][s1].block[it->second].rows() == 0)
3380 {
3381 Pt[t][s1].block[it->second] = Mtmp;
3382 }
3383 else
3384 {
3385 Pt[t][s1].block[it->second] += Mtmp;
3386 }
3387 }
3388 else
3389 {
3390 Pt[t][s1].push_back(qupleP, Mtmp);
3391 }
3392 }
3393 }
3394 }
3395 }
3396 }
3397 }
3398 }
3399 }
3400 }
3401
3402 for (size_t s=0; s<qloc[loc].size(); ++s)
3403 {
3404 P[s] = Pt[0][s];
3405 }
3406
3407 for (size_t t=1; t<H->Terms.size(); ++t)
3408 for (size_t s=0; s<qloc[loc].size(); ++s)
3409 {
3410 P[s].addScale_extend(1.,Pt[t][s]);
3411 }
3412
3413 if (H->Terms.size() > 0) for (size_t s=0; s<qloc[loc].size(); ++s) P[s] = P[s].cleaned();
3414
3415 // extend the A matrices
3416 for (size_t s=0; s<qloc[loc].size(); ++s)
3417 for (size_t qP=0; qP<P[s].size(); ++qP)
3418 {
3419 qarray2<Symmetry::Nq> quple = {P[s].in[qP], P[s].out[qP]};
3420 auto qA = A[loc][s].dict.find(quple);
3421
3422 if (qA != A[loc][s].dict.end())
3423 {
3424 addBottom(P[s].block[qP], A[loc][s].block[qA->second]);
3425 }
3426 else
3427 {
3428 if (inbase[loc].find(P[s].in[qP]))
3429 {
3430 MatrixType Mtmp(inbase[loc].inner_dim(P[s].in[qP]), P[s].block[qP].cols());
3431 Mtmp.setZero();
3432 addBottom(P[s].block[qP], Mtmp);
3433 A[loc][s].push_back(quple, Mtmp);
3434 }
3435 else
3436 {
3437 if (loc != 0)
3438 {
3439 bool BLOCK_INSERTED_AT_LOC = false;
3440
3441 for (size_t qin=0; qin<inbase[loc-1].Nq(); ++qin)
3442 for (size_t sprev=0; sprev<qloc[loc-1].size(); ++sprev)
3443 {
3444 auto qCandidates = Symmetry::reduceSilent(inbase[loc-1][qin], qloc[loc-1][sprev]);
3445 auto it = find(qCandidates.begin(), qCandidates.end(), P[s].in[qP]);
3446
3447 if (it != qCandidates.end())
3448 {
3449 if (!BLOCK_INSERTED_AT_LOC)
3450 {
3451 A[loc][s].push_back(quple, P[s].block[qP]);
3452 BLOCK_INSERTED_AT_LOC = true;
3453 }
3454 MatrixType Mtmp(inbase[loc-1].inner_dim(inbase[loc-1][qin]), P[s].block[qP].rows());
3455 Mtmp.setZero();
3456 A[loc-1][sprev].try_push_back(inbase[loc-1][qin], P[s].in[qP], Mtmp);
3457 }
3458 }
3459 }
3460 else
3461 {
3462 if (P[s].in[qP] == Symmetry::qvacuum())
3463 {
3464 A[loc][s].push_back(quple, P[s].block[qP]);
3465 }
3466 }
3467 }
3468 }
3469 }
3470
3471 if (loc != 0)
3472 {
3473 for (size_t s=0; s<qloc[loc].size(); ++s)
3474 for (size_t qA=0; qA<A[loc][s].dim; ++qA)
3475 for (size_t sprev=0; sprev<qloc[loc-1].size(); ++sprev)
3476 for (size_t qAprev=0; qAprev<A[loc-1][sprev].size(); ++qAprev)
3477 {
3478 if (A[loc-1][sprev].out[qAprev] == A[loc][s].in[qA] and
3479 A[loc-1][sprev].block[qAprev].cols() != A[loc][s].block[qA].rows())
3480 {
3481 size_t rows = A[loc-1][sprev].block[qAprev].rows();
3482 size_t cols = A[loc-1][sprev].block[qAprev].cols();
3483 int dcols = A[loc][s].block[qA].rows()-cols;
3484
3485 A[loc-1][sprev].block[qAprev].conservativeResize(rows, cols+dcols);
3486
3487 if (dcols > 0)
3488 {
3489 A[loc-1][sprev].block[qAprev].rightCols(dcols).setZero();
3490 }
3491 }
3492 }
3493 }
3494
3495 update_inbase(loc);
3496 if (loc != 0)
3497 {
3498 update_outbase(loc-1);
3499 }
3500 }
3501}
3502
3503template<typename Symmetry, typename Scalar>
3506{
3507 if (this->alpha_rsvd > mynumeric_limits<Scalar>::epsilon())
3508 {
3509 std::vector<Biped<Symmetry,MatrixType> > P(qloc[loc].size());
3510
3511// Qbasis<Symmetry> QbasisW;
3512// QbasisW.pullData(H->W, 1);
3513// auto QbasisP = outbase[loc].combine(QbasisW);
3514//
3515// // create tensor P
3516// #ifndef DMRG_DONT_USE_OPENMP
3517// #pragma omp parallel for
3518// #endif
3519// for (size_t s1=0; s1<qloc[loc].size(); ++s1)
3520// for (size_t s2=0; s2<qloc[loc].size(); ++s2)
3521// for (size_t k=0; k<H->qOp.size(); ++k)
3522// {
3523// if (H->W[s1][s2][k].size() == 0) {continue;}
3524// for (size_t qL=0; qL<H->L.size(); ++qL)
3525// {
3526// auto qAs = Symmetry::reduceSilent(H->L.out(qL),qloc[loc][s2]);
3527// for (const auto& qA : qAs)
3528// {
3529// qarray2<Symmetry::Nq> quple1 = {H->L.out(qL), qA};
3530// auto itA = A[loc][s2].dict.find(quple1);
3531//
3532// if (itA != A[loc][s2].dict.end())
3533// {
3534// auto qWs = Symmetry::reduceSilent(H->L.mid(qL), H->qOp[k]);
3535//
3536// for (const auto& qW : qWs)
3537// {
3538// auto qPs = Symmetry::reduceSilent(qA,qW);
3539//
3540// for (const auto& qP : qPs)
3541// {
3542// if (qP > QoutTop[loc] or qP < QoutBot[loc]) {continue;}
3543//
3544// Scalar factor_cgc = Symmetry::coeff_HPsi(A[loc][s2].in[itA->second], qloc[loc][s2], A[loc][s2].out[itA->second],
3545// H->L.mid(qL), H->qOp[k], qW,
3546// H->L.in(qL), qloc[loc][s1], qP);
3547//
3548// if (std::abs(factor_cgc) < std::abs(mynumeric_limits<Scalar>::epsilon())) {continue;}
3549//
3550// auto dict_entry = H->W[s1][s2][k].dict.find({H->L.mid(qL),qW});
3551// if(dict_entry == H->W[s1][s2][k].dict.end()) continue;
3552// for (int spInd=0; spInd<H->W[s1][s2][k].block[dict_entry->second].outerSize(); ++spInd)
3553// for (typename SparseMatrix<Scalar>::InnerIterator iW(H->W[s1][s2][k].block[dict_entry->second],spInd); iW; ++iW)
3554// {
3555// size_t a = iW.row();
3556// size_t b = iW.col();
3557//
3558// size_t Prows = H->L.block[qL][a][0].rows();
3559// if(Prows==0) { continue; }
3560// size_t Pcols = QbasisP.inner_dim(qP);
3561// if(Pcols==0) { continue; }
3562// size_t Acols = A[loc][s2].block[itA->second].cols();
3563// size_t stitch = QbasisP.leftAmount(qP,{qA,qW});
3564//
3565// MatrixType Mtmp(Prows,Pcols);
3566// Mtmp.setZero();
3567//
3568// if (stitch >= Pcols) {continue;}
3569// if (H->L.block[qL][a][0].rows() != 0 and
3570// H->L.block[qL][a][0].cols() != 0)
3571// {
3572// Mtmp.block(0,stitch+b*Acols, Prows,Acols) += (this->alpha_rsvd *
3573// factor_cgc *
3574// iW.value()) *
3575// H->L.block[qL][a][0] *
3576// A[loc][s2].block[itA->second];
3577// }
3578//
3579// // VectorXd norms = Mtmp.colwise().norm();
3582// // sort(indices.begin(), indices.end(), [norms](int i, int j){return norms(i) > norms(j);});
3587// int Nret = (this->max_Nrich<0)? Mtmp.cols():
3588// min(static_cast<int>(Mtmp.cols()), this->max_Nrich);
3589//
3596// if( Nret < Mtmp.cols() ) { Mtmp = Mtmp.leftCols(Nret).eval(); }
3597//
3598// if (Mtmp.size() != 0)
3599// {
3600// qarray2<Symmetry::Nq> qupleP = {H->L.in(qL), qP};
3601// auto it = P[s1].dict.find(qupleP);
3602// if (it != P[s1].dict.end())
3603// {
3604// if (P[s1].block[it->second].rows() == 0)
3605// {
3606// P[s1].block[it->second] = Mtmp;
3607// }
3608// else
3609// {
3610// P[s1].block[it->second] += Mtmp;
3611// }
3612// }
3613// else
3614// {
3615// P[s1].push_back(qupleP, Mtmp);
3616// }
3617// }
3618// }
3619// }
3620// }
3621// }
3622// }
3623// }
3624// }
3625
3626 vector<vector<Biped<Symmetry,MatrixType> > > Pt(H->Terms.size());
3627 for (size_t t=0; t<H->Terms.size(); ++t) Pt[t].resize(qloc[loc].size());
3628
3629 #ifndef DMRG_DONT_USE_OPENMP
3630 #pragma omp parallel for
3631 #endif
3632 for (size_t t=0; t<H->Terms.size(); ++t)
3633 {
3634 Qbasis<Symmetry> QbasisW;
3635 QbasisW.pullData(H->Terms[t].W, 1);
3636 auto QbasisP = outbase[loc].combine(QbasisW);
3637
3638 for (size_t s1=0; s1<qloc[loc].size(); ++s1)
3639 for (size_t s2=0; s2<qloc[loc].size(); ++s2)
3640 for (size_t k=0; k<H->Terms[t].qOp.size(); ++k)
3641 {
3642 if (H->Terms[t].W[s1][s2][k].size() == 0) {continue;}
3643 for (size_t qL=0; qL<H->Terms[t].L.size(); ++qL)
3644 {
3645 auto qAs = Symmetry::reduceSilent(H->Terms[t].L.out(qL),qloc[loc][s2]);
3646 for (const auto& qA : qAs)
3647 {
3648 qarray2<Symmetry::Nq> quple1 = {H->Terms[t].L.out(qL), qA};
3649 auto itA = A[loc][s2].dict.find(quple1);
3650
3651 if (itA != A[loc][s2].dict.end())
3652 {
3653 auto qWs = Symmetry::reduceSilent(H->Terms[t].L.mid(qL), H->Terms[t].qOp[k]);
3654
3655 for (const auto& qW : qWs)
3656 {
3657 auto qPs = Symmetry::reduceSilent(qA,qW);
3658
3659 for (const auto& qP : qPs)
3660 {
3661 if (qP > QoutTop[loc] or qP < QoutBot[loc]) {continue;}
3662
3663 Scalar factor_cgc = Symmetry::coeff_HPsi(A[loc][s2].in[itA->second], qloc[loc][s2], A[loc][s2].out[itA->second],
3664 H->Terms[t].L.mid(qL), H->Terms[t].qOp[k], qW,
3665 H->Terms[t].L.in(qL), qloc[loc][s1], qP);
3666
3667 if (std::abs(factor_cgc) < std::abs(mynumeric_limits<Scalar>::epsilon())) {continue;}
3668
3669 auto dict_entry = H->Terms[t].W[s1][s2][k].dict.find({H->Terms[t].L.mid(qL),qW});
3670 if(dict_entry == H->Terms[t].W[s1][s2][k].dict.end()) continue;
3671 for (int spInd=0; spInd<H->Terms[t].W[s1][s2][k].block[dict_entry->second].outerSize(); ++spInd)
3672 for (typename SparseMatrix<Scalar>::InnerIterator iW(H->Terms[t].W[s1][s2][k].block[dict_entry->second],spInd); iW; ++iW)
3673 {
3674 size_t a = iW.row();
3675 size_t b = iW.col();
3676
3677 size_t Prows = H->Terms[t].L.block[qL][a][0].rows();
3678 if(Prows==0) { continue; }
3679 size_t Pcols = QbasisP.inner_dim(qP);
3680 if(Pcols==0) { continue; }
3681 size_t Acols = A[loc][s2].block[itA->second].cols();
3682 size_t stitch = QbasisP.leftAmount(qP,{qA,qW});
3683
3684 MatrixType Mtmp(Prows,Pcols);
3685 Mtmp.setZero();
3686
3687 if (stitch >= Pcols) {continue;}
3688 if (H->Terms[t].L.block[qL][a][0].rows() != 0 and
3689 H->Terms[t].L.block[qL][a][0].cols() != 0)
3690 {
3691 Mtmp.block(0,stitch+b*Acols, Prows,Acols) += (this->alpha_rsvd *
3692 factor_cgc *
3693 iW.value()) *
3694 H->Terms[t].L.block[qL][a][0] *
3695 A[loc][s2].block[itA->second];
3696 }
3697
3698 int Nret = (this->max_Nrich<0)? Mtmp.cols():
3699 min(static_cast<int>(Mtmp.cols()), this->max_Nrich);
3700
3701 if( Nret < Mtmp.cols() ) { Mtmp = Mtmp.leftCols(Nret).eval(); }
3702
3703 if (Mtmp.size() != 0)
3704 {
3705 qarray2<Symmetry::Nq> qupleP = {H->Terms[t].L.in(qL), qP};
3706 auto it = Pt[t][s1].dict.find(qupleP);
3707 if (it != Pt[t][s1].dict.end())
3708 {
3709 if (Pt[t][s1].block[it->second].rows() == 0)
3710 {
3711 Pt[t][s1].block[it->second] = Mtmp;
3712 }
3713 else
3714 {
3715 Pt[t][s1].block[it->second] += Mtmp;
3716 }
3717 }
3718 else
3719 {
3720 Pt[t][s1].push_back(qupleP, Mtmp);
3721 }
3722 }
3723 }
3724 }
3725 }
3726 }
3727 }
3728 }
3729 }
3730 }
3731
3732 for (size_t s=0; s<qloc[loc].size(); ++s)
3733 {
3734 P[s] = Pt[0][s];
3735 }
3736
3737 for (size_t t=1; t<H->Terms.size(); ++t)
3738 for (size_t s=0; s<qloc[loc].size(); ++s)
3739 {
3740 P[s].addScale_extend(1.,Pt[t][s]);
3741 }
3742
3743 if (H->Terms.size() > 0) for (size_t s=0; s<qloc[loc].size(); ++s) P[s] = P[s].cleaned();
3744
3745 // extend the A matrices
3746 for (size_t s=0; s<qloc[loc].size(); ++s)
3747 for (size_t qP=0; qP<P[s].size(); ++qP)
3748 {
3749 qarray2<Symmetry::Nq> quple = {P[s].in[qP], P[s].out[qP]};
3750 auto qA = A[loc][s].dict.find(quple);
3751
3752 if (qA != A[loc][s].dict.end())
3753 {
3754 addRight(P[s].block[qP], A[loc][s].block[qA->second]);
3755 }
3756 else
3757 {
3758 if (outbase[loc].find(P[s].out[qP]))
3759 {
3760 MatrixType Mtmp(P[s].block[qP].rows(), outbase[loc].inner_dim(P[s].out[qP]));
3761 Mtmp.setZero();
3762 addRight(P[s].block[qP], Mtmp);
3763 A[loc][s].push_back(quple, Mtmp);
3764 }
3765 else
3766 {
3767 if (loc != this->N_sites-1)
3768 {
3769 bool BLOCK_INSERTED_AT_LOC = false;
3770
3771 for (size_t qout=0; qout<outbase[loc+1].Nq(); ++qout)
3772 for (size_t snext=0; snext<qloc[loc+1].size(); ++snext)
3773 {
3774 auto qCandidates = Symmetry::reduceSilent(outbase[loc+1][qout], Symmetry::flip(qloc[loc+1][snext]));
3775 auto it = find(qCandidates.begin(), qCandidates.end(), P[s].out[qP]);
3776
3777 if (it != qCandidates.end())
3778 {
3779 if (!BLOCK_INSERTED_AT_LOC)
3780 {
3781 A[loc][s].push_back(quple, P[s].block[qP]);
3782 BLOCK_INSERTED_AT_LOC = true;
3783 }
3784 MatrixType Mtmp(P[s].block[qP].cols(), outbase[loc+1].inner_dim(outbase[loc+1][qout]));
3785 Mtmp.setZero();
3786 A[loc+1][snext].try_push_back(P[s].out[qP], outbase[loc+1][qout], Mtmp);
3787 }
3788 }
3789 }
3790 else
3791 {
3792 if (P[s].out[qP] == Qtarget())
3793 {
3794 A[loc][s].push_back(quple, P[s].block[qP]);
3795 }
3796 }
3797 }
3798 }
3799 }
3800
3801 if (loc != this->N_sites-1)
3802 {
3803 for (size_t s=0; s<qloc[loc].size(); ++s)
3804 for (size_t qA=0; qA<A[loc][s].size(); ++qA)
3805 for (size_t snext=0; snext<qloc[loc+1].size(); ++snext)
3806 for (size_t qAnext=0; qAnext<A[loc+1][snext].size(); ++qAnext)
3807 {
3808 if (A[loc+1][snext].in[qAnext] == A[loc][s].out[qA] and
3809 A[loc+1][snext].block[qAnext].rows() != A[loc][s].block[qA].cols())
3810 {
3811 size_t rows = A[loc+1][snext].block[qAnext].rows();
3812 size_t cols = A[loc+1][snext].block[qAnext].cols();
3813 int drows = A[loc][s].block[qA].cols()-rows;
3814
3815 A[loc+1][snext].block[qAnext].conservativeResize(rows+drows, cols);
3816 if (drows > 0)
3817 {
3818 A[loc+1][snext].block[qAnext].bottomRows(drows).setZero();
3819 }
3820 }
3821 }
3822 }
3823
3824 update_outbase(loc);
3825 if (loc != this->N_sites-1)
3826 {
3827 update_inbase(loc+1);
3828 }
3829 }
3830}
3831
3832template<typename Symmetry, typename Scalar>
3834dot (const Mps<Symmetry,Scalar> &Vket) const
3835{
3836 if (Qtot != Vket.Qtarget())
3837 {
3838 lout << "calculating <φ|ψ> with different quantum numbers, " << "bra: " << Qtot << ", ket:" << Vket.Qtarget() << endl;
3839 return 0.;
3840 }
3841
3843 L.setIdentity(inBasis(0), inBasis(0));
3845
3846 for (size_t l=0; l<this->N_sites; ++l)
3847 {
3848 contract_L(L, A[l], Vket.A_at(l), qloc[l], Lnext);
3849 L.clear();
3850 L = Lnext;
3851 Lnext.clear();
3852 }
3853
3854 Lnext.setIdentity(outBasis(this->N_sites-1), outBasis(this->N_sites-1));
3855
3856 return L.contract(Lnext).trace();
3857}
3858
3859template<typename Symmetry, typename Scalar>
3860template<typename MpoScalar>
3862locAvg (const Mpo<Symmetry,MpoScalar> &O, size_t distance) const
3863{
3864// cout << O.info() << endl;
3865 assert(this->pivot != -1 and "This function can only compute averages for Mps in mixed canonical form. Use avg() instead.");
3866 //assert(O.Qtarget() == Symmetry::qvacuum() and "This function can only calculate averages with local singlet operators. Use avg() instead.");
3867
3868 size_t loc1 = this->pivot;
3869 size_t loc2 = this->pivot+distance;
3870
3871 //assert(O.locality() >= loc1 and O.locality() <= loc2);
3872/* lout << "loc1=" << loc1 << ", loc2=" << loc2 << endl;*/
3873/* lout << O.Qtarget() << endl;*/
3874
3877 L.setIdentity(1,1,inBasis(loc1));
3878
3879 for (size_t l=loc1; l<loc1+distance+1; ++l)
3880 {
3881 contract_L(L, A[l], O.W_at(l), A[l], O.locBasis(l), O.opBasis(l), Lnext);
3882 L = Lnext;
3883 Lnext.clear();
3884 }
3885
3887 R.setIdentity(1,1,outBasis(loc2));
3888
3889 return contract_LR(L,R);
3890}
3891
3892template<typename Symmetry, typename Scalar>
3894squaredNorm() const
3895{
3896 double res = 0.;
3897 // exploit canonical form:
3898 if (this->pivot != -1)
3899 {
3900 /* Biped<Symmetry,Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> > out = A[this->pivot][0].adjoint().contract(A[this->pivot][0]); */
3901 for (size_t s=0; s<qloc[this->pivot].size(); s++)
3902 for (size_t q=0; q<A[this->pivot][s].dim; ++q)
3903 {
3904 res += isReal((A[this->pivot][s].block[q].adjoint() * A[this->pivot][s].block[q]).trace()) * Symmetry::coeff_dot(A[this->pivot][s].out[q]);
3905 /* out += A[this->pivot][s].adjoint().contract(A[this->pivot][s]); */
3906 }
3907 /* res = out.trace(); */
3908 }
3909 // use dot product otherwise:
3910 else
3911 {
3912 res = isReal(dot(*this));
3913 }
3914 return res;
3915}
3916
3917template<typename Symmetry, typename Scalar>
3920{
3921 assert(Qmulti == V.Qmultitarget() and this->N_sites == V.length());
3922
3923 inbase.swap(V.inbase);
3924 outbase.swap(V.outbase);
3925
3926 QinTop.swap(V.QinTop);
3927 QinBot.swap(V.QinTop);
3928 QoutTop.swap(V.QinTop);
3929 QoutBot.swap(V.QinTop);
3930
3931 truncWeight.swap(V.truncWeight);
3932 std::swap(this->pivot, V.pivot);
3933 std::swap(this->N_sites, V.N_sites);
3934 std::swap(N_phys, V.N_phys);
3935
3936 std::swap(this->eps_svd, V.eps_svd);
3937 std::swap(this->eps_truncWeight, V.eps_truncWeight);
3938 std::swap(this->max_Nsv, V.max_Nsv);
3939 std::swap(this->min_Nsv, V.min_Nsv);
3940 std::swap(this->S, V.S);
3941
3942 for (size_t l=0; l<this->N_sites; ++l)
3943 for (size_t s=0; s<qloc[l].size(); ++s)
3944 {
3945 A[l][s].in.swap(V.A[l][s].in);
3946 A[l][s].out.swap(V.A[l][s].out);
3947 A[l][s].dict.swap(V.A[l][s].dict);
3948 std::swap(A[l][s].dim, V.A[l][s].dim);
3949
3950 for (size_t q=0; q<A[l][s].dim; ++q)
3951 {
3952 A[l][s].block[q].swap(V.A[l][s].block[q]);
3953 }
3954 }
3955}
3956
3957template<typename Symmetry, typename Scalar>
3960{
3961 this->eps_svd = V.eps_svd;
3962 this->eps_truncWeight = V.eps_truncWeight;
3963 this->max_Nsv = V.max_Nsv;
3964 this->min_Nsv = V.min_Nsv;
3965}
3966
3967template<typename Symmetry, typename Scalar>
3968template<typename OtherScalar>
3970operator*= (const OtherScalar &alpha)
3971{
3972 // scale the pivot site, if available; otherwise the first site
3973 int loc = (this->pivot == -1)? 0 : this->pivot;
3974 for (size_t s=0; s<qloc[loc].size(); ++s)
3975 for (size_t q=0; q<A[loc][s].dim; ++q)
3976 {
3977 A[loc][s].block[q] *= alpha;
3978 }
3979 return *this;
3980}
3981
3982template<typename Symmetry, typename Scalar>
3983template<typename OtherScalar>
3985operator/= (const OtherScalar &alpha)
3986{
3987 // scale the pivot site, if available; otherwise the first site
3988 int loc = (this->pivot == -1)? 0 : this->pivot;
3989 for (size_t s=0; s<qloc[loc].size(); ++s)
3990 for (size_t q=0; q<A[loc][s].dim; ++q)
3991 {
3992 A[loc][s].block[q] /= alpha;
3993 }
3994 return *this;
3995}
3996
3997template<typename Symmetry, typename Scalar, typename OtherScalar>
3998Mps<Symmetry,OtherScalar> operator* (const OtherScalar &alpha, const Mps<Symmetry,Scalar> &Vin)
3999{
4000 Mps<Symmetry,OtherScalar> Vout = Vin.template cast<OtherScalar>();
4001 Vout *= alpha;
4002 return Vout;
4003}
4004
4005template<typename Symmetry, typename Scalar, typename OtherScalar>
4006Mps<Symmetry,OtherScalar> operator/ (const Mps<Symmetry,Scalar> &Vin, const OtherScalar &alpha)
4007{
4008 Mps<Symmetry,OtherScalar> Vout = Vin.template cast<OtherScalar>();
4009 Vout /= alpha;
4010 return Vout;
4011}
4012
4013template<typename Symmetry, typename Scalar>
4016{
4017 assert(l < this->N_sites-1 and "Can not apply a gate because l is too large.");
4018 assert(qloc[l] == gate.leftBasis().qloc() and "Mismatching basis at left site from gate.");
4019 assert(qloc[l+1] == gate.rightBasis().qloc() and "Mismatching basis at right site from gate.");
4020
4021 // cout << termcolor::red << "Interchanging sites " << l << " <==> " << l+1 << termcolor::reset << endl;
4022
4023 auto locBasis_l = gate.leftBasis();
4024 auto locBasis_r = gate.rightBasis();
4025 auto locBasis_m = gate.midBasis();
4026 auto qmid = locBasis_m.qs();
4027
4028 //Apply the gate and get the two-site Atensor Apair.
4029 vector<Biped<Symmetry,MatrixType> > Apair(locBasis_m.size());
4030 for (size_t s1=0; s1<qloc[l].size(); s1++)
4031 for (size_t s2=0; s2<qloc[l+1].size(); s2++)
4032 for (size_t k=0; k<qmid.size(); k++)
4033 for (size_t s1p=0; s1p<qloc[l].size(); s1p++)
4034 for (size_t s2p=0; s2p<qloc[l+1].size(); s2p++)
4035 {
4036 if (!Symmetry::triangle(qarray3<Symmetry::Nq>{qloc[l][s1],qloc[l+1][s2],qmid[k]})) {continue;}
4037 if (!Symmetry::triangle(qarray3<Symmetry::Nq>{qloc[l][s1p],qloc[l+1][s2p],qmid[k]})) {continue;}
4038 if (gate.data[s1][s2][s1p][s2p][k] == 0.) {continue;}
4039 for (size_t ql=0; ql<A[l][s1p].size(); ql++)
4040 {
4041 typename Symmetry::qType qm = A[l][s1p].out[ql];
4042 auto qrs = Symmetry::reduceSilent(qm,qloc[l+1][s2p]);
4043 for (const auto &qr : qrs)
4044 {
4045 auto it_qr = A[l+1][s2p].dict.find({qm,qr});
4046 if ( it_qr == A[l+1][s2p].dict.end()) {continue;}
4047 MatrixType Mtmp(A[l][s1p].block[ql].rows(),A[l+1][s2p].block[it_qr->second].cols());
4048 Scalar factor_cgc = Symmetry::coeff_twoSiteGate(A[l][s1p].in[ql], qloc[l][s1p], qm,
4049 qloc[l+1][s2p] , qr , qmid[k]);
4050 if (abs(factor_cgc) < ::mynumeric_limits<double>::epsilon()) {continue;}
4051 // cout << "l=" << l << ", s1p=" << s1p << ", ql=" << ql << ", s2p=" << s2p << "qr=" << it_qr->second << endl;
4052 // print_size(A[l][s1p].block[ql], "A[l][s1p].block[ql]");
4053 // print_size(A[l+1][s2p].block[it_qr->second], "A[l+1][s2p].block[it_qr->second]");
4054
4055 Mtmp = factor_cgc * gate.data[s1][s2][s1p][s2p][k] * A[l][s1p].block[ql] * A[l+1][s2p].block[it_qr->second];
4056 size_t s1s2 = locBasis_m.outer_num(qmid[k]) + locBasis_m.leftAmount(qmid[k],{qloc[l][s1],qloc[l+1][s2]}) + locBasis_l.inner_num(s1) + locBasis_r.inner_num(s2)*locBasis_l.inner_dim(qloc[l][s1]);
4057 auto it_pair = Apair[s1s2].dict.find({A[l][s1p].in[ql],qr});
4058 if (it_pair == Apair[s1s2].dict.end())
4059 {
4060 Apair[s1s2].push_back(A[l][s1p].in[ql],qr,Mtmp);
4061 }
4062 else
4063 {
4064 Apair[s1s2].block[it_pair->second] += Mtmp;
4065 }
4066 }
4067 }
4068 }
4069
4070 //Decompose the two-site Atensor Apair
4072 double trunc, Sdumb;
4073 map<qarray<Nq>,ArrayXd> SV_dumb;
4074 split_AA2(DIR, locBasis_m, Apair, qloc[l], A[l], qloc[l+1], A[l+1], QoutTop[l], QoutBot[l], Cdumb, false, trunc, Sdumb, SV_dumb, this->eps_truncWeight, this->min_Nsv, this->max_Nsv);
4075 truncWeight(l) = trunc;
4076 update_outbase(l);
4077 update_inbase(l+1);
4078// split_AA(DIR, Apair, qloc[l], A[l], qloc[l+1], A[l+1], QoutTop[l], QoutBot[l], this->eps_truncWeight, this->min_Nsv, this->max_Nsv);
4079}
4080
4081template<typename Symmetry, typename Scalar>
4082template<typename OtherScalar>
4084cast() const
4085{
4087 Vout.outerResize(*this);
4088
4089 for (size_t l=0; l<this->N_sites; ++l)
4090 for (size_t s=0; s<qloc[l].size(); ++s)
4091 for (size_t q=0; q<A[l][s].dim; ++q)
4092 {
4093 Vout.A[l][s].block[q] = A[l][s].block[q].template cast<OtherScalar>();
4094 }
4095
4096 Vout.eps_svd = this->eps_svd;
4097 Vout.eps_truncWeight = this->eps_truncWeight;
4098 Vout.alpha_rsvd = this->alpha_rsvd;
4099 Vout.max_Nsv = this->max_Nsv;
4100 Vout.pivot = this->pivot;
4101 Vout.truncWeight = truncWeight;
4102
4103 Vout.QinTop = QinTop;
4104 Vout.QinBot = QinBot;
4105 Vout.QoutTop = QoutTop;
4106 Vout.QoutBot = QoutBot;
4107
4108 Vout.Boundaries = Boundaries.template cast<OtherScalar>();
4109
4110 Vout.update_inbase();
4111 Vout.update_outbase();
4112
4113 return Vout;
4114}
4115
4116//template<size_t D, size_t Nq>
4117//Mps<D,Nq,MatrixXd> operator* (const double &alpha, const Mps<D,Nq,MatrixXd> &Vin)
4118//{
4119// Mps<D,Nq,MatrixXd> Vout = Vin;
4120// Vout *= alpha;
4121// return Vout;
4122//}
4123
4124template<typename Symmetry, typename Scalar>
4127{
4128 addScale(+1.,Vin);
4129 return *this;
4130}
4131
4132template<typename Symmetry, typename Scalar>
4135{
4136 addScale(-1.,Vin);
4137 return *this;
4138}
4139
4140template<typename Symmetry, typename Scalar>
4141template<typename OtherScalar>
4143add_site (size_t loc, OtherScalar alpha, const Mps<Symmetry,Scalar> &Vin)
4144{
4145// if (loc == 0)
4146// {
4147// for (size_t s=0; s<qloc[0].size(); ++s)
4148// for (size_t q=0; q<A[0][s].dim; ++q)
4149// {
4150// qarray2<Nq> quple = {A[0][s].in[q], A[0][s].out[q]};
4151// auto it = Vin.A[0][s].dict.find(quple);
4152// addRight(alpha*Vin.A[0][s].block[it->second], A[0][s].block[q]);
4153// }
4154// }
4155// else if (loc == this->N_sites-1)
4156// {
4157// for (size_t s=0; s<qloc[this->N_sites-1].size(); ++s)
4158// for (size_t q=0; q<A[this->N_sites-1][s].dim; ++q)
4159// {
4160// qarray2<Nq> quple = {A[this->N_sites-1][s].in[q], A[this->N_sites-1][s].out[q]};
4161// auto it = Vin.A[this->N_sites-1][s].dict.find(quple);
4162// addBottom(Vin.A[this->N_sites-1][s].block[it->second], A[this->N_sites-1][s].block[q]);
4163// }
4164// }
4165// else
4166// {
4167// for (size_t s=0; s<qloc[loc].size(); ++s)
4168// for (size_t q=0; q<A[loc][s].dim; ++q)
4169// {
4170// qarray2<Nq> quple = {A[loc][s].in[q], A[loc][s].out[q]};
4171// auto it = Vin.A[loc][s].dict.find(quple);
4172// addBottomRight(Vin.A[loc][s].block[it->second], A[loc][s].block[q]);
4173// }
4174// }
4175
4176 // NOTE: Does not work if blocks don't match!
4177 if (loc == 0)
4178 {
4179 for (size_t s=0; s<qloc[loc].size(); ++s)
4180 {
4181 A[loc][s].addScale(alpha, Vin.A[loc][s], RIGHT);
4182 }
4183 }
4184 else if (loc == this->N_sites-1)
4185 {
4186 for (size_t s=0; s<qloc[loc].size(); ++s)
4187 {
4188 A[loc][s].addScale(static_cast<OtherScalar>(1.), Vin.A[loc][s], BOTTOM);
4189 }
4190 }
4191 else
4192 {
4193 for (size_t s=0; s<qloc[loc].size(); ++s)
4194 {
4195 A[loc][s].addScale(static_cast<OtherScalar>(1.), Vin.A[loc][s], BOTTOM_RIGHT);
4196 }
4197 }
4198}
4199
4200template<typename Symmetry, typename Scalar>
4201template<typename OtherScalar>
4203addScale (OtherScalar alpha, const Mps<Symmetry,Scalar> &Vin, bool SVD_COMPRESS)
4204{
4205 assert(Qmulti == Vin.Qmultitarget() and
4206 "Mismatched quantum numbers in addition of Mps!");
4207 this->pivot = -1;
4208
4209 if (&Vin.A == &A) // v+=α·v; results in v*=2·α;
4210 {
4211 operator*=(2.*alpha);
4212 }
4213 else
4214 {
4215 add_site(0,alpha,Vin);
4216 add_site(1,alpha,Vin);
4217// if (SVD_COMPRESS == true)
4218// {
4219// rightSweepStep(0,DMRG::BROOM::SVD);
4220// }
4221 for (size_t l=2; l<this->N_sites; ++l)
4222 {
4223 add_site(l,alpha,Vin);
4224// if (SVD_COMPRESS == true)
4225// {
4226// rightSweepStep(l-1,DMRG::BROOM::SVD);
4227// }
4228 }
4229
4230 // mend the blocks without match
4231/* for (size_t l=1; l<this->N_sites-1; ++l)*/
4232/* for (size_t s=0; s<qloc[l].size(); ++s)*/
4233/* for (size_t q=0; q<A[l][s].dim; ++q)*/
4234/* {*/
4235/* size_t rows = A[l][s].block[q].rows();*/
4236/* size_t cols = A[l][s].block[q].cols();*/
4237/* size_t rows_old = rows;*/
4238/* size_t cols_old = cols;*/
4239/* */
4240/* for (size_t snext=0; snext<qloc[l+1].size(); ++snext)*/
4241/* for (size_t qnext=0; qnext<A[l+1][snext].dim; ++qnext)*/
4242/* {*/
4243/* if (A[l+1][snext].in[qnext] == A[l][s].out[q] and*/
4244/* A[l+1][snext].block[qnext].rows() > A[l][s].block[q].cols())*/
4245/* {*/
4246/* cols = A[l+1][snext].block[qnext].rows();*/
4247/* break;*/
4248/* }*/
4249/* }*/
4250/* */
4251/* for (size_t sprev=0; sprev<qloc[l-1].size(); ++sprev)*/
4252/* for (size_t qprev=0; qprev<A[l-1][sprev].dim; ++qprev)*/
4253/* {*/
4254/* if (A[l-1][sprev].out[qprev] == A[l][s].in[q] and*/
4255/* A[l-1][sprev].block[qprev].cols() > A[l][s].block[q].rows())*/
4256/* {*/
4257/* rows = A[l-1][sprev].block[qprev].cols();*/
4258/* break;*/
4259/* }*/
4260/* }*/
4261/* */
4262/* A[l][s].block[q].conservativeResize(rows,cols);*/
4263/* A[l][s].block[q].bottomRows(rows-rows_old).setZero();*/
4264/* A[l][s].block[q].rightCols(cols-cols_old).setZero();*/
4265/* }*/
4266 }
4267}
4268
4269template<typename Symmetry, typename Scalar>
4271set_A_from_C (size_t loc, const vector<Tripod<Symmetry,MatrixType> > &C, DMRG::BROOM::OPTION TOOL)
4272{
4273 lout << termcolor::red << "set_A_from_C is highly deprecated!" << termcolor::reset << endl;
4274 if (loc == this->N_sites-1)
4275 {
4276 for (size_t s=0; s<qloc[loc].size(); ++s)
4277 for (size_t q=0; q<C[s].dim; ++q)
4278 {
4279 qarray2<Nq> cmpA = {C[s].out(q)+C[s].mid(q)-qloc[loc][s],
4280 C[s].out(q)+C[s].mid(q)};
4281 auto qA = A[this->N_sites-1][s].dict.find(cmpA);
4282
4283 if (qA != A[this->N_sites-1][s].dict.end())
4284 {
4285 // find the non-zero matrix in C[s].block[q]
4286 size_t w=0; while (C[s].block[q][w][0].rows() == 0) {++w;}
4287 A[this->N_sites-1][s].block[qA->second] = C[s].block[q][w][0];
4288 }
4289 }
4290 }
4291 else
4292 {
4293 vector<vector<MatrixType> > Omega(qloc[loc].size());
4294 for (size_t s=0; s<qloc[loc].size(); ++s)
4295 {
4296 Omega[s].resize(C[s].dim);
4297 for (size_t q=0; q<C[s].dim; ++q)
4298 {
4299 size_t r=0; while (C[s].block[q][r][0].rows()==0 or C[s].block[q][r][0].cols()==0) {++r;}
4300 typename MatrixType::Index Crows = C[s].block[q][r][0].rows();
4301 typename MatrixType::Index Ccols = C[s].block[q][r][0].cols();
4302
4303 for (size_t w=0; w<C[s].block[q].size(); ++w)
4304 {
4305 if (C[s].block[q][w][0].rows() != 0)
4306 {
4307 addRight(C[s].block[q][w][0], Omega[s][q]);
4308 }
4309 else
4310 {
4311 MatrixType Mtmp(Crows,Ccols);
4312 Mtmp.setZero();
4313 addRight(Mtmp, Omega[s][q]);
4314 }
4315 }
4316 }
4317 }
4318
4319 ArrayXd truncWeightSub(outbase[loc].Nq());
4320 truncWeightSub.setZero();
4321
4322// #ifndef DMRG_DONT_USE_OPENMP
4323// #pragma omp parallel for
4324// #endif
4325 for (size_t qout=0; qout<outbase[loc].Nq(); ++qout)
4326 {
4327 map<tuple<size_t,size_t,size_t>,vector<size_t> > sqmap; // map s,qA,rows -> q{mid}
4328 for (size_t s=0; s<qloc[loc].size(); ++s)
4329 for (size_t q=0; q<C[s].dim; ++q)
4330 {
4331 qarray2<Nq> cmpA = {outbase[loc][qout]-qloc[loc][s], outbase[loc][qout]};
4332 auto qA = A[loc][s].dict.find(cmpA);
4333
4334 if (C[s].mid(q)+C[s].out(q) == outbase[loc][qout])
4335// if (C[s].mid(q)+C[s].out(q) == outbase[loc][qout] and qA != A[loc][s].dict.end())
4336 {
4337 tuple<size_t,size_t,size_t> key = make_tuple(s, qA->second, Omega[s][q].rows());
4338 sqmap[key].push_back(q);
4339 }
4340 }
4341
4342 vector<size_t> svec;
4343 vector<size_t> qAvec;
4344 vector<size_t> Nrowsvec;
4345 vector<vector<size_t> > qmidvec;
4346 for (auto it=sqmap.begin(); it!=sqmap.end(); ++it)
4347 {
4348 svec.push_back(get<0>(it->first));
4349 qAvec.push_back(get<1>(it->first));
4350 Nrowsvec.push_back(get<2>(it->first));
4351 qmidvec.push_back(it->second);
4352 }
4353
4354 if (Nrowsvec.size() != 0)
4355 {
4356 size_t Nrows = accumulate(Nrowsvec.begin(), Nrowsvec.end(), 0);
4357
4358 vector<vector<size_t> > Ncolsvec(qmidvec.size());
4359 for (size_t i=0; i<qmidvec.size(); ++i)
4360 {
4361 size_t s = svec[i];
4362 for (size_t j=0; j<qmidvec[i].size(); ++j)
4363 {
4364 size_t q = qmidvec[i][j];
4365 Ncolsvec[i].push_back(Omega[s][q].cols());
4366 }
4367 }
4368
4369 size_t Ncols = accumulate(Ncolsvec[0].begin(), Ncolsvec[0].end(), 0);
4370 for (size_t i=0; i<Ncolsvec.size(); ++i)
4371 {
4372 size_t Ncols_new = accumulate(Ncolsvec[i].begin(), Ncolsvec[i].end(), 0);
4373 if (Ncols_new > Ncols) {Ncols = Ncols_new;}
4374 }
4375
4376 MatrixType Cclump(Nrows,Ncols);
4377 Cclump.setZero();
4378 size_t istitch = 0;
4379 size_t jstitch = 0;
4380 for (size_t i=0; i<Nrowsvec.size(); ++i)
4381 {
4382 for (size_t j=0; j<Ncolsvec[i].size(); ++j)
4383 {
4384 Cclump.block(istitch,jstitch, Nrowsvec[i],Ncolsvec[i][j]) = Omega[svec[i]][qmidvec[i][j]];
4385 jstitch += Ncolsvec[i][j];
4386 }
4387 istitch += Nrowsvec[i];
4388 jstitch = 0;
4389 }
4390
4391// cout << Cclump.rows() << ", " << Cclump.cols() << endl;
4392// size_t Nzerocols = 0;
4393 for (size_t i=0; i<Cclump.cols(); ++i)
4394 {
4395 if (Cclump.col(i).norm() == 0 and Cclump.cols() > 1)
4396 {
4397 remove_col(i,Cclump);
4398// ++Nzerocols;
4399 }
4400 }
4401// cout << "Nzerocols=" << Nzerocols << endl;
4402// cout << Cclump.rows() << ", " << Cclump.cols() << endl;
4403
4404// for (size_t i=0; i<Nrowsvec.size(); ++i)
4405// {
4406// for (size_t j=0; j<Ncolsvec[i].size(); ++j)
4407// {
4408// cout << svec[i] << "," << qmidvec[i][j] << " ";
4409// }
4410// cout << endl;
4411// }
4412// cout << endl;
4413
4414 #ifdef DONT_USE_BDCSVD
4415 JacobiSVD<MatrixType> Jack(Cclump,ComputeThinU); // standard SVD
4416 #else
4417 BDCSVD<MatrixType> Jack(Cclump,ComputeThinU); // "Divide and conquer" SVD (only available in Eigen)
4418 #endif
4419
4420 size_t Nret;
4421 if (TOOL == DMRG::BROOM::BRUTAL_SVD)
4422 {
4423 Nret = (Jack.singularValues().array() > 0.).count();
4424 Nret = min(Nret, this->max_Nsv);
4425 }
4426 else // SVD
4427 {
4428 Nret = (Jack.singularValues().array() > this->eps_svd).count();
4429 }
4430 Nret = max(Nret,1ul);
4431 truncWeightSub(qout) = Jack.singularValues().tail(Jack.singularValues().rows()-Nret).cwiseAbs2().sum();
4432
4433 size_t stitch = 0;
4434 for (size_t i=0; i<svec.size(); ++i)
4435 {
4436 if (TOOL == DMRG::BROOM::QR)
4437 {
4438 Nret = min(A[loc][svec[i]].block[qAvec[i]].cols(), Jack.matrixU().cols());
4439 }
4440 A[loc][svec[i]].block[qAvec[i]] = Jack.matrixU().block(stitch,0, Nrowsvec[i],Nret);
4441 stitch += Nrowsvec[i];
4442 }
4443 }
4444 }
4445
4446 truncWeight(loc) = truncWeightSub.sum();
4447 }
4448}
4449
4450template<typename Symmetry, typename Scalar>
4452mend()
4453{
4454 for (size_t l=0; l<this->N_sites; ++l)
4455 for (size_t s=0; s<qloc[l].size(); ++s)
4456 for (size_t q=0; q<A[l][s].dim; ++q)
4457 {
4458 if (A[l][s].block[q].rows()==0 and A[l][s].block[q].cols()==0)
4459 {
4460 size_t rows = 1;
4461 size_t cols = 1;
4462
4463 if (l != 0)
4464 {
4465 size_t sm = 0;
4466 bool GOT_A_MATCH = false;
4467 while (GOT_A_MATCH == false and sm<qloc[l-1].size())
4468 {
4469 qarray2<Nq> cmpm = {A[l][s].in[q]-qloc[l-1][sm], A[l][s].in[q]};
4470 auto qm = A[l-1][sm].dict.find(cmpm);
4471 if (qm != A[l-1][sm].dict.end())
4472 {
4473 rows = max(static_cast<size_t>(A[l-1][sm].block[qm->second].cols()),1ul);
4474 GOT_A_MATCH = true;
4475 }
4476 else {++sm;}
4477 }
4478 }
4479
4480 if (l != this->N_sites-1)
4481 {
4482 size_t sp = 0;
4483 bool GOT_A_MATCH = false;
4484 while (GOT_A_MATCH == false and sp<qloc[l+1].size())
4485 {
4486 qarray2<Nq> cmpp = {A[l][s].out[q], A[l][s].out[q]+qloc[l+1][sp]};
4487 auto qp = A[l+1][sp].dict.find(cmpp);
4488 if (qp != A[l+1][sp].dict.end())
4489 {
4490 cols = max(static_cast<size_t>(A[l+1][sp].block[qp->second].rows()),1ul);
4491 GOT_A_MATCH = true;
4492 }
4493 else {++sp;}
4494 }
4495 }
4496
4497 A[l][s].block[q].resize(rows,cols);
4498 A[l][s].block[q].setZero();
4499 }
4500 }
4501}
4502
4503template<typename Symmetry, typename Scalar>
4505collapse()
4506{
4507// vector<qarray<Nq> > conf(this->N_sites);
4508// vector<std::array<double,D> > newAvals(this->N_sites);
4509//
4510// for (size_t l=0; l<this->N_sites; ++l)
4511// {
4512// MatrixXd BasisTrafo = randOrtho(qloc[l].size());
4513// vector<double> prob(qloc[l].size());
4514// vector<double> ranges(D+1);
4515// ranges[0] = 0.;
4516//
4517// for (size_t i=0; i<qloc[i].size(); ++i)
4518// {
4519// prob[i] = 0.;
4520//
4521// Biped<Symmetry,MatrixType> Arow = BasisTrafo(0,i) * A[l][0].adjoint();
4522// for (size_t s=1; s<qloc[i].size(); ++s)
4523// {
4524// Arow += BasisTrafo(s,i) * A[l][s].adjoint();
4525// }
4526//
4527// Biped<Symmetry,MatrixType> Acol = BasisTrafo(0,i) * A[l][0];
4528// for (size_t s=1; s<qloc[i].size(); ++s)
4529// {
4530// Acol += BasisTrafo(s,i) * A[l][s];
4531// }
4532//
4533// for (size_t q=0; q<Arow.dim; ++q)
4534// {
4535// qarray2<Nq> quple = {Arow.out[q], Arow.in[q]};
4536// auto it = Acol.dict.find(quple);
4537// if (it != Acol.dict.end())
4538// {
4539// prob[i] += (Acol.block[it->second] * Arow.block[q])(0,0);
4540// }
4541// }
4542//
4543// ranges[i+1] = ranges[i] + prob[i];
4544// }
4545// assert(fabs(ranges[D]-1.) < 1e-14 and
4546// "Probabilities in collapse don't add up to 1!");
4547//
4548// double die = UniformDist(MtEngine);
4549// size_t select;
4550// for (size_t i=1; i<D+1; ++i)
4551// {
4552// if (die>=ranges[i-1] and die<ranges[i])
4553// {
4554// select = i-1;
4555// }
4556// }
4557// conf[l] = qloc[select];
4558//
4559// if (l<this->N_sites-1)
4560// {
4561// for (size_t s2=0; s2<qloc[l].size(); ++s2)
4562// {
4563// Biped<Symmetry,MatrixType> Mtmp = BasisTrafo(0,select) * A[l][0] * A[l+1][s2];
4564// for (size_t s1=1; s1<qloc[l].size(); ++s1)
4565// {
4566// Mtmp += BasisTrafo(s1,select) * A[l][s1] * A[l+1][s2];
4567// }
4568// A[l+1][s2] = 1./sqrt(prob[select]) * Mtmp;
4569// }
4570// }
4571//
4572// for (size_t s1=0; s1<qloc[l].size(); ++s1)
4573// {
4574// newAvals[l][s1] = BasisTrafo(s1,select);
4575// }
4576// }
4577//
4578// setProductState(conf);
4579//
4589}
4590
4591// template<typename Symmetry, typename Scalar>
4592// template<size_t MpoNq>
4593// void Mps<Symmetry,Scalar>::
4594// setFlattenedMpo (const Mpo<MpoNq,Scalar> &Op, bool USE_SQUARE)
4595// {
4596// static_assert (Nq == 0, "A flattened Mpo must have Nq=0!");
4597
4598// this->N_sites = Op.length();
4599// Qtot = qvacuum<0>();
4600// this->set_defaultCutoffs();
4601
4602// // set local basis
4603// qloc.resize(this->N_sites);
4604// for (size_t l=0; l<this->N_sites; ++l)
4605// {
4606// size_t D = Op.locBasis(l).size();
4607// qloc[l].resize(D*D);
4608
4609// for (size_t s1=0; s1<D; ++s1)
4610// for (size_t s2=0; s2<D; ++s2)
4611// {
4612// qloc[l][s2+D*s1] = qvacuum<0>();
4613// }
4614// }
4615
4616// resize_arrays();
4617// outerResizeNoSymm();
4618// innerResize(1);
4619
4620// for (size_t l=0; l<this->N_sites; ++l)
4621// {
4622// size_t D = Op.locBasis(l).size();
4623// for (size_t s1=0; s1<D; ++s1)
4624// for (size_t s2=0; s2<D; ++s2)
4625// {
4626// size_t s = s2 + D*s1;
4627// if (USE_SQUARE)
4628// {
4629// A[l][s].block[0] = MatrixType(Op.Wsq_at(l)[s1][s2]);
4630// }
4631// else
4632// {
4633// A[l][s].block[0] = MatrixType(Op.W_at(l)[s1][s2]);
4634// }
4635// }
4636// }
4637// }
4638
4639template<typename Symmetry, typename Scalar>
4641validate (string name) const
4642{
4643 stringstream ss;
4644
4645// for (size_t s=0; s<qloc[0].size(); ++s)
4646// for (size_t q=0; q<A[0][s].dim; ++q)
4647// {
4648// if (A[0][s].block[q].rows() != 1)
4649// {
4650// ss << name << " has wrong dimensions at: l=0: rows=" << A[0][s].block[q].rows() << " != 1" << endl;
4651// }
4652// }
4653
4654 for (size_t l=0; l<this->N_sites-1; ++l)
4655 for (size_t s1=0; s1<qloc[l].size(); ++s1)
4656 for (size_t q1=0; q1<A[l][s1].dim; ++q1)
4657 for (size_t s2=0; s2<qloc[l+1].size(); ++s2)
4658 for (size_t q2=0; q2<A[l+1][s2].dim; ++q2)
4659 {
4660 if (A[l][s1].out[q1] == A[l+1][s2].in[q2])
4661 {
4662 if (A[l][s1].block[q1].cols()-A[l+1][s2].block[q2].rows() != 0)
4663 {
4664 ss << name << " has wrong dimensions at: l=" << l << "→" << l+1
4665 << ", qnum=" << A[l][s1].out[q1]
4666 << ", s1=" << Sym::format<Symmetry>(qloc[l][s1]) << ", s2=" << Sym::format<Symmetry>(qloc[l+1][s1])
4667 << ", cols=" << A[l][s1].block[q1].cols() << " → rows=" << A[l+1][s2].block[q2].rows() << endl;
4668 }
4669 if (A[l][s1].block[q1].cols() == 0 or A[l+1][s2].block[q2].rows() == 0)
4670 {
4671 ss << name << " has zero dimensions at: l=" << l << "→" << l+1
4672 << ", qnum=" << A[l][s1].out[q1]
4673 << ", s1=" << Sym::format<Symmetry>(qloc[l][s1]) << ", s2=" << Sym::format<Symmetry>(qloc[l+1][s1])
4674 << ", cols=" << A[l][s1].block[q1].cols() << " → rows=" << A[l+1][s2].block[q2].rows() << endl;
4675 }
4676 }
4677 }
4678
4679// for (size_t s=0; s<qloc[this->N_sites-1].size(); ++s)
4680// for (size_t q=0; q<A[this->N_sites-1][s].dim; ++q)
4681// {
4682// if (A[this->N_sites-1][s].block[q].cols() != 1)
4683// {
4684// ss << name << " has wrong dimensions at: l=" << this->N_sites-1 << ": cols=" << A[this->N_sites-1][s].block[q].cols() << " != 1" << endl;
4685// }
4686// }
4687
4688 if (ss.str().size() == 0)
4689 {
4690 ss << name << " looks okay!";
4691 }
4692 return ss.str();
4693}
4694
4695template<typename Symmetry, typename Scalar>
4697test_ortho (double tol) const
4698{
4699 stringstream sout;
4700 std::array<string,4> normal_token = {"A","B","M","X"};
4701 std::array<string,4> special_token = {"\e[4mA\e[0m","\e[4mB\e[0m","\e[4mM\e[0m","\e[4mX\e[0m"};
4702
4703 std::array<string,4> normal_token_for_nullspace = {"F","G","M","X"};
4704 std::array<string,4> special_token_for_nullspace = {"\e[4mF\e[0m","\e[4mG\e[0m","\e[4mM\e[0m","\e[4mX\e[0m"};
4705
4706 for (int l=0; l<this->N_sites; ++l)
4707 {
4708 // check for A
4709 Biped<Symmetry,MatrixType> Test = A[l][0].adjoint().contract(A[l][0]);
4710 for (size_t s=1; s<qloc[l].size(); ++s)
4711 {
4712 Test += A[l][s].adjoint().contract(A[l][s]);
4713 }
4714
4715 vector<bool> A_CHECK(Test.dim);
4716 vector<double> A_infnorm(Test.dim);
4717 for (size_t q=0; q<Test.dim; ++q)
4718 {
4719// if (l == 0) {cout << "A l=" << l << ", Test.block[q]=" << endl << Test.block[q] << endl << endl;}
4720// MatrixType Id = MatrixType::Identity(Test.block[q].rows(), Test.block[q].cols());
4721// if (l == 0) {Id.bottomRows(Id.rows()-1).setZero();}
4722// Test.block[q] -= Id;
4723 Test.block[q] -= MatrixType::Identity(Test.block[q].rows(), Test.block[q].cols());
4724 A_CHECK[q] = Test.block[q].template lpNorm<Infinity>()<tol ? true : false;
4725 A_infnorm[q] = Test.block[q].template lpNorm<Infinity>();
4726 }
4727
4728 // check for B
4729 Test.clear();
4730 Test = A[l][0].contract(A[l][0].adjoint(),contract::MODE::OORR);
4731 for (size_t s=1; s<qloc[l].size(); ++s)
4732 {
4733 Test = Test + A[l][s].contract(A[l][s].adjoint(),contract::MODE::OORR);
4734 }
4735
4736 vector<bool> B_CHECK(Test.dim);
4737 vector<double> B_infnorm(Test.dim);
4738 for (size_t q=0; q<Test.dim; ++q)
4739 {
4740// MatrixType Id = MatrixType::Identity(Test.block[q].rows(), Test.block[q].cols());
4741// if (l == this->N_sites-1) {Id.bottomRows(Id.rows()-1).setZero();}
4742// Test.block[q] -= Id;
4743// cout << "B l=" << l << ", Test.block[q]=" << Test.block[q] << endl << endl;
4744 Test.block[q] -= MatrixType::Identity(Test.block[q].rows(), Test.block[q].cols());
4745 B_CHECK[q] = Test.block[q].template lpNorm<Infinity>()<tol ? true : false;
4746 B_infnorm[q] = Test.block[q].template lpNorm<Infinity>();
4747 }
4748
4749 // interpret result
4750 if (all_of(A_CHECK.begin(),A_CHECK.end(),[](bool x){return x;}) and
4751 all_of(B_CHECK.begin(),B_CHECK.end(),[](bool x){return x;}))
4752 {
4753 sout << termcolor::magenta;
4754 sout << ((l==this->pivot) ? special_token[3] : normal_token[3]); // X
4755 }
4756 else if (all_of(A_CHECK.begin(),A_CHECK.end(),[](bool x){return x;}))
4757 {
4758 sout << termcolor::red;
4759 sout << ((l==this->pivot) ? special_token[0] : normal_token[0]); // A
4760 }
4761 else if (all_of(B_CHECK.begin(),B_CHECK.end(),[](bool x){return x;}))
4762 {
4763 sout << termcolor::blue;
4764 sout << ((l==this->pivot) ? special_token[1] : normal_token[1]); // B
4765 }
4766 else
4767 {
4768 sout << termcolor::green;
4769 sout << ((l==this->pivot) ? special_token[2] : normal_token[2]); // M
4770 }
4771 }
4772 sout << termcolor::reset;
4773 return sout.str();
4774}
4775
4776template<typename Symmetry, typename Scalar>
4777std::pair<vector<qarray<Symmetry::Nq> >, ArrayXd> Mps<Symmetry,Scalar>::
4778entanglementSpectrumLoc (size_t loc) const
4779{
4780 vector<pair<qarray<Nq>, double> > Svals;
4781 for (const auto &x : SVspec[loc])
4782 for (int i=0; i<x.second.size(); ++i)
4783 {
4784 Svals.push_back(std::make_pair(x.first,x.second(i)));
4785 }
4786 sort(Svals.begin(), Svals.end(), [] (const pair<qarray<Nq>, double> &p1, const pair<qarray<Nq>, double> &p2) { return p2.second < p1.second;});
4787 // reverse(Svals.begin(), Svals.end());
4788
4789 ArrayXd Sout(Svals.size());
4790 vector<qarray<Nq> > Qout(Svals.size());
4791 for (int i=0; i<Svals.size(); ++i)
4792 {
4793 Sout(i) = Svals[i].second;
4794 Qout[i] = Svals[i].first;
4795 }
4796 return std::make_pair(Qout,Sout);
4797}
4798
4799template<typename Symmetry, typename Scalar>
4801graph (string filename) const
4802{
4803 stringstream ss;
4804
4805 ss << "#!/usr/bin/dot dot -Tpdf -o " << filename << ".pdf\n\n";
4806 ss << "digraph G\n{\n";
4807 ss << "rankdir = LR;\n";
4808 ss << "labelloc=\"t\";\n";
4809 ss << "label=\"MPS: L=" << this->N_sites << ", (";
4810 for (size_t q=0; q<Nq; ++q)
4811 {
4812 ss << Symmetry::kind()[q];
4813 if (q!=Nq-1) {ss << ",";}
4814 }
4815 ss << ")=" << Sym::format<Symmetry>(Qtot) << "\";\n";
4816
4817 // vacuum node
4818 ss << "\"l=" << 0 << ", " << Sym::format<Symmetry>(Symmetry::qvacuum()) << "\"";
4819 ss << "[label=" << "\"" << Sym::format<Symmetry>(Symmetry::qvacuum()) << "\"" << "];\n";
4820
4821 // site nodes
4822 for (size_t l=0; l<this->N_sites; ++l)
4823 {
4824 ss << "subgraph" << " cluster_" << l << "\n{\n";
4825 for (size_t s=0; s<qloc[l].size(); ++s)
4826 for (size_t q=0; q<A[l][s].dim; ++q)
4827 {
4828 string qin = Sym::format<Symmetry>(A[l][s].in[q]);
4829 ss << "\"l=" << l << ", " << qin << "\"";
4830 ss << "[label=" << "\"" << qin << "\"" << "];\n";
4831 }
4832 if (l>0) {ss << "label=\"l=" << l << "\"\n";}
4833 else {ss << "label=\"vacuum\"\n";}
4834 ss << "}\n";
4835 }
4836
4837 // last node
4838 ss << "subgraph" << " cluster_" << this->N_sites << "\n{\n";
4839 ss << "\"l=" << this->N_sites << ", " << Sym::format<Symmetry>(Qtot) << "\"";
4840 ss << "[label=" << "\"" << Sym::format<Symmetry>(Qtot) << "\"" << "];\n";
4841 ss << "label=\"l=" << this->N_sites << "\"\n";
4842 ss << "}\n";
4843
4844 // edges
4845 for (size_t l=0; l<this->N_sites; ++l)
4846 {
4847 for (size_t s=0; s<qloc[l].size(); ++s)
4848 for (size_t q=0; q<A[l][s].dim; ++q)
4849 {
4850 string qin = Sym::format<Symmetry>(A[l][s].in[q]);
4851 string qout = Sym::format<Symmetry>(A[l][s].out[q]);
4852 ss << "\"l=" << l << ", " << qin << "\"";
4853 ss << "->";
4854 ss << "\"l=" << l+1 << ", " << qout << "\"";
4855 ss << " [label=\"" << A[l][s].block[q].rows() << "x" << A[l][s].block[q].cols() << "\"";
4856 ss << "];\n";
4857 }
4858 }
4859
4860 ss << "\n}";
4861
4862 ofstream f(filename+".dot");
4863 f << ss.str();
4864 f.close();
4865}
4866
4867template<typename Symmetry, typename Scalar>
4869Asizes() const
4870{
4871 stringstream ss;
4872 ss << endl << "Asizes:" << endl;
4873 for (size_t l=0; l<this->N_sites; ++l)
4874 {
4875 ss << "\tl=" << l << ": ";
4876 for (size_t s=0; s<qloc[l].size(); ++s)
4877 {
4878 ss << "s=" << s << ": ";
4879 for (size_t q=0; q<A[l][s].dim; ++q)
4880 {
4881 ss << "(" << A[l][s].block[q].rows() << "," << A[l][s].block[q].cols() << ") ";
4882 }
4883 }
4884 if (l!=this->N_sites-1) {ss << endl;}
4885 }
4886 return ss.str();
4887}
4888
4889template<typename Symmetry, typename Scalar>
4891memory (MEMUNIT memunit) const
4892{
4893 double res = 0.;
4894 for (size_t l=0; l<this->N_sites; ++l)
4895 for (size_t s=0; s<qloc[l].size(); ++s)
4896 {
4897 res += A[l][s].memory(memunit);
4898 }
4899 return res;
4900}
4901
4902template<typename Symmetry, typename Scalar>
4903ostream &operator<< (ostream& os, const Mps<Symmetry,Scalar> &V)
4904{
4905 os << setfill('-') << setw(30) << "-" << setfill(' ');
4906 os << "Mps: L=" << V.length();
4907 os << setfill('-') << setw(30) << "-" << endl << setfill(' ');
4908
4909 for (size_t l=0; l<V.length(); ++l)
4910 {
4911 for (size_t s=0; s<V.locBasis(l).size(); ++s)
4912 {
4913 os << "l=" << l << "\ts=" << Sym::format<Symmetry>(V.locBasis(l)[s]) << endl;
4914 os << V.A_at(l)[s].print(true); //V.A_at(l)[s].formatted();
4915 os << endl;
4916 }
4917 os << setfill('-') << setw(80) << "-" << setfill(' ');
4918 if (l != V.length()-1) {os << endl;}
4919 }
4920 return os;
4921}
4922
4923#endif
void addBottom(const MatrixType1 &Min, MatrixType2 &Mout)
void addRight(const MatrixType1 &Min, MatrixType2 &Mout)
void remove_col(size_t i, MatrixType &M)
@ BOTTOM_RIGHT
void split_AA2(DMRG::DIRECTION::OPTION DIR, const Qbasis< Symmetry > &locBasis, const vector< Biped< Symmetry, Matrix< Scalar, Dynamic, Dynamic > > > &Apair, const vector< qarray< Symmetry::Nq > > &qloc_l, vector< Biped< Symmetry, Matrix< Scalar, Dynamic, Dynamic > > > &Al, const vector< qarray< Symmetry::Nq > > &qloc_r, vector< Biped< Symmetry, Matrix< Scalar, Dynamic, Dynamic > > > &Ar, const qarray< Symmetry::Nq > &qtop, const qarray< Symmetry::Nq > &qbot, double eps_svd, size_t min_Nsv, size_t max_Nsv)
int posmod(int x)
Definition: DmrgExternal.h:20
Scalar dot(const Mps< Symmetry, Scalar > &Vbra, const Mps< Symmetry, Scalar > &Vket)
void addScale(const OtherScalar alpha, const Mps< Symmetry, Scalar > &Vin, Mps< Symmetry, Scalar > &Vout, DMRG::VERBOSITY::OPTION VERBOSITY=DMRG::VERBOSITY::SILENT)
size_t dim(const PivotMatrix0< Symmetry, Scalar, MpoScalar > &H)
double isReal(double x)
Definition: DmrgTypedefs.h:21
@ A
Definition: DmrgTypedefs.h:130
Mps< Symmetry, OtherScalar > operator*(const OtherScalar &alpha, const Mps< Symmetry, Scalar > &Vin)
Definition: Mps.h:3998
ostream & operator<<(ostream &os, const Mps< Symmetry, Scalar > &V)
Definition: Mps.h:4903
Mps< Symmetry, OtherScalar > operator/(const Mps< Symmetry, Scalar > &Vin, const OtherScalar &alpha)
Definition: Mps.h:4006
Base class for all the sweeping stuff. Needs to know PivotMatrixType because sweeps using DMRG::BROOM...
Definition: DmrgJanitor.h:29
double eps_truncWeight
Definition: DmrgJanitor.h:97
void sweep(size_t loc, DMRG::BROOM::OPTION TOOL, PivotMatrixType *H=NULL)
Definition: DmrgJanitor.h:198
size_t N_sites
Definition: DmrgJanitor.h:112
double eps_svd
Definition: DmrgJanitor.h:97
size_t max_Nsv
Definition: DmrgJanitor.h:98
size_t length() const
Definition: DmrgJanitor.h:92
size_t min_Nsv
Definition: DmrgJanitor.h:98
double alpha_rsvd
Definition: DmrgJanitor.h:97
const std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > & W_at(const std::size_t loc) const
Definition: MpoTerms.h:699
const std::vector< std::vector< qType > > & locBasis() const
Definition: MpoTerms.h:702
const std::vector< std::vector< qType > > & opBasis() const
Definition: MpoTerms.h:710
Definition: Mpo.h:40
Definition: Mps.h:39
friend void HxV(const Mpo< Symmetry_, S1 > &H, const Mps< Symmetry_, S2 > &Vin, Mps< Symmetry_, S2 > &Vout, DMRG::VERBOSITY::OPTION VERBOSITY)
Mps< Symmetry, OtherScalar > cast() const
void canonize(DMRG::DIRECTION::OPTION DIR=DMRG::DIRECTION::LEFT)
vector< qarray< Nq > > locBasis(size_t loc) const
Definition: Mps.h:444
void outerResize(const Mps< Symmetry, OtherMatrixType > &V)
void absorb(size_t loc, DMRG::DIRECTION::OPTION DIR, const Biped< Symmetry, MatrixType > &C)
size_t calc_fullMmax() const
void elongate_hetero(size_t Nleft=0, size_t Nright=0)
Definition: Mps.h:506
void leftSplitStep(size_t loc, Biped< Symmetry, MatrixType > &C)
void set_Qmultitarget(const vector< qarray< Nq > > &Qmulti_input)
Definition: Mps.h:206
void set_A_from_C(size_t loc, const vector< Tripod< Symmetry, MatrixType > > &C, DMRG::BROOM::OPTION TOOL=DMRG::BROOM::SVD)
void graph(string filename) const
void rightSweepStep(size_t loc, DMRG::BROOM::OPTION BROOM, PivotMatrix1< Symmetry, Scalar, Scalar > *H=NULL, bool DISCARD_V=false)
Tripod< Symmetry, Matrix< Scalar, Dynamic, Dynamic > > get_boundaryTensor(DMRG::DIRECTION::OPTION DIR, size_t usePower=1ul) const
Definition: Mps.h:488
size_t calc_Nqmax() const
Scalar dot(const Mps< Symmetry, Scalar > &Vket) const
void addScale(OtherScalar alpha, const Mps< Symmetry, Scalar > &Vin, bool SVD_COMPRESS=false)
const vector< Biped< Symmetry, MatrixType > > & A_at(size_t loc) const
Definition: Mps.h:456
Mps< Symmetry, Scalar > & operator*=(const OtherScalar &alpha)
void rightSplitStep(size_t loc, Biped< Symmetry, MatrixType > &C)
void calc_Qlimits()
void setZero()
void shift_hetero(int Nshift=0)
Definition: Mps.h:551
double calc_Nqavg() const
void transform_base(qarray< Symmetry::Nq > Qtot, int L, bool PRINT=false)
Definition: Mps.h:593
MpsBoundaries< Symmetry, Scalar > Boundaries
Definition: Mps.h:481
Mps< Symmetry, Scalar > & operator-=(const Mps< Symmetry, Scalar > &Vin)
void outerResize(size_t L_input, vector< vector< qarray< Nq > > > qloc_input, qarray< Nq > Qtot_input, int Nqmax_input=500)
void update_inbase(size_t loc)
vector< qarray< Nq > > QoutBot
Definition: Mps.h:642
friend class Mps
Definition: Mps.h:55
void innerResize(size_t Mmax)
vector< qarray< Nq > > QoutTop
Definition: Mps.h:641
void collapse()
string info() const
string validate(string name="Mps") const
void update_inbase()
Definition: Mps.h:652
void setProductState(const Hamiltonian &H, const vector< qarray< Nq > > &config)
vector< vector< qarray< Nq > > > locBasis() const
Definition: Mps.h:445
void enrich_right(size_t loc, PivotMatrix1< Symmetry, Scalar, Scalar > *H)
double squaredNorm() const
size_t Nqout(size_t l)
Definition: Mps.h:273
vector< map< qarray< Nq >, ArrayXd > > SVspec
Definition: Mps.h:632
vector< Qbasis< Symmetry > > outbase
Definition: Mps.h:636
size_t N_phys
Definition: Mps.h:612
void outerResizeAll(size_t L_input, vector< vector< qarray< Nq > > > qloc_input, qarray< Nq > Qtot_input)
friend void OxV_exact(const Mpo< Symmetry_, S1 > &H, const Mps< Symmetry_, S2 > &Vin, Mps< Symmetry_, S2 > &Vout, double tol_compr, DMRG::VERBOSITY::OPTION VERBOSITY, int max_halfsweeps, int min_halfsweeps, int Minit)
void calc_N(DMRG::DIRECTION::OPTION DIR, size_t loc, vector< Biped< Symmetry, MatrixType > > &N)
ArrayXd truncWeight
Definition: Mps.h:627
void outerResize(const Hamiltonian &H, qarray< Nq > Qtot_input, int Nqmax_input=500)
void update_outbase(size_t loc)
void mend()
vector< qarray< Nq > > QinTop
Definition: Mps.h:639
void outerResizeNoSymm()
void set_open_bc()
Definition: Mps.h:483
void leftSweepStep(size_t loc, DMRG::BROOM::OPTION BROOM, PivotMatrix1< Symmetry, Scalar, Scalar > *H=NULL, bool DISCARD_U=false)
size_t get_Min(size_t loc) const
Qbasis< Symmetry > inBasis(size_t loc) const
Definition: Mps.h:448
size_t calc_Mmax() const
friend void OxV(const Mpo< Symmetry_, S1 > &H, const Mps< Symmetry_, S2 > &Vin, Mps< Symmetry_, S2 > &Vout, DMRG::BROOM::OPTION TOOL)
vector< Qbasis< Symmetry > > inbase
Definition: Mps.h:635
string Asizes() const
void update_outbase()
Definition: Mps.h:653
Mps(size_t L_input, vector< vector< qarray< Nq > > > qloc_input, qarray< Nq > Qtot_input, size_t N_phys_input, int Nqmax_input, bool TRIVIAL_BOUNDARIES=true)
vector< qarray< Nq > > Qmulti
Definition: Mps.h:621
vector< qarray< Nq > > QinBot
Definition: Mps.h:640
qarray< Nq > Qtot
Definition: Mps.h:618
size_t calc_Dmax() const
int get_pivot() const
Definition: Mps.h:462
size_t get_Mout(size_t loc) const
void swap(Mps< Symmetry, Scalar > &V)
ArrayXd S
Definition: Mps.h:630
void resize_arrays()
static constexpr size_t Nq
Definition: Mps.h:41
void set_Qlimits_to_inf()
vector< Qbasis< Symmetry > > inBasis() const
Definition: Mps.h:449
Mps(size_t L_input, const vector< vector< Biped< Symmetry, MatrixType > > > &As, const vector< vector< qarray< Nq > > > &qloc_input, qarray< Nq > Qtot_input, size_t N_phys_input)
vector< map< qarray< Nq >, ArrayXd > > entanglementSpectrum() const
Definition: Mps.h:471
void applyGate(const TwoSiteGate< Symmetry, Scalar > &gate, size_t l, DMRG::DIRECTION::OPTION DIR)
vector< vector< qarray< Nq > > > qloc
Definition: Mps.h:615
double memory(MEMUNIT memunit=GB) const
vector< qarray< Nq > > Qmultitarget() const
Definition: Mps.h:441
void enrich_left(size_t loc, PivotMatrix1< Symmetry, Scalar, Scalar > *H)
ArrayXd get_truncWeight() const
Definition: Mps.h:465
void add_site(size_t loc, OtherScalar alpha, const Mps< Symmetry, Scalar > &Vin)
void sweepStep2(DMRG::DIRECTION::OPTION DIR, size_t loc, const vector< Biped< Symmetry, MatrixType > > &Apair, bool SEPARATE_SV=false)
Symmetry::qType qType
Definition: Mps.h:42
void setRandom()
Mps(const Hamiltonian &H, size_t Mmax, qarray< Nq > Qtot_input, int Nqmax_input)
string test_ortho(double tol=1e-8) const
Qbasis< Symmetry > outBasis(size_t loc) const
Definition: Mps.h:452
qarray< Nq > Qtarget() const
Definition: Mps.h:438
vector< Qbasis< Symmetry > > outBasis() const
Definition: Mps.h:453
void setRandom(size_t loc)
vector< Biped< Symmetry, MatrixType > > & A_at(size_t loc)
Definition: Mps.h:459
Matrix< Scalar, Dynamic, Dynamic > MatrixType
Definition: Mps.h:40
Mps< Symmetry, Scalar > & operator/=(const OtherScalar &alpha)
ArrayXd entropy() const
Definition: Mps.h:468
std::pair< vector< qarray< Symmetry::Nq > >, ArrayXd > entanglementSpectrumLoc(size_t loc) const
Mps< Symmetry, Scalar > & operator+=(const Mps< Symmetry, Scalar > &Vin)
void get_controlParams(const Mps< Symmetry, Scalar > &V)
vector< vector< Biped< Symmetry, MatrixType > > > A
Definition: Mps.h:624
Scalar locAvg(const Mpo< Symmetry, MpoScalar > &O, size_t distance=0) const
Definition: Qbasis.h:39
Qbasis< Symmetry > combine(const Qbasis< Symmetry > &other, bool FLIP=false) const
Definition: Qbasis.h:686
void pullData(const vector< Biped< Symmetry, MatrixType > > &A, const Eigen::Index &leg)
Definition: Qbasis.h:486
Qbasis< Symmetry > rightBasis() const
Definition: TwoSiteGate.h:29
Qbasis< Symmetry > midBasis() const
Definition: TwoSiteGate.h:27
Qbasis< Symmetry > leftBasis() const
Definition: TwoSiteGate.h:28
vector< vector< vector< vector< vector< Scalar > > > > > data
Definition: TwoSiteGate.h:46
void contract_L(const Tripod< Symmetry, MatrixType2 > &Lold, const vector< Biped< Symmetry, MatrixType > > &Abra, const vector< vector< vector< Biped< Symmetry, MpoMatrixType > > > > &W, const vector< Biped< Symmetry, MatrixType > > &Aket, const vector< qarray< Symmetry::Nq > > &qloc, const vector< qarray< Symmetry::Nq > > &qOp, Tripod< Symmetry, MatrixType2 > &Lnew, bool RANDOMIZE=false, tuple< CONTRACT_LR_MODE, size_t > MODE_input=make_pair(FULL, 0), const std::unordered_map< pair< qarray< Symmetry::Nq >, size_t >, size_t > &basis_order_map={})
Scalar contract_LR(const Tripod< Symmetry, Matrix< Scalar, Dynamic, Dynamic > > &L, const vector< Biped< Symmetry, Matrix< Scalar, Dynamic, Dynamic > > > &Abra, const vector< vector< vector< Biped< Symmetry, MpoMatrixType > > > > &W, const vector< Biped< Symmetry, Matrix< Scalar, Dynamic, Dynamic > > > &Aket, const Tripod< Symmetry, Matrix< Scalar, Dynamic, Dynamic > > &R, const vector< qarray< Symmetry::Nq > > &qloc, const vector< qarray< Symmetry::Nq > > &qOp)
@ OORR
Definition: Biped.h:48
std::array< qarray< Nq >, 2 > qarray2
Definition: qarray.h:51
std::array< qarray< Nq >, 3 > qarray3
Definition: qarray.h:52
Definition: Biped.h:64
std::unordered_map< std::array< qType, 2 >, std::size_t > dict
Definition: Biped.h:104
std::vector< MatrixType_ > block
Definition: Biped.h:96
std::vector< qType > in
Definition: Biped.h:87
Biped< Symmetry, MatrixType_ > contract(const Biped< Symmetry, MatrixType_ > &A, const contract::MODE MODE=contract::MODE::UNITY) const
Definition: Biped.h:976
void push_back(qType qin, qType qout, const MatrixType_ &M)
Definition: Biped.h:529
void clear()
Definition: Biped.h:325
tuple< Biped< Symmetry, MatrixType_ >, Biped< Symmetry, MatrixType_ >, Biped< Symmetry, MatrixType_ > > truncateSVD(size_t minKeep, size_t maxKeep, EpsScalar eps_svd, double &truncWeight, double &entropy, map< qarray< Symmetry::Nq >, Eigen::ArrayXd > &SVspec, bool PRESERVE_MULTIPLETS=true, bool RETURN_SPEC=true) const
Definition: Biped.h:744
std::size_t dim
Definition: Biped.h:82
std::vector< qType > out
Definition: Biped.h:90
void setIdentity(const Qbasis< Symmetry > &base1, const Qbasis< Symmetry > &base2, qType Q=Symmetry::qvacuum())
Definition: Biped.h:358
void clear()
Definition: Multipede.h:409
void setIdentity(size_t Drows, size_t Dcols, size_t amax=1, size_t bmax=1)
Definition: Multipede.h:509
vector< PivotMatrix1Terms< Symmetry, Scalar, MpoScalar > > Terms
Definition: qarray.h:26