VMPS++
Loading...
Searching...
No Matches
MpoTerms.h
Go to the documentation of this file.
1#ifndef DMRG_HAMILTONIAN_TERMS
2#define DMRG_HAMILTONIAN_TERMS
3#define EIGEN_DONT_VECTORIZE
4#ifndef DEBUG_VERBOSITY
5#define DEBUG_VERBOSITY 0
6#endif
7
8#ifndef MAX_SUMPROD_STRINGLENGTH
9#define MAX_SUMPROD_STRINGLENGTH 700
10#endif
11
13#include <vector>
14#include <string>
15#include "boost/multi_array.hpp"
17
18#include "numeric_limits.h" // from TOOLS
19#include "Stopwatch.h" // from TOOLS
21#include "symmetry/qarray.h"
22#include "tensors/Qbasis.h"
23#include "tensors/Biped.h"
24#include "MemCalc.h" // from TOOLS
25#ifdef USE_HDF5_STORAGE
26 #include <HDF5Interface.h>
27#endif
28
29namespace MPO_STATUS
30{
32}
33
34template<typename Symmetry, typename Scalar> class MpoTerms
35{
36public:
38 typedef typename Symmetry::qType qType;
39 typedef Eigen::SparseMatrix<Scalar,Eigen::ColMajor,EIGEN_DEFAULT_SPARSE_INDEX_TYPE> MatrixType;
40
41protected:
42
47 std::vector<std::map<std::array<qType, 2>,std::vector<std::vector<std::map<qType,OperatorType>>>>> O;
48
49
55 std::vector<std::map<qType, std::size_t>> auxdim;
56
61
65 qType qVac = Symmetry::qvacuum();
66
70 std::size_t pos_qTot;
71
75 std::size_t pos_qVac;
76
81
86 std::vector<std::vector<std::string>> info;
87
92 std::vector<int> hilbert_dimension;
93
98
103
107 std::string before_verb_set;
108
112 std::size_t current_power = 1;
113
117 bool GOT_QOP = false;
118
122 bool GOT_QAUX = false;
123
127 bool GOT_W = false;
128
133 std::vector<bool> GOT_QPHYS;
134
141 void increment_auxdim (const std::size_t loc, const qType &q);
142
148
154
161 void decrement_auxdim (const std::size_t loc, const qType &q);
162
168
174
184 void add (const std::size_t loc, const OperatorType &op, const qType &qIn, const qType &qOut, const std::size_t IndexIn, const std::size_t IndexOut);
185
193 std::size_t get_auxdim (const std::size_t loc, const qType &q) const;
194
200 void assert_hilbert (const std::size_t loc, const std::size_t dim);
201
207 bool eliminate_linearlyDependent_rows (const std::size_t loc, const qType &qIn, const double tolerance);
208
215 bool eliminate_linearlyDependent_cols (const std::size_t loc, const qType &qOut, const double tolerance);
216
225 std::map<qType, std::vector<std::map<qType,OperatorType>>> delete_row (const std::size_t loc, const qType &qIn, const std::size_t row_to_delete, const bool SAMESITE);
226
235 std::map<qType, std::vector<std::map<qType,OperatorType>>> delete_col (const std::size_t loc, const qType &qOut, const std::size_t col_to_delete, const bool SAMESITE);
236
245 void add_to_row (const std::size_t loc, const qType &qIn, const std::size_t row, const std::map<qType,std::vector<std::map<qType,OperatorType>>> &ops, const Scalar factor);
246
255 void add_to_col (const std::size_t loc, const qType &qOut, const std::size_t col, const std::map<qType,std::vector<std::map<qType,OperatorType>>> &ops, const Scalar factor);
256
260 void calc_qOp ();
261
265 void calc_qAux ();
266
270 void calc_W ();
271
275 inline void got_update ();
276
280 void initialize ();
281
286 void compress (const double tolerance);
287
291 void renormalize ();
292
297
302 inline std::tuple<std::size_t,std::size_t,std::size_t,std::size_t> auxdim_infos () const;
303
312 static void prod_swap_IBC (std::vector<std::map<std::array<qType,2>,std::vector<std::vector<std::map<qType,OperatorType>>>>> &O_out, std::vector<std::size_t> &row_qVac, std::vector<std::size_t> &col_qVac, std::vector<std::size_t> &row_qTot, std::vector<std::size_t> &col_qTot);
313
322 static void prod_delZeroCols_OBC (std::map<std::array<qType, 2>, std::vector<std::vector<std::map<qType,OperatorType>>>> &O_last, Qbasis<Symmetry> &qAux_last, Qbasis<Symmetry> &qAux_prev, const qType &qTot, const std::size_t col_qTot);
323
329 static std::string power_to_string (std::size_t power);
330
336 static std::pair<std::string,std::size_t> detect_and_remove_power (const std::string &name_w_power);
337
344 std::vector<qType> calc_qList (const std::vector<OperatorType> &opList);
345
347
348public:
349
354 std::vector<std::vector<qType>> qOp;
355
360 std::vector<Qbasis<Symmetry>> qAux;
361
366 std::vector<std::vector<qType>> qPhys;
367
372 std::vector<std::vector<std::vector<std::vector<Biped<Symmetry, MatrixType>>>>> W;
373
378 std::vector<std::vector<std::vector<qType>>> qOp_powers;
379
384 std::vector<std::vector<Qbasis<Symmetry>>> qAux_powers;
385
390 std::vector<std::vector<std::vector<std::vector<std::vector<Biped<Symmetry, MatrixType>>>>>> W_powers;
391
395 std::size_t N_sites;
396
400 std::size_t N_phys = 0ul;
401
403 {
404 std::vector<std::vector<std::vector<std::vector<Biped<Symmetry, MatrixType>>>>> W;
405 std::vector<Qbasis<Symmetry>> qAux;
406 bool SET = false;
407 };
408
410
419 void reconstruct (const std::vector<std::map<std::array<qType,2>, std::vector<std::vector<std::map<qType,OperatorType>>>>> &O_in, const std::vector<Qbasis<Symmetry>> &qAux_in, const std::vector<std::vector<qType>> &qPhys_in, const bool FINALIZED_IN, const BC boundary_condition_in, const qType &qTot_in = Symmetry::qvacuum());
420
421public:
422
429 MpoTerms (const std::size_t L=0, const BC boundary_condition_in=BC::OPEN, const qType &qTot_in=Symmetry::qvacuum(), const DMRG::VERBOSITY::OPTION &VERB_in = DMRG::VERBOSITY::OPTION::SILENT);
430
437 void initialize (const std::size_t L, const BC boundary_condition_in, const qType &qTot_in);
438
446 virtual void push (const std::size_t loc, const std::vector<OperatorType> &opList, const std::vector<qType> &qList, const Scalar lambda = 1.0);
447
455 void push (const std::size_t loc, const std::vector<OperatorType> &opList, const Scalar lambda = 1.0) {push(loc, opList, calc_qList(opList), lambda);}
456
460 void show () const;
461
466 void save_label (const std::size_t loc, const std::string &info_label);
467
471 void set_name (const std::string &label_in) {label = label_in;}
472
476 const std::string get_name () const {return label;}
477
481 std::vector<std::string> get_info () const;
482
488 void scale (const Scalar factor, const Scalar offset=0., const std::size_t power=0ul, const double tolerance=1.e-14);
489
493 template<typename OtherScalar> MpoTerms<Symmetry, OtherScalar> cast ();
494
500 void set_qPhys (const std::size_t loc, const std::vector<qType> &qPhys_in){assert_hilbert(loc, qPhys_in.size()); GOT_QPHYS[loc] = true; qPhys[loc] = qPhys_in;}
501
510 void finalize (const bool COMPRESS=true, const std::size_t power=1, const double tolerance=::mynumeric_limits<double>::epsilon());
511
516 void calc (const std::size_t power);
517
521 bool is_finalized () const {return (status == MPO_STATUS::FINALIZED);}
522
526 const std::vector<std::map<std::array<qType, 2>, std::vector<std::vector<std::map<qType,OperatorType>>>>> &get_O () const {return O;}
527
531 const std::vector<std::vector<std::vector<std::vector<Biped<Symmetry, MatrixType>>>>> &get_W () const {assert(GOT_W and "W has not been calculated!"); return W;}
532
536 const std::vector<Qbasis<Symmetry>> &get_qAux () const {assert(GOT_QAUX and "qAux has not been calculated!"); return qAux;}
537
541 const std::vector<std::vector<qType>> &get_qOp () const {assert(GOT_QOP and "qOp has not been calculated!"); return qOp;}
542
546 const std::vector<std::vector<qType>> &get_qPhys () const {assert(check_qPhys() and "qPhys has not been set!"); return qPhys;}
547
552 const std::vector<std::vector<std::vector<std::vector<Biped<Symmetry, MatrixType>>>>> &get_W_power (std::size_t power) const;
553
558 const std::vector<Qbasis<Symmetry>> &get_qAux_power (std::size_t power) const;
559
564 const std::vector<std::vector<qType>> &get_qOp_power (std::size_t power) const;
565
569 std::size_t get_hilbert_dimension (const std::size_t loc) const {return hilbert_dimension[loc];}
570
575
579 const qType &get_qVac () const {return qVac;}
580
584 const qType &get_qTot () const {return qTot;}
585
589 const std::size_t get_pos_qTot () const {return pos_qTot;}
590
594 bool check_qPhys () const;
595
600 bool check_power (std::size_t power) const {return (power <= current_power);}
601
605 std::size_t maxPower () const {return current_power;}
606
610 std::size_t size () const {return N_sites;}
611
615 std::string label = "MPO";
616
628 void transform_base (const qType &qShift, const bool PRINT=false, const int factor=-1, const std::size_t powre=0ul);
629
633 std::vector<std::vector<TwoSiteData<Symmetry,Scalar>>> calc_TwoSiteData () const;
634
638 std::vector<std::pair<qType,std::size_t>> base_order_IBC (const std::size_t power=1) const;
639
645 double memory (MEMUNIT memunit=kB) const;
646
653 double sparsity (const std::size_t power=1, const bool PER_MATRIX=false) const;
654
663 static MpoTerms<Symmetry,Scalar> prod (const MpoTerms<Symmetry,Scalar> &top, const MpoTerms<Symmetry,Scalar> &bottom, const qType &qTot, const double tolerance=::mynumeric_limits<double>::epsilon());
664
672 static MpoTerms<Symmetry,Scalar> sum (const MpoTerms<Symmetry,Scalar> &top, const MpoTerms<Symmetry,Scalar> &bottom, const double tolerance=::mynumeric_limits<double>::epsilon());
673
677 void set_Identity (const typename Symmetry::qType &Q=Symmetry::qvacuum());
678
682 void set_Zero ();
683
689
694
695 void save (std::string filename);
696 void load (std::string filename);
697
698
699 const std::vector<std::vector<std::vector<Biped<Symmetry, MatrixType>>>> &W_at (const std::size_t loc) const {return W[loc];}
700 const std::vector<std::vector<std::vector<std::vector<Biped<Symmetry, MatrixType>>>>> &W_full () const {return W;}
701
702 const std::vector<std::vector<qType>> &locBasis () const {return qPhys;}
703 const std::vector<qType> &locBasis (const std::size_t loc) const {return qPhys[loc];}
704
705 const std::vector<Qbasis<Symmetry>> &auxBasis () const {return qAux;}
706 const Qbasis<Symmetry> &auxBasis (const std::size_t loc) const {return qAux[loc];}
707 const Qbasis<Symmetry> &inBasis (const std::size_t loc) const {return qAux[loc];}
708 const Qbasis<Symmetry> &outBasis (const std::size_t loc) const {return qAux[loc+1];}
709
710 const std::vector<std::vector<qType>> &opBasis () const {return qOp;}
711 const std::vector<qType> &opBasis (const std::size_t loc) const {return qOp[loc];}
712
713 const qType &Qtarget () const {return qTot;}
714
715 void setLocBasis (const std::vector<std::vector<qType>> &q) {for(std::size_t loc=0; loc<q.size(); ++loc) set_qPhys(loc, q[loc]);}
716 void setLocBasis (const std::vector<qType> &q, std::size_t loc) {set_qPhys(loc, q);}
717
718 const std::vector<std::vector<std::vector<Biped<Symmetry, MatrixType>>>> &Wsq_at (const std::size_t loc) const {if(VERB != DMRG::VERBOSITY::OPTION::SILENT) lout << "Warning: method Wsq_at(loc) is deprecated" << std::endl; return W_powers[0][loc];}
719 const std::vector<qType> &opBasisSq (const std::size_t loc) const {if(VERB != DMRG::VERBOSITY::OPTION::SILENT) lout << "Warning: method opBasisSq(loc) is deprecated" << std::endl; return qOp_powers[0][loc];}
720 const std::vector<std::vector<qType>> &opBasisSq () const {if(VERB != DMRG::VERBOSITY::OPTION::SILENT) lout << "Warning: method opBasisSq() is deprecated" << std::endl; return qOp_powers[0];}
721 const bool check_SQUARE () const {if(VERB != DMRG::VERBOSITY::OPTION::SILENT) lout << "Warning: method check_SQUARE() is deprecated" << std::endl; return (current_power>=2);}
722 double sparsity (bool USE_SQUARE, bool PER_MATRIX) const {if(VERB != DMRG::VERBOSITY::OPTION::SILENT) lout << "Warning: method sparsity(bool,bool) is deprecated" << std::endl; return sparsity(2,PER_MATRIX);}
723
724
725 void setQtarget (const qType &q) {assert(false and "setQtarget should not be called after the MPO has been initialized.");}
726};
727
728template<typename Symmetry> using MpoTermsXd = MpoTerms<Symmetry,double>;
729template<typename Symmetry> using MpoTermsXcd = MpoTerms<Symmetry,std::complex<double>>;
730
731template<typename Symmetry, typename Scalar> MpoTerms<Symmetry,Scalar>::
732MpoTerms (const std::size_t L, const BC boundary_condition_in, const qType &qTot_in, const DMRG::VERBOSITY::OPTION &VERB_in)
733: N_sites(L), boundary_condition(boundary_condition_in), qTot(qTot_in), VERB(VERB_in)
734{
735 if(N_sites>0)
736 {
737 initialize();
738 }
739}
740
741template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
742initialize ()
743{
744 #if DEBUG_VERBOSITY > 0
746 {
747 lout << "Initializing an MPO with L=" << N_sites << ", Boundary condition=" << boundary_condition << " and qTot={" << Sym::format<Symmetry>(qTot) << "}" << std::endl;
748 }
749 else
750 {
751 std::stringstream ss;
752 ss << before_verb_set << "Initializing an MPO with L=" << N_sites << ", Boundary condition=" << boundary_condition << " and qTot={" << Sym::format<Symmetry>(qTot) << "}" << std::endl;
753 before_verb_set = ss.str();
754 }
755 #endif
756 assert(boundary_condition == BC::OPEN or qTot == qVac);
757 current_power = 1;
758 if(qTot == qVac)
759 {
760 pos_qVac = 0;
761 pos_qTot = 1;
762 }
763 else
764 {
765 pos_qVac = 0;
766 pos_qTot = 0;
767 }
768 hilbert_dimension.clear();
769 hilbert_dimension.resize(N_sites, 0);
770 O.clear();
771 O.resize(N_sites);
772 qAux.clear();
773 auxdim.clear();
774 auxdim.resize(N_sites+1);
775 qPhys.clear();
776 qPhys.resize(N_sites);
777 GOT_QPHYS.clear();
778 GOT_QPHYS.resize(N_sites, false);
779 info.clear();
780 info.resize(N_sites);
781
782 if(boundary_condition == BC::OPEN)
783 {
784 increment_first_auxdim_OBC(qVac);
785 increment_first_auxdim_OBC(qTot);
786 increment_last_auxdim_OBC(qVac);
787 increment_last_auxdim_OBC(qTot);
788 }
789 else
790 {
791 increment_auxdim(0,qVac);
792 increment_auxdim(0,qTot);
793 }
794 for(std::size_t loc=1; loc<N_sites; ++loc)
795 {
796 increment_auxdim(loc,qVac);
797 increment_auxdim(loc,qTot);
798 }
799}
800
801template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
802initialize (const std::size_t L, const BC boundary_condition_in, const qType &qTot_in)
803{
804 N_sites = L;
805 boundary_condition = boundary_condition_in;
806 qTot = qTot_in;
807 initialize();
808}
809
810template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
811reconstruct (const std::vector<std::map<std::array<qType,2>,std::vector<std::vector<std::map<qType,OperatorType>>>>> &O_in, const std::vector<Qbasis<Symmetry>> &qAux_in, const std::vector<std::vector<qType>> &qPhys_in, const bool FINALIZED_IN, const BC boundary_condition_in, const qType &qTot_in)
812{
813 #if DEBUG_VERBOSITY > 0
815 {
816 lout << "Reconstructing an MPO with L=" << O_in.size() << ", Boundary condition=" << boundary_condition_in << " and qTot={" << Sym::format<Symmetry>(qTot_in) << "}" << std::endl;
817 }
818 else
819 {
820 std::stringstream ss;
821 ss << before_verb_set << "Reconstructing an MPO with L=" << O_in.size() << ", Boundary condition=" << boundary_condition_in << " and qTot={" << Sym::format<Symmetry>(qTot_in) << "}" << std::endl;
822 before_verb_set = ss.str();
823 }
824 #endif
825 N_sites = O_in.size();
826 boundary_condition = boundary_condition_in;
827 qTot = qTot_in;
828 qPhys.clear();
829 qPhys = qPhys_in;
830 if(FINALIZED_IN)
831 {
832 status = MPO_STATUS::FINALIZED;
833 }
834 else
835 {
836 status = MPO_STATUS::ALTERABLE;
837 }
838
839 assert(boundary_condition == BC::OPEN or qTot == qVac);
840 if(qTot == qVac)
841 {
842 pos_qVac = 0;
843 pos_qTot = 1;
844 }
845 else
846 {
847 pos_qVac = 0;
848 pos_qTot = 0;
849 }
850
851 hilbert_dimension.clear();
852 hilbert_dimension.resize(N_sites,0);
853 auxdim.clear();
854 qAux.clear();
855 auxdim.resize(N_sites+1);
856 GOT_QPHYS.clear();
857 GOT_QPHYS.resize(N_sites,false);
858 info.clear();
859 info.resize(N_sites);
860 for(std::size_t loc=0; loc<N_sites; ++loc)
861 {
862 hilbert_dimension[loc] = qPhys[loc].size();
863 GOT_QPHYS[loc] = true;
864 }
865 for(std::size_t loc=0; loc<N_sites+1; ++loc)
866 {
867 std::vector<qType> qs = qAux_in[loc].qs();
868 auxdim[loc].clear();
869 for(const auto &q : qs)
870 {
871 std::size_t deg = qAux_in[loc].inner_dim(q);
872 auxdim[loc].insert({q,deg});
873 }
874 }
875 O.clear();
876 O = O_in;
877 calc(1);
878}
879
880template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
882{
883 #if DEBUG_VERBOSITY > 0
885 {
886 lout << before_verb_set;
887 }
888 #endif
889 VERB = VERB_in;
890}
891
892template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
893push (const std::size_t loc, const std::vector<OperatorType> &opList, const std::vector<qType> &qList, const Scalar lambda)
894{
895 assert(loc < N_sites and "Chosen lattice site out of bounds");
896 assert((loc+opList.size() <= N_sites or boundary_condition == BC::INFINITE) and "For finite lattices operators must not exceed lattice size");
897 assert(status == MPO_STATUS::ALTERABLE and "Terms have already been finalized or have been loaded");
898 std::size_t range = opList.size();
899 assert(qList.size() == range+1 and "Amount of quantum numbers does not match amount of operators!");
900 assert(qList[0] == qVac and qList[range] == qTot and "Quantum number list does not match the total MPO quantum number!");
901 if(std::abs(lambda) < ::mynumeric_limits<double>::epsilon())
902 {
903 return;
904 }
905 for(std::size_t i=0; i<range; ++i)
906 {
907 assert_hilbert((loc+i)%N_sites, opList[i].data.rows());
908 if(opList[i].data.norm() < ::mynumeric_limits<double>::epsilon())
909 {
910 return;
911 }
912 }
913 if(range == 1)
914 {
915 #if DEBUG_VERBOSITY > 0
917 {
918 lout << "Local interaction at site " << loc;
919 #ifdef OPLABELS
920 lout << ": " << lambda << " * " << opList[0].label;
921 #endif
922 lout << std::endl;
923 }
924 #endif
925 assert(opList[0].Q == qTot and "Local operator does not match the total MPO quantum number!");
926 add(loc, lambda*opList[0], qVac, qTot, pos_qVac, pos_qTot);
927 }
928 else
929 {
930 #if DEBUG_VERBOSITY > 0
932 {
933 lout << range-1 << ".-neighbour interaction between the sites " << loc << " and " << (loc+range-1)%N_sites;
934 #ifdef OPLABELS
935 lout << ": " << lambda << " * " << opList[0].label << " ";
936 for(std::size_t n=1; n<range; ++n)
937 {
938 lout << " * " << opList[n].label;
939 }
940 #endif
941 lout << std::endl;
942 }
943 #endif
944 std::size_t row = pos_qVac;
945 std::size_t col = get_auxdim(loc+1, qList[1]);
946 increment_auxdim((loc+1)%N_sites, qList[1]);
947 add(loc, lambda*opList[0], qVac, qList[1], row, col);
948 for(int i=1; i<range-1; ++i)
949 {
950 row = col;
951 col = get_auxdim(loc+1+i, qList[i+1]);
952 increment_auxdim((loc+1+i)%N_sites, qList[i+1]);
953 add((loc+i)%N_sites, opList[i], qList[i], qList[i+1], row, col);
954 }
955 row = col;
956 col = pos_qTot;
957 add((loc+range-1)%N_sites, opList[range-1], qList[range-1], qTot, row, col);
958 }
959}
960
961template<typename Symmetry, typename Scalar> std::vector<typename Symmetry::qType> MpoTerms<Symmetry,Scalar>::
962calc_qList (const std::vector<OperatorType> &opList)
963{
964 struct qBranch
965 {
966 qType current;
967 std::vector<qType> history;
968 qBranch() {}
969 qBranch(qType current_in, std::vector<qType> history_in)
970 : current{current_in}, history{history_in}{}
971 std::string info()
972 {
973 std::stringstream sout;
974 for(int i=0; i<history.size(); ++i)
975 {
976 sout << "{" << Sym::format<Symmetry>(history[i]) << "} -> ";
977 }
978 sout << "{" << Sym::format<Symmetry>(current) << "}";
979 return sout.str();
980 }
981 };
982
983 std::size_t range = opList.size();
984 std::vector<std::vector<qBranch>> Qtree(range);
985 qBranch temp{opList[0].Q, {}};
986 Qtree[0].push_back(temp);
987 for(std::size_t m=1; m<range; ++m)
988 {
989 for(int i=0; i<Qtree[m-1].size(); ++i)
990 {
991 std::vector<qType> qs = Symmetry::reduceSilent(opList[m].Q, Qtree[m-1][i].current);
992 for(int j=0; j<qs.size(); ++j)
993 {
994 qBranch temp{qs[j], Qtree[m-1][i].history};
995 temp.history.push_back(Qtree[m-1][i].current);
996 Qtree[m].push_back(temp);
997 }
998 }
999 }
1000
1001 std::vector<qType> qList(range+1);
1002 qList[0] = qVac;
1003 int count = 0;
1004 for (int i=0; i<Qtree[range-1].size(); ++i)
1005 {
1006 if (Qtree[range-1][i].current == qTot)
1007 {
1008 ++count;
1009 for (int j=0; j<range-1; ++j)
1010 {
1011 qList[j+1] = Qtree[range-1][i].history[j];
1012 }
1013 qList[range] = qTot;
1014 #if DEBUG_VERBOSITY > 1
1016 {
1017 lout << "This branch of quantum numbers leads to the total MPO quantum number: {" << Sym::format<Symmetry>(qList[0]) << "} -> ";
1018 for(int j=0; j<range-1; ++j)
1019 {
1020 lout << "{" << Sym::format<Symmetry>(qList[j+1]) << "} -> ";
1021 }
1022 lout << "{" << Sym::format<Symmetry>(qList[range]) << "}" << std::endl;
1023 }
1024 #endif
1025 }
1026 }
1027 if (count > 1) {lout << termcolor::red << count << " quantum number branches lead to the total MPO quantum number" << termcolor::reset << endl;}
1028 else if (count == 0) {lout << termcolor::red << "No quantum number branch leads to the total MPO quantum number" << termcolor::reset << endl;}
1029 assert(count == 1);
1030 return qList;
1031}
1032
1033template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1034show () const
1035{
1036 lout << "####################################################################################################" << std::endl;
1037 lout << "Name: " << label << std::endl;
1038 lout << "System with " << N_sites << " lattice sites and " << boundary_condition << " boundary condition, target quantum number {" << Sym::format<Symmetry>(qTot) << "}";
1039 switch(status)
1040 {
1042 lout << ", alterable and not finalized yet." << std::endl;
1043 break;
1045 lout << ", already finalized." << std::endl;
1046 break;
1047 default:
1048 lout << ", ill-defined state!" << std::endl;
1049 break;
1050 }
1051 lout << "Approximate memory usage: " << round(memory(kB),1) << " kB";
1052 if(GOT_W and GOT_QOP)
1053 {
1054 lout << ", sparsity: " << round(sparsity()*100,1) << "%";
1055 }
1056 lout << std::endl;
1057 auto [total_auxdim, maximum_local_auxdim, total_full_auxdim, maximum_local_full_auxdim] = auxdim_infos();
1058 lout << "Calculated bases and data:\n";
1059 if(GOT_QAUX)
1060 {
1061 lout << "• MPO auxiliar bases (Average bond dimension: " << (total_auxdim*1.0)/N_sites << " (max. " << maximum_local_auxdim << ")";
1062 if(Symmetry::NON_ABELIAN)
1063 {
1064 lout << ", average full bond dimension: " << (total_full_auxdim*1.0)/N_sites << " (max. " << maximum_local_full_auxdim << ")";
1065 }
1066 lout << ")" << std::endl;
1067 }
1068 if(check_qPhys()) lout << "• Physical bases of local Hilbert spaces" << std::endl;
1069 if(GOT_QOP) lout << "• Local operator bases" << std::endl;
1070 if(GOT_W) lout << "• W matrix" << std::endl;
1071 if(current_power > 1) lout << "• All of the previous up to " << current_power << ". power of the MPO" << std::endl;
1072 if(reversed.SET) lout << "• Reversed W matrix and auxiliar bases" << std::endl;
1073 #if DEBUG_VERBOSITY > 0
1074 for(std::size_t loc=0; loc<N_sites; ++loc)
1075 {
1076 lout << "Lattice site: " << loc << std::endl;
1077 lout << "\tPhysical basis of local Hilbert space (" << hilbert_dimension[loc] << " dim):\t";
1078 if(GOT_QPHYS[loc])
1079 {
1080 for(std::size_t n=0; n<qPhys[loc].size(); ++n)
1081 {
1082 lout << "\t{" << Sym::format<Symmetry>(qPhys[loc][n]) << "}";
1083 }
1084 }
1085 lout << "\n\tIncoming quantum numbers:\t";
1086 for(const auto &[qIn, deg] : auxdim[loc])
1087 {
1088 lout << "\t({" << Sym::format<Symmetry>(qIn) << "} [#=" << deg << "])";
1089 }
1090 lout << "\n\tOutgoing quantum numbers:\t";
1091 for(const auto &[qOut, deg] : auxdim[loc+1])
1092 {
1093 lout << "\t({" << Sym::format<Symmetry>(qOut) << "} [#=" << deg << "])";
1094 }
1095 lout << std::endl;
1096 #if DEBUG_VERBOSITY > 2
1097 lout << "\tOperators:" << std::endl;
1098 for(const auto &[qs, ops] : O[loc])
1099 {
1100 std::size_t rows = get_auxdim(loc, std::get<0>(qs));
1101 std::size_t cols = get_auxdim(loc+1, std::get<1>(qs));
1102 bool any_nonzero = false;
1103 for(std::size_t row=0; row<rows; ++row)
1104 {
1105 for(std::size_t col=0; col<cols; ++col)
1106 {
1107 if(ops[row][col].size() > 0)
1108 {
1109 if(!any_nonzero)
1110 {
1111 any_nonzero = true;
1112 lout << "\t\t{" << Sym::format<Symmetry>(std::get<0>(qs)) << "}->{" << Sym::format<Symmetry>(std::get<1>(qs)) << "}:" << std::endl;
1113 }
1114 lout << "\t\t\tPosition [" << row << "|" << col << "]:";
1115 for(const auto &[Q,op] : ops[row][col])
1116 {
1117 #ifdef OPLABELS
1118 lout << "\t" << op.label << " ({" << Sym::format<Symmetry>(Q) << "}) norm=" << op.data.norm();
1119 #else
1120 lout << "\t ({" << Sym::format<Symmetry>(Q) << "}) norm=" << op.data.norm();
1121 #endif
1122 }
1123 lout << std::endl;
1124 }
1125 }
1126 }
1127 }
1128 #endif
1129 }
1130 #endif
1131 lout << "####################################################################################################" << std::endl;
1132}
1133
1134template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1135calc (const std::size_t power)
1136{
1137 if(!GOT_QAUX)
1138 {
1139 calc_qAux();
1140 }
1141 if(!GOT_QOP)
1142 {
1143 calc_qOp();
1144 }
1145 if(!GOT_W)
1146 {
1147 calc_W();
1148 }
1149 W_powers.clear();
1150 qAux_powers.clear();
1151 qOp_powers.clear();
1152 W_powers.resize(power-1);
1153 qAux_powers.resize(power-1);
1154 qOp_powers.resize(power-1);
1155 MpoTerms<Symmetry,Scalar> current = *this;
1156 for(std::size_t n=2; n<=power; ++n)
1157 {
1158 std::vector<qType> qTots = Symmetry::reduceSilent(current.get_qTot(),qTot);
1159 assert(qTots.size() == 1 and "Target quantum number has to be unique for computing higher powers of the MPO.");
1160 current = MpoTerms<Symmetry,Scalar>::prod(current,*this,qTots[0]);
1161 W_powers[n-2] = current.get_W();
1162 qAux_powers[n-2] = current.get_qAux();
1163 qOp_powers[n-2] = current.get_qOp();
1164 #if DEBUG_VERBOSITY > 0
1166 {
1167 lout << n << ". power of the MPO:" << std::endl;
1168 current.show();
1169 }
1170 #endif
1171 }
1172 current_power = power;
1173}
1174
1175template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1176calc_W ()
1177{
1178 assert(GOT_QOP and "qOp is needed for calculation of W matrix!");
1179 W.resize(N_sites);
1180
1181 for(std::size_t loc=0; loc<N_sites; ++loc)
1182 {
1183 std::size_t hdim = hilbert_dimension[loc];
1184 std::size_t odim = qOp[loc].size();
1185 W[loc].resize(hdim);
1186 for(std::size_t m=0; m<hdim; ++m)
1187 {
1188 W[loc][m].resize(hdim);
1189 for(std::size_t n=0; n<hdim; ++n)
1190 {
1191 W[loc][m][n].resize(odim);
1192 for(std::size_t t=0; t<odim; ++t)
1193 {
1195 for(const auto &[qIn, rows] : auxdim[loc])
1196 {
1197 for(const auto &[qOut, cols] : auxdim[loc+1])
1198 {
1199 auto it = O[loc].find({qIn, qOut});
1200 assert(it != O[loc].end());
1201 bool found_match = false;
1202 MatrixType mat(rows, cols);
1203 mat.setZero();
1204 for(std::size_t row=0; row<rows; ++row)
1205 {
1206 for(std::size_t col=0; col<cols; ++col)
1207 {
1208 for(const auto &[Q,op] : (it->second)[row][col])
1209 {
1210 if(Q == qOp[loc][t])
1211 {
1212 mat.coeffRef(row, col) = op.data.coeff(m,n);
1213 if(std::abs(mat.coeffRef(row, col)) > ::mynumeric_limits<double>::epsilon())
1214 {
1215 found_match = true;
1216 }
1217 }
1218 }
1219 }
1220 }
1221 if(found_match and mat.norm() > ::mynumeric_limits<double>::epsilon())
1222 {
1223 bip.push_back(qIn, qOut, mat);
1224 }
1225 }
1226 }
1227 W[loc][m][n][t] = bip;
1228 }
1229 }
1230 }
1231 }
1232 GOT_W = true;
1233}
1234
1235template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1236calc_qOp ()
1237{
1238 qOp.resize(N_sites);
1239
1240 for(std::size_t loc=0; loc<N_sites; ++loc)
1241 {
1242 std::set<typename Symmetry::qType> qOp_set;
1243 for(const auto &[qs, ops] : O[loc])
1244 {
1245 std::size_t rows = get_auxdim(loc, std::get<0>(qs));
1246 std::size_t cols = get_auxdim(loc+1, std::get<1>(qs));
1247 for(std::size_t row=0; row<rows; ++row)
1248 {
1249 for(std::size_t col=0; col<cols; ++col)
1250 {
1251 for(const auto &[Q,op] : ops[row][col])
1252 {
1253 qOp_set.insert(Q);
1254 }
1255 }
1256 }
1257 }
1258 qOp[loc].resize(qOp_set.size());
1259 copy(qOp_set.begin(), qOp_set.end(), qOp[loc].begin());
1260 }
1261 GOT_QOP = true;
1262}
1263
1264template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1265calc_qAux ()
1266{
1267 qAux.resize(N_sites+1);
1268 for(std::size_t loc=0; loc<N_sites+1; ++loc)
1269 {
1270 qAux[loc].clear();
1271 for(const auto &[q,deg] : auxdim[loc])
1272 {
1273 qAux[loc].push_back(q,deg);
1274 }
1275 }
1276 GOT_QAUX = true;
1277
1278}
1279
1280template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1281finalize (const bool COMPRESS, const std::size_t power, const double tolerance)
1282{
1283 assert(status == MPO_STATUS::ALTERABLE);
1284 status = MPO_STATUS::FINALIZED;
1285 for(std::size_t loc=0; loc<N_sites; ++loc)
1286 {
1287 if(hilbert_dimension[loc] == 0) hilbert_dimension[loc] = 1;
1288 OperatorType Id(Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>::Identity(hilbert_dimension[loc], hilbert_dimension[loc]).sparseView(),qVac);
1289 #ifdef OPLABELS
1290 Id.label = "id";
1291 #endif
1292 add(loc, Id, qVac, qVac, pos_qVac, pos_qVac);
1293 add(loc, Id, qTot, qTot, pos_qTot, pos_qTot);
1294 }
1295 if(boundary_condition == BC::OPEN)
1296 {
1297 delete_row(0, qTot, pos_qTot,false);
1298 bool SAMESITE = false;
1299 if(N_sites == 1)
1300 {
1301 SAMESITE = true;
1302 }
1303 delete_col(N_sites-1, qVac, pos_qVac,SAMESITE);
1304
1305 decrement_first_auxdim_OBC(qTot);
1306 decrement_last_auxdim_OBC(qVac);
1307 }
1308 #ifndef OPLABELS
1309 clear_opLabels();
1310 #endif
1311 if(COMPRESS)
1312 {
1313 compress(tolerance);
1314 }
1315 calc(power);
1316}
1317
1318#ifdef USE_OLD_COMPRESSION
1319template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1320compress (const double tolerance)
1321{
1322 std::size_t lindep_checks=0;
1323 assert(status == MPO_STATUS::FINALIZED and "Terms need to be finalized before compression.");
1324 #if DEBUG_VERBOSITY > 0
1326 {
1327 lout << "Starting compression of the MPO" << std::endl;
1328 }
1329 #endif
1330 Stopwatch<> watch;
1331 auto [total_auxdim_initial, maximum_local_auxdim_initial, total_full_auxdim_initial, maximum_local_full_auxdim_initial] = auxdim_infos();
1332 std::vector<bool> updated_bond(N_sites,true);
1333 std::size_t minimum_bond = 0;
1334 if(boundary_condition == BC::OPEN)
1335 {
1336 minimum_bond = 1;
1337 updated_bond[0] = false;
1338 }
1339 auto any_update = [minimum_bond](const std::vector<bool> &bonds)->bool
1340 {
1341 for(std::size_t loc=minimum_bond; loc<bonds.size(); ++loc)
1342 {
1343 if(bonds[loc])
1344 {
1345 return true;
1346 }
1347 }
1348 return false;
1349 };
1350 std::size_t counter = 0;
1351 while(any_update(updated_bond))
1352 {
1353 bool change = false;
1354 for(std::size_t loc=minimum_bond; loc<N_sites; ++loc)
1355 {
1356 if(updated_bond[(loc+N_sites-1)%N_sites] or updated_bond[loc])
1357 {
1358 for(auto &[q,deg] : auxdim[loc])
1359 {
1360 lindep_checks++;
1361 if(eliminate_linearlyDependent_cols((loc+N_sites-1)%N_sites,q,tolerance))
1362 {
1363 counter++;
1364 updated_bond[loc] = true;
1365 change = true;
1366 #if DEBUG_VERBOSITY > 2
1368 {
1369 lout << "Current MPO:" << std::endl;
1370 show();
1371 }
1372 #endif
1373 break;
1374 }
1375 }
1376 }
1377 if(!change and (updated_bond[loc] or updated_bond[(loc+1)%N_sites]))
1378 {
1379 for(auto &[q,deg] : auxdim[loc])
1380 {
1381 lindep_checks++;
1382 if(eliminate_linearlyDependent_rows(loc,q,tolerance))
1383 {
1384 counter++;
1385 updated_bond[loc] = true;
1386 change = true;
1387 #if DEBUG_VERBOSITY > 2
1389 {
1390 lout << "Current MPO:" << std::endl;
1391 show();
1392 }
1393 #endif
1394 break;
1395 }
1396 }
1397 }
1398
1399 if(change)
1400 {
1401 break;
1402 }
1403 else if(updated_bond[loc])
1404 {
1405 #if DEBUG_VERBOSITY > 1
1407 {
1408 lout << "Bond connecting lattice sites " << (loc+N_sites-1)%N_sites << " and " << loc << ": No linear dependence detected" << std::endl;
1409 }
1410 #endif
1411 updated_bond[loc] = false;
1412 }
1413 }
1414 }
1415 auto [total_auxdim_final, maximum_local_auxdim_final, total_full_auxdim_final, maximum_local_full_auxdim_final] = auxdim_infos();
1416 int compr_rate = (int)std::round(100.-(100.*total_auxdim_final)/(1.0*total_auxdim_initial));
1417 std::stringstream ss;
1418 auto curr_prec = std::cout.precision();
1419 ss << this->get_name() << " - Compression (Old alg.) | " << watch.info("Time") << " | Steps: " << counter << " | Rate: " << compr_rate << "% (" << std::setprecision(1)
1420 << std::fixed << (total_auxdim_initial*1.0)/N_sites << "(max=" << maximum_local_auxdim_initial << ")" << " ⇒ " << (total_auxdim_final*1.0)/N_sites << "(max=" << maximum_local_auxdim_final << ")"
1421 << ") | Linear dependence checks: " << lindep_checks << std::defaultfloat << std::endl;
1422 std::cout.precision(curr_prec);
1424 {
1425 lout << ss.str();
1426 #if DEBUG_VERBOSITY > 1
1427 lout << "Compressed MPO:" << std::endl;
1428 show();
1429 #endif
1430 }
1431 else
1432 {
1433 before_verb_set += ss.str();
1434 }
1435}
1436#else
1437template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1438compress (const double tolerance)
1439{
1440 std::size_t lindep_checks = 0;
1441 assert(status == MPO_STATUS::FINALIZED and "Terms need to be finalized before compression.");
1442 #if DEBUG_VERBOSITY > 0
1444 {
1445 lout << "Starting compression of the MPO" << std::endl;
1446 }
1447 #endif
1448 Stopwatch<> watch;
1449 auto [total_auxdim_initial, maximum_local_auxdim_initial, total_full_auxdim_initial, maximum_local_full_auxdim_initial] = auxdim_infos();
1450 std::vector<std::size_t> bonds_to_check;
1451 for(std::size_t bond=1; bond<N_sites; bond+=2ul)
1452 {
1453 bonds_to_check.push_back(bond);
1454 }
1455 if(boundary_condition == BC::INFINITE and N_sites%2 == 1)
1456 {
1457 bonds_to_check.push_back(N_sites);
1458 }
1459 std::size_t counter = 0;
1460 std::size_t threads = 1;
1461 #ifdef _OPENMP
1462 threads = omp_get_max_threads();
1463 #endif
1464 while(!bonds_to_check.empty())
1465 {
1466 counter++;
1467 std::vector<std::vector<std::size_t>> next_bonds_to_check(threads);
1468 std::size_t lindep_checks_temp = 0ul;
1469 #pragma omp parallel for shared(next_bonds_to_check) reduction(+ : lindep_checks_temp)
1470 for(std::size_t i=0; i<bonds_to_check.size(); ++i)
1471 {
1472 std::size_t thread_id = 0;
1473 #ifdef _OPENMP
1474 thread_id = omp_get_thread_num();
1475 #endif
1476 std::size_t loc = bonds_to_check[i];
1477 std::vector<qType> qs;
1478 for(const auto &[q,deg] : auxdim[loc])
1479 {
1480 qs.push_back(q);
1481 }
1482 for(std::size_t j=0; j<qs.size(); ++j)
1483 {
1484 qType& q = qs[j];
1485 lindep_checks_temp++;
1486 if(eliminate_linearlyDependent_cols(loc-1,q,tolerance))
1487 {
1488 if(loc != 1ul)
1489 {
1490 next_bonds_to_check[thread_id].push_back(loc-1);
1491 }
1492 if(loc < N_sites-1)
1493 {
1494 next_bonds_to_check[thread_id].push_back(loc+1);
1495 }
1496 if(boundary_condition == BC::INFINITE and (loc <= 1ul or loc >= N_sites-1))
1497 {
1498 next_bonds_to_check[thread_id].push_back(N_sites);
1499 }
1500 lindep_checks_temp++;
1501 while(eliminate_linearlyDependent_cols(loc-1,q,tolerance)) {lindep_checks_temp++;}
1502 }
1503 #if DEBUG_VERBOSITY > 1
1504 else
1505 {
1506 lout << "O[" << loc-1 << "](...->{" << Sym::format<Symmetry>(q) << "}): No linear dependent columns detected!" << std::endl;
1507 }
1508 #endif
1509 lindep_checks_temp++;
1510 if(eliminate_linearlyDependent_rows(loc%N_sites,q,tolerance))
1511 {
1512 if(loc != 1ul)
1513 {
1514 next_bonds_to_check[thread_id].push_back(loc-1);
1515 }
1516 if(loc < N_sites-1)
1517 {
1518 next_bonds_to_check[thread_id].push_back(loc+1);
1519 }
1520 if(boundary_condition == BC::INFINITE and (loc <= 1ul or loc >= N_sites-1))
1521 {
1522 next_bonds_to_check[thread_id].push_back(N_sites);
1523 }
1524 lindep_checks_temp++;
1525 while(eliminate_linearlyDependent_rows(loc%N_sites,q,tolerance)) {lindep_checks_temp++;}
1526 }
1527 #if DEBUG_VERBOSITY > 1
1528 else
1529 {
1530 lout << "O[" << loc%N_sites << "]({" << Sym::format<Symmetry>(q) << "}->...): No linear dependent rows detected!" << std::endl;
1531 }
1532 #endif
1533 }
1534 }
1535 lindep_checks += lindep_checks_temp;
1536
1537 #if DEBUG_VERBOSITY > 2
1539 {
1540 lout << "Current MPO:" << std::endl;
1541 show();
1542 }
1543 #endif
1544
1545 std::set<std::size_t> unique_control;
1546 if(counter == 1)
1547 {
1548 for(std::size_t bond=2; bond<N_sites; bond+=2ul)
1549 {
1550 unique_control.insert(bond);
1551 }
1552 if(boundary_condition == BC::INFINITE and N_sites%2 == 0)
1553 {
1554 unique_control.insert(N_sites);
1555 }
1556 }
1557 for(std::size_t thread_id=0; thread_id<threads; ++thread_id)
1558 {
1559 for(std::size_t i=0; i<next_bonds_to_check[thread_id].size(); ++i)
1560 {
1561 unique_control.insert(next_bonds_to_check[thread_id][i] != 0 ? next_bonds_to_check[thread_id][i] : N_sites);
1562 }
1563 }
1564 bonds_to_check.resize(0);
1565 for(std::set<std::size_t>::iterator it = unique_control.begin(); it != unique_control.end(); ++it)
1566 {
1567 bonds_to_check.push_back(*it);
1568 }
1569 }
1570
1571 auto [total_auxdim_final, maximum_local_auxdim_final, total_full_auxdim_final, maximum_local_full_auxdim_final] = auxdim_infos();
1572 int compr_rate = (int)std::round(100.-(100.*total_auxdim_final)/(1.0*total_auxdim_initial));
1573 std::stringstream ss;
1574 auto curr_prec = std::cout.precision();
1575 ss << this->get_name() << " - Compression (New alg., threads: " << threads << ") | " << watch.info("Time") << " | Steps: " << counter << " | Rate: " << compr_rate << "% (" << std::setprecision(1) << std::fixed << (total_auxdim_initial*1.0)/N_sites << " ⇒ " << (total_auxdim_final*1.0)/N_sites << ") | Linear dependence checks: " << lindep_checks << std::defaultfloat << std::endl;
1576 std::cout.precision(curr_prec);
1578 {
1579 lout << ss.str();
1580 #if DEBUG_VERBOSITY > 1
1581 lout << "Compressed MPO:" << std::endl;
1582 show();
1583 #endif
1584 }
1585 else
1586 {
1587 before_verb_set += ss.str();
1588 }
1589}
1590#endif
1591
1592template<typename Symmetry, typename Scalar> bool MpoTerms<Symmetry,Scalar>::
1593eliminate_linearlyDependent_rows (const std::size_t loc, const qType &qIn, const double tolerance)
1594{
1595 std::size_t rows = get_auxdim(loc, qIn);
1596 if(rows == 0)
1597 {
1598 return false;
1599 }
1600 bool SAMESITE = false;
1601 if(N_sites == 1 and boundary_condition == BC::INFINITE)
1602 {
1603 SAMESITE = true;
1604 }
1605 assert(hilbert_dimension[loc] > 0);
1606 std::size_t cols_eff = 0;
1607 std::size_t hd = hilbert_dimension[loc];
1608
1609 std::map<qType,std::vector<std::vector<qType>>> opQs;
1610 for(const auto &[qs,ops] : O[loc])
1611 {
1612 if(std::get<0>(qs) != qIn)
1613 {
1614 continue;
1615 }
1616 std::vector<std::vector<qType>> opQs_fixed_qOut(ops[0].size());
1617 for(std::size_t col=0; col<ops[0].size(); ++col)
1618 {
1619 std::unordered_set<qType> unique_control;
1620 for(std::size_t row=0; row<ops.size(); ++row)
1621 {
1622
1623 for(const auto &[Q,op] : ops[row][col])
1624 {
1625 unique_control.insert(Q);
1626 }
1627 }
1628 cols_eff += (unique_control.size() * hd * hd);
1629 opQs_fixed_qOut[col].resize(unique_control.size());
1630 std::copy(unique_control.begin(), unique_control.end(), opQs_fixed_qOut[col].begin());
1631 }
1632 opQs.insert({std::get<1>(qs), opQs_fixed_qOut});
1633 }
1634 std::size_t rows_eff = rows;
1635 std::size_t skipcount = 0;
1636 if(boundary_condition == BC::INFINITE and qIn == qVac)
1637 {
1638 rows_eff = rows_eff-2;
1639 }
1640 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> mat = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>::Zero(rows_eff, cols_eff);
1641 for(std::size_t row=0; row<rows; ++row)
1642 {
1643 std::size_t count = 0;
1644 if((boundary_condition == BC::INFINITE and qIn == qVac and (row == pos_qVac or row == pos_qTot)))
1645 {
1646 skipcount++;
1647 continue;
1648 }
1649 bool zero_row = true;
1650 for(const auto &[qOut, deg] : auxdim[loc+1])
1651 {
1652 auto it_ops = O[loc].find({qIn,qOut});
1653 assert(it_ops != O[loc].end());
1654 auto it_qs = opQs.find(qOut);
1655 assert(it_qs != opQs.end());
1656 for(std::size_t col=0; col<deg; ++col)
1657 {
1658 std::map<qType,OperatorType> &ops = (it_ops->second)[row][col];
1659 for(std::size_t n=0; n<(it_qs->second)[col].size(); ++n)
1660 {
1661 qType &opQ = (it_qs->second)[col][n];
1662 auto it_op = ops.find(opQ);
1663 if(it_op != ops.end() and (it_op->second).data.norm() > tolerance)
1664 {
1665 zero_row = false;
1666 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> opmat((it_op->second).data);
1667 mat.block(row-skipcount, hd*hd*count, 1, hd*hd) = Eigen::Map<Eigen::Matrix<Scalar, 1, Eigen::Dynamic>>(opmat.data(), hd*hd);
1668 }
1669 count++;
1670 }
1671 }
1672 }
1673 if(zero_row)
1674 {
1675 if(rows > 1)
1676 {
1677 #if DEBUG_VERBOSITY > 1
1679 {
1680 lout << "O[" << loc << "]({" << Sym::format<Symmetry>(qIn) << "}->...): Row " << row << " is a zero row, but not the last row in these blocks. Thus it is deleted." << std::endl;
1681 }
1682 #endif
1683 delete_row(loc, qIn, row, false);
1684 delete_col((loc+N_sites-1)%N_sites, qIn, row, SAMESITE);
1685 }
1686 #if DEBUG_VERBOSITY > 1
1687 else
1688 {
1690 {
1691 lout << "O[" << loc << "]({" << Sym::format<Symmetry>(qIn) << "}->...): Row " << row << " is a zero row and the last row in this block. Thus the quantum number is removed from the auxiliar basis to delete the row and the corresponding column at the previous lattice site." << std::endl;
1692 }
1693 }
1694 #endif
1695 decrement_auxdim(loc,qIn);
1696 return true;
1697 }
1698 }
1699 if(rows > 3 or (rows > 1 and (boundary_condition == BC::OPEN or qIn != qVac)))
1700 {
1701 std::size_t rowskipcount = 0;
1702 for(std::size_t row_to_delete=0; row_to_delete<rows; ++row_to_delete)
1703 {
1704 if((boundary_condition == BC::INFINITE and qIn == qVac and (row_to_delete == pos_qVac or row_to_delete == pos_qTot)))
1705 {
1706 rowskipcount++;
1707 continue;
1708 }
1709 std::size_t row_to_delete_eff = row_to_delete - rowskipcount;
1710 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> tempmat(cols_eff, rows_eff-1);
1711 Eigen::Matrix<Scalar, Eigen::Dynamic, 1> tempvec(cols_eff);
1712 tempvec = mat.block(row_to_delete_eff, 0, 1, cols_eff).transpose();
1713 tempmat.block(0,0, cols_eff, row_to_delete_eff) = mat.block(0,0,row_to_delete_eff,cols_eff).transpose();
1714 tempmat.block(0,row_to_delete_eff, cols_eff, rows_eff-row_to_delete_eff-1) = mat.block(row_to_delete_eff+1,0,rows_eff-row_to_delete_eff-1,cols_eff).transpose();
1715
1716
1717 Eigen::Matrix<Scalar, Eigen::Dynamic, 1> vec = tempmat.colPivHouseholderQr().solve(tempvec);
1718
1719 if((tempmat*vec - tempvec).norm() < tolerance)
1720 {
1721 #if DEBUG_VERBOSITY > 1
1723 {
1724 lout << "O[" << loc << "]({" << Sym::format<Symmetry>(qIn) << "}->...): Row " << row_to_delete << " can be written as linear combination of other rows" << std::endl;
1725 }
1726 #endif
1727 delete_row(loc, qIn, row_to_delete, false);
1728 std::map<qType, std::vector<std::map<qType,OperatorType>>> deleted_col = delete_col((loc+N_sites-1)%N_sites, qIn, row_to_delete, SAMESITE);
1729 decrement_auxdim(loc,qIn);
1730 std::size_t cols = get_auxdim(loc,qIn);
1731 std::size_t colskipcount = 0;
1732 for(std::size_t col=0; col<cols; ++col)
1733 {
1734 if((boundary_condition == BC::INFINITE and qIn == qVac and (col == pos_qVac or col == pos_qTot)))
1735 {
1736 colskipcount++;
1737 continue;
1738 }
1739 if(std::abs(vec(col-colskipcount)) > tolerance)
1740 {
1741 add_to_col((loc+N_sites-1)%N_sites, qIn, col, deleted_col, vec(col-colskipcount));
1742 }
1743 }
1744 return true;
1745 }
1746 }
1747 }
1748 return false;
1749}
1750
1751template<typename Symmetry, typename Scalar> bool MpoTerms<Symmetry,Scalar>::
1752eliminate_linearlyDependent_cols (const std::size_t loc, const qType &qOut, const double tolerance)
1753{
1754 std::size_t cols = get_auxdim(loc+1, qOut);
1755 if(cols == 0)
1756 {
1757 return false;
1758 }
1759 bool SAMESITE = false;
1760 if(N_sites == 1 and boundary_condition == BC::INFINITE)
1761 {
1762 SAMESITE = true;
1763 }
1764 assert(hilbert_dimension[loc] > 0);
1765 std::size_t rows_eff = 0;
1766 std::size_t hd = hilbert_dimension[loc];
1767
1768 std::map<qType,std::vector<std::vector<qType>>> opQs;
1769 for(const auto &[qs,ops] : O[loc])
1770 {
1771 if(std::get<1>(qs) != qOut)
1772 {
1773 continue;
1774 }
1775 std::vector<std::vector<qType>> opQs_fixed_qIn(ops.size());
1776 for(std::size_t row=0; row<ops.size(); ++row)
1777 {
1778 std::unordered_set<qType> unique_control;
1779 for(std::size_t col=0; col<ops[row].size(); ++col)
1780 {
1781 for(const auto &[Q,op] : ops[row][col])
1782 {
1783 unique_control.insert(Q);
1784 }
1785 }
1786 rows_eff += (unique_control.size() * hd * hd);
1787 opQs_fixed_qIn[row].resize(unique_control.size());
1788 std::copy(unique_control.begin(), unique_control.end(), opQs_fixed_qIn[row].begin());
1789 }
1790 opQs.insert({std::get<0>(qs), opQs_fixed_qIn});
1791 }
1792
1793 std::size_t cols_eff = cols;
1794 std::size_t skipcount = 0;
1795 if(boundary_condition == BC::INFINITE and qOut == qVac)
1796 {
1797 cols_eff = cols_eff-2;
1798 }
1799 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> mat = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>::Zero(rows_eff, cols_eff);
1800 for(std::size_t col=0; col<cols; ++col)
1801 {
1802 std::size_t count = 0;
1803 if((boundary_condition == BC::INFINITE and qOut == qVac and (col == pos_qVac or col == pos_qTot)))
1804 {
1805 skipcount++;
1806 continue;
1807 }
1808 bool zero_col = true;
1809 for(const auto &[qIn, deg] : auxdim[loc])
1810 {
1811 auto it_ops = O[loc].find({qIn,qOut});
1812 assert(it_ops != O[loc].end());
1813 auto it_qs = opQs.find(qIn);
1814 assert(it_qs != opQs.end());
1815 for(std::size_t row=0; row<deg; ++row)
1816 {
1817 std::map<qType,OperatorType> &ops = (it_ops->second)[row][col];
1818 for(std::size_t n=0; n<(it_qs->second)[row].size(); ++n)
1819 {
1820 qType &opQ = (it_qs->second)[row][n];
1821 auto it_op = ops.find(opQ);
1822 if(it_op != ops.end() and (it_op->second).data.norm() > tolerance)
1823 {
1824 zero_col = false;
1825 Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> opmat((it_op->second).data);
1826 mat.block(hd*hd*count, col-skipcount, hd*hd, 1) = Eigen::Map<Eigen::Matrix<Scalar, Eigen::Dynamic,1>>(opmat.data(), hd*hd);
1827 }
1828 count++;
1829 }
1830 }
1831 }
1832 if(zero_col)
1833 {
1834 if(cols > 1)
1835 {
1836 #if DEBUG_VERBOSITY > 1
1838 {
1839 lout << "O[" << loc << "](...->{" << Sym::format<Symmetry>(qOut) << "}): Column " << col << " is a zero column, but not the last column in these blocks. Thus it is deleted." << std::endl;
1840 }
1841 #endif
1842 delete_col(loc, qOut, col, false);
1843 delete_row((loc+1)%N_sites, qOut, col, SAMESITE);
1844 }
1845 #if DEBUG_VERBOSITY > 1
1846 else
1847 {
1849 {
1850 lout << "O[" << loc << "](...->{" << Sym::format<Symmetry>(qOut) << "}): Column " << col << " is a zero column and the last column in this block. Thus the quantum number is removed from the auxiliar basis to delete the column and the corresponding row at the next lattice site." << std::endl;
1851 }
1852 }
1853 #endif
1854 decrement_auxdim((loc+1)%N_sites,qOut);
1855 return true;
1856 }
1857 }
1858 if(cols > 3 or ((boundary_condition == BC::OPEN or qOut != qVac) and cols>1))
1859 {
1860 std::size_t colskipcount = 0;
1861 for(std::size_t col_to_delete=0; col_to_delete<cols; ++col_to_delete)
1862 {
1863 if((boundary_condition == BC::INFINITE and qOut == qVac and (col_to_delete == pos_qVac or col_to_delete == pos_qTot)))
1864
1865 {
1866 colskipcount++;
1867 continue;
1868 }
1869 std::size_t col_to_delete_eff = col_to_delete - colskipcount;
1870 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> tempmat(rows_eff, cols_eff-1);
1871 Eigen::Matrix<Scalar, Eigen::Dynamic, 1> tempvec(rows_eff);
1872 tempvec = mat.block(0, col_to_delete_eff, rows_eff, 1);
1873 tempmat.block(0,0, rows_eff, col_to_delete_eff) = mat.block(0, 0, rows_eff, col_to_delete_eff);
1874 tempmat.block(0, col_to_delete_eff, rows_eff, cols_eff-col_to_delete_eff-1) = mat.block(0, col_to_delete_eff+1, rows_eff, cols_eff-col_to_delete_eff-1);
1875
1876 Eigen::Matrix<Scalar, Eigen::Dynamic, 1> vec = tempmat.colPivHouseholderQr().solve(tempvec);
1877
1878 if((tempmat*vec - tempvec).norm() < tolerance)
1879 {
1880 #if DEBUG_VERBOSITY > 1
1882 {
1883 lout << "O[" << loc << "](...->{" << Sym::format<Symmetry>(qOut) << "}): Column " << col_to_delete << " can be written as linear combination of other columns" << std::endl;
1884 }
1885 #endif
1886 delete_col(loc, qOut, col_to_delete,false);
1887 std::map<qType, std::vector<std::map<qType,OperatorType>>> deleted_row = delete_row((loc+1)%N_sites, qOut, col_to_delete, SAMESITE);
1888 decrement_auxdim((loc+1)%N_sites,qOut);
1889 std::size_t rows = get_auxdim(loc+1,qOut);
1890 std::size_t rowskipcount = 0;
1891 for(std::size_t row=0; row<rows; ++row)
1892 {
1893 if((boundary_condition == BC::INFINITE and qOut == qVac and (row == pos_qVac or row == pos_qTot)))
1894
1895 {
1896 rowskipcount++;
1897 continue;
1898 }
1899 if(std::abs(vec(row-rowskipcount)) > tolerance)
1900 {
1901 add_to_row((loc+1)%N_sites, qOut, row, deleted_row, vec(row-rowskipcount));
1902 }
1903 }
1904 return true;
1905 }
1906 }
1907 }
1908 return false;
1909}
1910
1911template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1912add_to_row (const std::size_t loc, const qType &qIn, const std::size_t row, const std::map<qType,std::vector<std::map<qType,OperatorType>>> &ops, const Scalar factor)
1913{
1914 #if DEBUG_VERBOSITY > 2
1916 {
1917 lout << "\tO[" << loc << "]({" << Sym::format<Symmetry>(qIn) << "}->...): Add another row scaled by factor " << factor << " to row " << row << std::endl;
1918 }
1919 #endif
1920 std::size_t rows = get_auxdim(loc, qIn);
1921 assert(row < rows and "Trying to add to a nonexisting row");
1922 got_update();
1923 for(const auto &[qOut, deg] : auxdim[loc+1])
1924 {
1925 auto it = O[loc].find({qIn, qOut});
1926 auto it2 = ops.find(qOut);
1927 assert(it != O[loc].end());
1928 assert(it2 != ops.end());
1929 assert((it2->second).size() == deg and "Adding rows of different size");
1930 for(std::size_t col=0; col<deg; ++col)
1931 {
1932 std::map<qType,OperatorType> &existing_ops = (it->second)[row][col];
1933 const std::map<qType,OperatorType> &ops_new = (it2->second)[col];
1934 for(const auto &[Q_new,op_new] : ops_new)
1935 {
1936 auto it3 = existing_ops.find(Q_new);
1937 if(it3 != existing_ops.end())
1938 {
1939 (it3->second) += factor*op_new;
1940 }
1941 else
1942 {
1943 existing_ops.insert({Q_new,factor*op_new});
1944 }
1945 }
1946 }
1947 }
1948}
1949
1950template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
1951add_to_col (const std::size_t loc, const qType &qOut, const std::size_t col, const std::map<qType, std::vector<std::map<qType,OperatorType>>> &ops, const Scalar factor)
1952{
1953 #if DEBUG_VERBOSITY > 2
1955 {
1956 lout << "\tO[" << loc << "](...->{" << Sym::format<Symmetry>(qOut) << "}): Add another column scaled by factor " << factor << " to column " << col << std::endl;
1957 }
1958 #endif
1959 std::size_t cols = get_auxdim(loc+1, qOut);
1960 assert(col < cols and "Trying to add to a nonexisting col");
1961 got_update();
1962 for(const auto &[qIn, deg] : auxdim[loc])
1963 {
1964 auto it = O[loc].find({qIn, qOut});
1965 auto it2 = ops.find(qIn);
1966 assert(it != O[loc].end());
1967 assert(it2 != ops.end());
1968 assert((it2->second).size() == deg and "Adding columns of different size");
1969 for(std::size_t row=0; row<deg; ++row)
1970 {
1971 std::map<qType,OperatorType> &existing_ops = (it->second)[row][col];
1972 const std::map<qType,OperatorType> &ops_new = (it2->second)[row];
1973 for(const auto &[Q_new,op_new] : ops_new)
1974 {
1975 auto it3 = existing_ops.find(Q_new);
1976 if(it3 != existing_ops.end())
1977 {
1978 (it3->second) += factor*op_new;
1979 }
1980 else
1981 {
1982 existing_ops.insert({Q_new,factor*op_new});
1983 }
1984 }
1985 }
1986 }
1987}
1988
1989template<typename Symmetry, typename Scalar> std::map<typename Symmetry::qType,std::vector<std::map<typename Symmetry::qType,SiteOperator<Symmetry,Scalar>>>> MpoTerms<Symmetry,Scalar>::
1990delete_row (const std::size_t loc, const qType &qIn, const std::size_t row_to_delete, const bool SAMESITE)
1991{
1992 #if DEBUG_VERBOSITY > 2
1994 {
1995 lout << "\tO[" << loc << "]({" << Sym::format<Symmetry>(qIn) << "}->...): Delete row " << row_to_delete << std::endl;
1996 if(SAMESITE)
1997 {
1998 lout << "\tPaying attention since a column has been deleted at the same site before" << std::endl;
1999 }
2000 }
2001 #endif
2002 std::map<qType, std::vector<std::map<qType,OperatorType>>> deleted_row;
2003 std::size_t rows = get_auxdim(loc, qIn);
2004 assert(row_to_delete < rows and "Trying to delete a nonexisting row");
2005 got_update();
2006 std::map<qType,OperatorType> empty_op_map;
2007 for(const auto &[qOut, deg] : auxdim[loc+1])
2008 {
2009 auto it = O[loc].find({qIn, qOut});
2010 std::vector<std::map<qType,OperatorType>> temp;
2011 assert(it != O[loc].end());
2012 std::size_t skip = 0;
2013 if(SAMESITE and qOut == qIn)
2014 {
2015 skip = 1;
2016 }
2017 for(std::size_t col=0; col<deg-skip; ++col)
2018 {
2019 temp.push_back((it->second)[row_to_delete][col]);
2020 for(std::size_t row=row_to_delete; row<rows-1; ++row)
2021 {
2022 (it->second)[row][col] = (it->second)[row+1][col];
2023 }
2024 (it->second)[rows-1][col] = empty_op_map;
2025 }
2026 deleted_row.insert({qOut, temp});
2027 }
2028 return deleted_row;
2029}
2030
2031template<typename Symmetry, typename Scalar> std::map<typename Symmetry::qType,std::vector<std::map<typename Symmetry::qType,SiteOperator<Symmetry,Scalar>>>> MpoTerms<Symmetry,Scalar>::
2032delete_col (const std::size_t loc, const qType &qOut, const std::size_t col_to_delete, const bool SAMESITE)
2033{
2034 #if DEBUG_VERBOSITY > 2
2036 {
2037 lout << "\tO[" << loc << "](...->{" << Sym::format<Symmetry>(qOut) << "}): Delete column " << col_to_delete << std::endl;
2038 if(SAMESITE)
2039 {
2040 lout << "\tPaying attention since a row has been deleted at the same site before" << std::endl;
2041 }
2042 }
2043 #endif
2044 std::map<qType, std::vector<std::map<qType,OperatorType>>> deleted_col;
2045 std::size_t cols = get_auxdim(loc+1, qOut);
2046 assert(col_to_delete < cols and "Trying to delete a nonexisting column");
2047 got_update();
2048 std::map<qType,OperatorType> empty_op_map;
2049 for(const auto &[qIn, deg] : auxdim[loc])
2050 {
2051 auto it = O[loc].find({qIn, qOut});
2052 std::vector<std::map<qType,OperatorType>> temp;
2053 assert(it != O[loc].end());
2054 std::size_t skip = 0;
2055 if(SAMESITE and qIn == qOut)
2056 {
2057 skip = 1;
2058 }
2059 for(std::size_t row=0; row<deg-skip; ++row)
2060 {
2061 temp.push_back((it->second)[row][col_to_delete]);
2062 for(std::size_t col=col_to_delete; col<cols-1; ++col)
2063 {
2064 (it->second)[row][col] = (it->second)[row][col+1];
2065 }
2066 (it->second)[row][cols-1] = empty_op_map;
2067 }
2068 deleted_col.insert({qIn, temp});
2069 }
2070 return deleted_col;
2071}
2072
2073template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2074add (const std::size_t loc, const OperatorType &op, const qType &qIn, const qType &qOut, const std::size_t leftIndex, const std::size_t rightIndex)
2075{
2076 #if DEBUG_VERBOSITY > 2
2078 {
2079 #ifdef OPLABELS
2080 lout << "O[" << loc << "]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "})[" << leftIndex << "|" << rightIndex << "]: Add " << op.label << " ({" << Sym::format<Symmetry>(op.Q) << "})" << std::endl;
2081 #else
2082 lout << "O[" << loc << "]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "})[" << leftIndex << "|" << rightIndex << "]: Add Operator ({" << Sym::format<Symmetry>(op.Q) << "})" << std::endl;
2083 #endif
2084 }
2085 #endif
2086 std::size_t rows = get_auxdim(loc, qIn);
2087 std::size_t cols = get_auxdim(loc+1, qOut);
2088 auto it = O[loc].find({qIn, qOut});
2089 assert(leftIndex <= rows and "Index out of bounds");
2090 assert(rightIndex <= cols and "Index out of bounds");
2091 assert(it != O[loc].end() and "Quantum numbers not available");
2092 got_update();
2093 std::map<qType,OperatorType> &existing_ops = (it->second)[leftIndex][rightIndex];
2094 auto it2 = existing_ops.find(op.Q);
2095 if(it2 != existing_ops.end())
2096 {
2097 (it2->second) += op;
2098 }
2099 else
2100 {
2101 existing_ops.insert({op.Q,op});
2102 }
2103}
2104
2105template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2106increment_auxdim (const std::size_t loc, const qType &q)
2107{
2108 #if DEBUG_VERBOSITY > 1
2110 {
2111 lout << "\tqAux[" << (loc+N_sites-1)%N_sites << "->" << loc << "]({" << Sym::format<Symmetry>(q) << "}): ";
2112 }
2113 #endif
2114 got_update();
2115 std::map<qType,OperatorType> empty_op_map;
2116 if(loc != 0)
2117 {
2118 assert(loc < N_sites);
2119 auto it = auxdim[loc].find(q);
2120 if(it == auxdim[loc].end())
2121 {
2122 #if DEBUG_VERBOSITY > 1
2124 {
2125 lout << "New counter started" << std::endl;
2126 }
2127 #endif
2128 for(const auto &[qPrev,dimPrev] : auxdim[loc-1])
2129 {
2130 #if DEBUG_VERBOSITY > 2
2132 {
2133 lout << "\t\tO[" << loc-1 << "]({" << Sym::format<Symmetry>(qPrev) << "}->{" << Sym::format<Symmetry>(q) << "}): Block created with one column of operators (number of rows: " << dimPrev << ")" << std::endl;
2134 }
2135 #endif
2136 std::vector<std::map<qType,OperatorType>> temp_col(1,empty_op_map);
2137 std::vector<std::vector<std::map<qType,OperatorType>>> temp_ops(dimPrev,temp_col);
2138 O[loc-1].insert({{qPrev,q},temp_ops});
2139 }
2140 for(const auto &[qNext,dimNext] : auxdim[loc+1])
2141 {
2142 #if DEBUG_VERBOSITY > 2
2144 {
2145 lout << "\t\tO[" << loc << "]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(qNext) << "}): Block created with one row of operators (number of columns: " << dimNext << ")" << std::endl;
2146 }
2147 #endif
2148 std::vector<std::map<qType,OperatorType>> temp_col(dimNext,empty_op_map);
2149 std::vector<std::vector<std::map<qType,OperatorType>>> temp_ops(1,temp_col);
2150 O[loc].insert({{q,qNext},temp_ops});
2151 }
2152 auxdim[loc].insert({q,1});
2153 }
2154 else
2155 {
2156 #if DEBUG_VERBOSITY > 1
2158 {
2159 lout << "Counter incremented to " << (it->second)+1 << std::endl;
2160 }
2161 #endif
2162 for(const auto &[qPrev,dimPrev] : auxdim[loc-1])
2163 {
2164 #if DEBUG_VERBOSITY > 2
2166 {
2167 lout << "\t\tO[" << loc-1 << "]({" << Sym::format<Symmetry>(qPrev) << "}->{" << Sym::format<Symmetry>(q) << "}): Create a new column of operators (number of rows: " << dimPrev << ")" << std::endl;
2168 }
2169 #endif
2170 auto it_prev = O[loc-1].find({qPrev,q});
2171 assert(it_prev != O[loc-1].end());
2172 for(std::size_t row=0; row<dimPrev; ++row)
2173 {
2174 (it_prev->second)[row].push_back(empty_op_map);
2175 }
2176 }
2177 for(const auto &[qNext,dimNext] : auxdim[loc+1])
2178 {
2179 #if DEBUG_VERBOSITY > 1
2181 {
2182 lout << "\t\tO[" << loc << "]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(qNext) << "}): Create a new row of operators (number of columns: " << dimNext << ")" << std::endl;
2183 }
2184 #endif
2185 auto it_next = O[loc].find({q,qNext});
2186 assert(it_next != O[loc].end());
2187 std::vector<std::map<qType,OperatorType>> temp_row(dimNext, empty_op_map);
2188 (it_next->second).push_back(temp_row);
2189 }
2190 (it->second)++;
2191 }
2192 }
2193 else
2194 {
2195 assert(boundary_condition == BC::INFINITE);
2196 auto it = auxdim[0].find(q);
2197 if(it == auxdim[0].end())
2198 {
2199 #if DEBUG_VERBOSITY > 1
2201 {
2202 lout << "New counter started" << std::endl;
2203 }
2204 #endif
2205 for(const auto &[qPrev,dimPrev] : auxdim[N_sites-1])
2206 {
2207 #if DEBUG_VERBOSITY > 2
2209 {
2210 lout << "\t\tO[" << N_sites-1 << "]({" << Sym::format<Symmetry>(qPrev) << "}->{" << Sym::format<Symmetry>(q) << "}): Block created with one column of operators (number of rows: " << dimPrev << ")" << std::endl;
2211 }
2212 #endif
2213 std::vector<std::map<qType,OperatorType>> temp_col(1,empty_op_map);
2214 std::vector<std::vector<std::map<qType,OperatorType>>> temp_ops(dimPrev,temp_col);
2215 O[N_sites-1].insert({{qPrev,q},temp_ops});
2216 }
2217 for(const auto &[qNext,dimNext] : auxdim[1])
2218 {
2219 #if DEBUG_VERBOSITY > 2
2221 {
2222 lout << "\t\tO[0]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(qNext) << "}): Block created with one row of operators (number of columns: " << dimNext << ")" << std::endl;
2223 }
2224 #endif
2225 std::vector<std::map<qType,OperatorType>> temp_col(dimNext,empty_op_map);
2226 std::vector<std::vector<std::map<qType,OperatorType>>> temp_ops(1,temp_col);
2227 O[0].insert({{q,qNext},temp_ops});
2228 }
2229 auxdim[0].insert({q,1});
2230 auxdim[N_sites].insert({q,1});
2231 }
2232 else
2233 {
2234 #if DEBUG_VERBOSITY > 1
2236 {
2237 lout << "Counter incremented to " << (it->second)+1 << std::endl;
2238 }
2239 #endif
2240 for(const auto &[qPrev,dimPrev] : auxdim[N_sites-1])
2241 {
2242 #if DEBUG_VERBOSITY > 2
2244 {
2245 lout << "\t\tO[" << N_sites-1 << "]({" << Sym::format<Symmetry>(qPrev) << "}->{" << Sym::format<Symmetry>(q) << "}): Create a new column of operators (number of rows: " << dimPrev << ")" << std::endl;
2246 }
2247 #endif
2248 auto it_prev = O[N_sites-1].find({qPrev,q});
2249 assert(it_prev != O[N_sites-1].end());
2250 for(std::size_t row=0; row<dimPrev; ++row)
2251 {
2252 (it_prev->second)[row].push_back(empty_op_map);
2253 }
2254 }
2255 for(const auto &[qNext,dimNext] : auxdim[1])
2256 {
2257 #if DEBUG_VERBOSITY > 2
2259 {
2260 lout << "\t\tO[0]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(qNext) << "}): Create a new row of operators (number of columns: " << dimNext << ")" << std::endl;
2261 }
2262 #endif
2263 auto it_next = O[0].find({q,qNext});
2264 assert(it_next != O[0].end());
2265 std::vector<std::map<qType,OperatorType>> temp_row(dimNext, empty_op_map);
2266 (it_next->second).push_back(temp_row);
2267 }
2268 (it->second)++;
2269 auto it_edge = auxdim[N_sites].find(q);
2270 assert(it_edge != auxdim[N_sites].end());
2271 (it_edge->second)++;
2272 }
2273 if(N_sites == 1)
2274 {
2275 auto it = O[0].find({q,q});
2276 if(it == O[0].end())
2277 {
2278 #if DEBUG_VERBOSITY > 2
2280 {
2281 lout << "\t\tO[0]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(q) << "}): Create a new block of operators with 1 row and 1 column" << std::endl;
2282 }
2283 #endif
2284 std::vector<std::map<qType,OperatorType>> temp_col(1,empty_op_map);
2285 std::vector<std::vector<std::map<qType,OperatorType>>> temp_ops(1,temp_col);
2286 O[0].insert({{q,q},temp_ops});
2287 }
2288 else
2289 {
2290 #if DEBUG_VERBOSITY > 2
2292 {
2293 lout << "\t\tO[0]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(q) << "}): Add the corner operator" << std::endl;
2294 }
2295 #endif
2296 (it->second)[(it->second).size()-1].push_back(empty_op_map);
2297 }
2298 }
2299 }
2300}
2301
2302template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2304{
2305 assert(boundary_condition == BC::OPEN);
2306 #if DEBUG_VERBOSITY > 1
2308 {
2309 lout << "\tqAux[left edge->0]({" << Sym::format<Symmetry>(qIn) << "}): ";
2310 }
2311 #endif
2312 got_update();
2313 std::map<qType,OperatorType> empty_op_map;
2314 auto it = auxdim[0].find(qIn);
2315 if(it == auxdim[0].end())
2316 {
2317 #if DEBUG_VERBOSITY > 1
2319 {
2320 lout << "New counter started" << std::endl;
2321 }
2322 #endif
2323 for(const auto &[qOut,deg] : auxdim[1])
2324 {
2325 #if DEBUG_VERBOSITY > 2
2327 {
2328 lout << "\t\tO[0]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "}): Block created with one row of operators (number of columns: " << deg << ")" << std::endl;
2329 }
2330 #endif
2331 std::vector<std::map<qType,OperatorType>> temp_col(deg,empty_op_map);
2332 std::vector<std::vector<std::map<qType,OperatorType>>> temp_ops(1,temp_col);
2333 O[0].insert({{qIn,qOut},temp_ops});
2334 }
2335 auxdim[0].insert({qIn,1});
2336 }
2337 else
2338 {
2339 #if DEBUG_VERBOSITY > 1
2341 {
2342 lout << "Counter incremented to " << (it->second)+1 << std::endl;
2343 }
2344 #endif
2345 for(const auto &[qOut,deg] : auxdim[1])
2346 {
2347 #if DEBUG_VERBOSITY > 2
2349 {
2350 lout << "\t\tO[0]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "}): Create a new row of operators (number of columns: " << deg << ")" << std::endl;
2351 }
2352 #endif
2353 auto it_ops = O[0].find({qIn,qOut});
2354 assert(it_ops != O[0].end());
2355 std::vector<std::map<qType,OperatorType>> temp_row(deg, empty_op_map);
2356 (it_ops->second).push_back(temp_row);
2357 }
2358 (it->second)++;
2359 }
2360}
2361
2362template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2363increment_last_auxdim_OBC (const qType &qOut)
2364{
2365 assert(boundary_condition == BC::OPEN);
2366 #if DEBUG_VERBOSITY > 1
2368 {
2369 lout << "\tqAux[" << N_sites-1 << "->right edge]({" << Sym::format<Symmetry>(qOut) << "}): ";
2370 }
2371 #endif
2372 got_update();
2373 std::map<qType,OperatorType> empty_op_map;
2374 auto it = auxdim[N_sites].find(qOut);
2375 if(it == auxdim[N_sites].end())
2376 {
2377 #if DEBUG_VERBOSITY > 1
2379 {
2380 lout << "New counter started" << std::endl;
2381 }
2382 #endif
2383 for(const auto &[qIn,deg] : auxdim[N_sites-1])
2384 {
2385 #if DEBUG_VERBOSITY > 2
2387 {
2388 lout << "\t\tO[" << N_sites-1 << "]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "}): Block created with one column of operators (number of rows: " << deg << ")" << std::endl;
2389 }
2390 #endif
2391 std::vector<std::map<qType,OperatorType>> temp_col(1,empty_op_map);
2392 std::vector<std::vector<std::map<qType,OperatorType>>> temp_ops(deg,temp_col);
2393 O[N_sites-1].insert({{qIn,qOut},temp_ops});
2394 }
2395 auxdim[N_sites].insert({qOut,1});
2396 }
2397 else
2398 {
2399 #if DEBUG_VERBOSITY > 1
2401 {
2402 lout << "Counter incremented to " << (it->second)+1 << std::endl;
2403 }
2404 #endif
2405 for(const auto &[qIn,deg] : auxdim[N_sites-1])
2406 {
2407 #if DEBUG_VERBOSITY > 2
2409 {
2410 lout << "\t\tO[" << N_sites-1 << "]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "}): Create a new column of operators (number of rows: " << deg << ")" << std::endl;
2411 }
2412 #endif
2413 auto it_ops = O[N_sites-1].find({qIn,qOut});
2414 assert(it_ops != O[N_sites-1].end());
2415 for(std::size_t row=0; row<deg; ++row)
2416 {
2417 (it_ops->second)[row].push_back(empty_op_map);
2418 }
2419 }
2420 (it->second)++;
2421 }
2422}
2423
2424template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2425decrement_auxdim (const std::size_t loc, const qType &q)
2426{
2427 #if DEBUG_VERBOSITY > 1
2429 {
2430 lout << "\tqAux[" << (loc+N_sites-1)%N_sites << "->" << loc << "]({" << Sym::format<Symmetry>(q) << "}): ";
2431 }
2432 #endif
2433 got_update();
2434 auto it = auxdim[loc].find(q);
2435 assert(it != auxdim[loc].end());
2436 if(loc != 0)
2437 {
2438 assert(loc < N_sites);
2439 if(it->second == 1)
2440 {
2441 #if DEBUG_VERBOSITY > 1
2443 {
2444 lout << "Quantum number deleted" << std::endl;
2445 }
2446 #endif
2447 for(const auto &[qPrev,dimPrev] : auxdim[loc-1])
2448 {
2449 #if DEBUG_VERBOSITY > 2
2451 {
2452 lout << "\t\tO[" << loc-1 << "]({" << Sym::format<Symmetry>(qPrev) << "}->{" << Sym::format<Symmetry>(q) << "}): Block deleted" << std::endl;
2453 }
2454 #endif
2455 O[loc-1].erase({qPrev,q});
2456 }
2457 for(const auto &[qNext,dimNext] : auxdim[loc+1])
2458 {
2459 #if DEBUG_VERBOSITY > 2
2461 {
2462 lout << "\t\tO[" << loc << "]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(qNext) << "}): Block deleted" << std::endl;
2463 }
2464 #endif
2465 O[loc].erase({q,qNext});
2466 }
2467 auxdim[loc].erase(q);
2468 }
2469 else
2470 {
2471 #if DEBUG_VERBOSITY > 1
2473 {
2474 lout << "Counter decremented to " << (it->second)-1 << std::endl;
2475 }
2476 #endif
2477 for(const auto &[qPrev,dimPrev] : auxdim[loc-1])
2478 {
2479 #if DEBUG_VERBOSITY > 2
2481 {
2482 lout << "\t\tO[" << loc-1 << "]({" << Sym::format<Symmetry>(qPrev) << "}->{" << Sym::format<Symmetry>(q) << "}): Delete a column of operators (number of rows: " << dimPrev << ")" << std::endl;
2483 }
2484 #endif
2485 auto it_prev = O[loc-1].find({qPrev,q});
2486 assert(it_prev != O[loc-1].end());
2487 for(std::size_t row=0; row<dimPrev; ++row)
2488 {
2489 (it_prev->second)[row].resize((it_prev->second)[row].size()-1);
2490 }
2491 }
2492 for(const auto &[qNext,dimNext] : auxdim[loc+1])
2493 {
2494 #if DEBUG_VERBOSITY > 2
2496 {
2497 lout << "\t\tO[" << loc << "]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(qNext) << "}): Delete a row of operators (number of columns: " << dimNext << ")" << std::endl;
2498 }
2499 #endif
2500 auto it_next = O[loc].find({q,qNext});
2501 assert(it_next != O[loc].end());
2502 (it_next->second).resize((it_next->second).size()-1);
2503 }
2504 (it->second)--;
2505 }
2506 }
2507 else
2508 {
2509 assert(boundary_condition == BC::INFINITE);
2510 if(it->second == 1)
2511 {
2512 #if DEBUG_VERBOSITY > 1
2514 {
2515 lout << "Quantum number deleted" << std::endl;
2516 }
2517 #endif
2518 for(const auto &[qPrev,dimPrev] : auxdim[N_sites-1])
2519 {
2520 #if DEBUG_VERBOSITY > 2
2522 {
2523 lout << "\t\tO[" << N_sites-1 << "]({" << Sym::format<Symmetry>(qPrev) << "}->{" << Sym::format<Symmetry>(q) << "}): Block deleted" << std::endl;
2524 }
2525 #endif
2526 O[N_sites-1].erase({qPrev,q});
2527 }
2528 for(const auto &[qNext,dimNext] : auxdim[1])
2529 {
2530 #if DEBUG_VERBOSITY > 2
2532 {
2533 lout << "\t\tOperators[0]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(qNext) << "}): Block deleted" << std::endl;
2534 }
2535 #endif
2536 O[0].erase({q,qNext});
2537 }
2538 auxdim[0].erase(q);
2539 auxdim[N_sites].erase(q);
2540 }
2541 else
2542 {
2543 #if DEBUG_VERBOSITY > 1
2545 {
2546 lout << "Counter decremented to " << (it->second)-1 << std::endl;
2547 }
2548 #endif
2549 for(const auto &[qPrev,dimPrev] : auxdim[N_sites-1])
2550 {
2551 #if DEBUG_VERBOSITY > 2
2553 {
2554 lout << "\t\tO[" << N_sites-1 << "]({" << Sym::format<Symmetry>(qPrev) << "}->{" << Sym::format<Symmetry>(q) << "}): Delete a column of operators (number of rows: " << dimPrev << ")" << std::endl;
2555 }
2556 #endif
2557 auto it_prev = O[N_sites-1].find({qPrev,q});
2558 assert(it_prev != O[N_sites-1].end());
2559 for(std::size_t row=0; row<dimPrev; ++row)
2560 {
2561 (it_prev->second)[row].resize((it_prev->second)[row].size()-1);
2562 }
2563 }
2564 for(const auto &[qNext,dimNext] : auxdim[1])
2565 {
2566 #if DEBUG_VERBOSITY > 2
2568 {
2569 lout << "\t\tO[0]({" << Sym::format<Symmetry>(q) << "}->{" << Sym::format<Symmetry>(qNext) << "}): Delete a row of operators (number of columns: " << dimNext << ")" << std::endl;
2570 }
2571 #endif
2572 auto it_next = O[0].find({q,qNext});
2573 assert(it_next != O[0].end());
2574 (it_next->second).resize((it_next->second).size()-1);
2575 }
2576 (it->second)--;
2577 auto it_edge = auxdim[N_sites].find(q);
2578 assert(it_edge != auxdim[N_sites].end());
2579 (it_edge->second)--;
2580
2581 }
2582 }
2583}
2584
2585template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2587{
2588 assert(boundary_condition == BC::OPEN);
2589 #if DEBUG_VERBOSITY > 1
2591 {
2592 lout << "\tqAux[left edge->0]({" << Sym::format<Symmetry>(qIn) << "}): ";
2593 }
2594 #endif
2595 got_update();
2596 auto it = auxdim[0].find(qIn);
2597 assert(it != auxdim[0].end());
2598 if(it->second == 1)
2599 {
2600 #if DEBUG_VERBOSITY > 1
2602 {
2603 lout << "Quantum number deleted" << std::endl;
2604 }
2605 #endif
2606 for(const auto &[qOut,deg] : auxdim[1])
2607 {
2608 #if DEBUG_VERBOSITY > 2
2610 {
2611 lout << "\t\tO[0]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "}): Block deleted" << std::endl;
2612 }
2613 #endif
2614 O[0].erase({qIn,qOut});
2615 }
2616 auxdim[0].erase(qIn);
2617 }
2618 else
2619 {
2620 #if DEBUG_VERBOSITY > 1
2622 {
2623 lout << "Counter decremented to " << (it->second)-1 << std::endl;
2624 }
2625 #endif
2626 for(const auto &[qOut,deg] : auxdim[1])
2627 {
2628 #if DEBUG_VERBOSITY > 2
2630 {
2631 lout << "\t\tO[0]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "}): Delete a row of operators (number of columns: " << deg << ")" << std::endl;
2632 }
2633 #endif
2634 auto it_ops = O[0].find({qIn,qOut});
2635 assert(it_ops != O[0].end());
2636 (it_ops->second).resize((it_ops->second).size()-1);
2637 }
2638 (it->second)--;
2639 }
2640}
2641
2642template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2643decrement_last_auxdim_OBC (const qType &qOut)
2644{
2645 assert(boundary_condition == BC::OPEN);
2646 #if DEBUG_VERBOSITY > 1
2648 {
2649 lout << "\tqAux[" << N_sites-1 << "->right edge]({" << Sym::format<Symmetry>(qOut) << "}): ";
2650 }
2651 #endif
2652 got_update();
2653 auto it = auxdim[N_sites].find(qOut);
2654 assert(it != auxdim[N_sites].end());
2655 if(it->second == 1)
2656 {
2657 #if DEBUG_VERBOSITY > 1
2659 {
2660 lout << "Quantum number deleted" << std::endl;
2661 }
2662 #endif
2663 for(const auto &[qIn,deg] : auxdim[N_sites-1])
2664 {
2665 #if DEBUG_VERBOSITY > 2
2667 {
2668 lout << "\t\tO[" << N_sites-1 << "]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "}): Block deleted" << std::endl;
2669 }
2670 #endif
2671 O[N_sites-1].erase({qIn,qOut});
2672 }
2673 auxdim[N_sites].erase(qOut);
2674 }
2675 else
2676 {
2677 #if DEBUG_VERBOSITY > 1
2679 {
2680 lout << "Counter decremented to " << (it->second)-1 << std::endl;
2681 }
2682 #endif
2683 for(const auto &[qIn,deg] : auxdim[N_sites-1])
2684 {
2685 #if DEBUG_VERBOSITY > 2
2687 {
2688 lout << "\t\tO[" << N_sites-1 << "]({" << Sym::format<Symmetry>(qIn) << "}->{" << Sym::format<Symmetry>(qOut) << "}): Delete a column of operators (number of rows: " << deg << ")" << std::endl;
2689 }
2690 #endif
2691 auto it_ops = O[N_sites-1].find({qIn,qOut});
2692 assert(it_ops != O[N_sites-1].end());
2693 for(std::size_t row=0; row<deg; ++row)
2694 {
2695 (it_ops->second)[row].resize((it_ops->second)[row].size()-1);
2696 }
2697 }
2698 (it->second)--;
2699 }
2700}
2701
2702
2703
2704template<typename Symmetry, typename Scalar> std::size_t MpoTerms<Symmetry,Scalar>::
2705get_auxdim (const std::size_t loc, const qType &q) const
2706{
2707 std::size_t loc_eff;
2708 if(boundary_condition == BC::INFINITE)
2709 {
2710 loc_eff = loc%N_sites;
2711 }
2712 else
2713 {
2714 loc_eff = loc;
2715 }
2716 auto it = auxdim[loc_eff].find(q);
2717 if (it != auxdim[loc_eff].end())
2718 {
2719 return (it->second);
2720 }
2721 else
2722 {
2723 return 0;
2724 }
2725}
2726
2727template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2728assert_hilbert (const std::size_t loc, const std::size_t dim)
2729{
2730 if(hilbert_dimension[loc] == 0)
2731 {
2732 hilbert_dimension[loc] = dim;
2733 }
2734 else
2735 {
2736 if (hilbert_dimension[loc] != dim)
2737 {
2738 lout << termcolor::red << "hilbert_dimension[loc]=" << hilbert_dimension[loc] << ", dim=" << dim << termcolor::reset << endl;
2739 }
2740 assert(hilbert_dimension[loc] == dim and "Dimensions of operator and local Hilbert space do not match!");
2741 }
2742}
2743
2744template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2745save_label (const std::size_t loc, const std::string &info_label)
2746{
2747 assert(loc < N_sites and "Chosen lattice site out of bounds");
2748 if(info_label != "")
2749 {
2750 info[loc].push_back(info_label);
2751 }
2752}
2753
2754template<typename Symmetry, typename Scalar> std::vector<std::string> MpoTerms<Symmetry,Scalar>::
2755get_info () const
2756{
2757 std::vector<std::string> res(N_sites);
2758 for(std::size_t loc=0; loc<N_sites; ++loc)
2759 {
2760 std::stringstream ss;
2761 if (info[loc].size()>0)
2762 {
2763 std::copy(info[loc].begin(), info[loc].end()-1, std::ostream_iterator<std::string>(ss,","));
2764 ss << info[loc].back();
2765 }
2766 else
2767 {
2768 ss << "no info";
2769 }
2770
2771 res[loc] = ss.str();
2772
2773 while (res[loc].find("perp") != std::string::npos) res[loc].replace(res[loc].find("perp"), 4, "⟂");
2774 while (res[loc].find("para") != std::string::npos) res[loc].replace(res[loc].find("para"), 4, "∥");
2775 while (res[loc].find("prime") != std::string::npos) res[loc].replace(res[loc].find("prime"), 5, "'");
2776 while (res[loc].find("Perp") != std::string::npos) res[loc].replace(res[loc].find("Perp"), 4, "⟂");
2777 while (res[loc].find("Para") != std::string::npos) res[loc].replace(res[loc].find("Para"), 4, "∥");
2778 while (res[loc].find("Prime") != std::string::npos) res[loc].replace(res[loc].find("Prime"), 5, "'");
2779 while (res[loc].find("mu") != std::string::npos) res[loc].replace(res[loc].find("mu"), 2, "µ");
2780 while (res[loc].find("Delta") != std::string::npos) res[loc].replace(res[loc].find("Delta"), 5, "Δ");
2781 while (res[loc].find("next") != std::string::npos) res[loc].replace(res[loc].find("next"), 4, "ₙₑₓₜ");
2782 while (res[loc].find("prev") != std::string::npos) res[loc].replace(res[loc].find("prev"), 4, "ₚᵣₑᵥ");
2783 while (res[loc].find("3site") != std::string::npos) res[loc].replace(res[loc].find("3site"), 5, "₃ₛᵢₜₑ");
2784 while (res[loc].find("sub") != std::string::npos) res[loc].replace(res[loc].find("sub"), 3, "ˢᵘᵇ");
2785 while (res[loc].find("rung") != std::string::npos) res[loc].replace(res[loc].find("rung"), 4, "ʳᵘⁿᵍ");
2786 while (res[loc].find("t0") != std::string::npos) res[loc].replace(res[loc].find("t0"), 2, "t₀");
2787
2788 //⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁺ ⁻ ⁼ ⁽ ⁾ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₊ ₋ ₌ ₍ ₎
2789 //ᵃ ᵇ ᶜ ᵈ ᵉ ᶠ ᵍ ʰ ⁱ ʲ ᵏ ˡ ᵐ ⁿ ᵒ ᵖ ʳ ˢ ᵗ ᵘ ᵛ ʷ ˣ ʸ ᶻ
2790 //ᴬ ᴮ ᴰ ᴱ ᴳ ᴴ ᴵ ᴶ ᴷ ᴸ ᴹ ᴺ ᴼ ᴾ ᴿ ᵀ ᵁ ⱽ ᵂ
2791 //ₐ ₑ ₕ ᵢ ⱼ ₖ ₗ ₘ ₙ ₒ ₚ ᵣ ₛ ₜ ᵤ ᵥ ₓ
2792 //ᵅ ᵝ ᵞ ᵟ ᵋ ᶿ ᶥ ᶲ ᵠ ᵡ ᵦ ᵧ ᵨ ᵩ ᵪ
2793 }
2794 return res;
2795}
2796template<typename Symmetry, typename Scalar> const std::vector<std::vector<std::vector<std::vector<Biped<Symmetry, Eigen::SparseMatrix<Scalar,Eigen::ColMajor,EIGEN_DEFAULT_SPARSE_INDEX_TYPE>>>>>> &MpoTerms<Symmetry,Scalar>::
2797get_W_power (std::size_t power) const
2798{
2799 assert(power > 0 and "Power has to be at least 1");
2800 assert(power <= current_power and "This power of the MPO has not been calculated!");
2801 if(power == 1)
2802 {
2803 return W;
2804 }
2805 else
2806 {
2807 return W_powers[power-2];
2808 }
2809}
2810
2811template<typename Symmetry, typename Scalar> const std::vector<Qbasis<Symmetry>> &MpoTerms<Symmetry,Scalar>::
2812get_qAux_power (std::size_t power) const
2813{
2814 assert(power > 0 and "Power has to be at least 1");
2815 assert(power <= current_power and "This power of the MPO has not been calculated!");
2816 if(power == 1)
2817 {
2818 return qAux;
2819 }
2820 else
2821 {
2822 return qAux_powers[power-2];
2823 }
2824}
2825
2826
2827template<typename Symmetry, typename Scalar> const std::vector<std::vector<typename Symmetry::qType>> &MpoTerms<Symmetry,Scalar>::
2828get_qOp_power (std::size_t power) const
2829{
2830 assert(power > 0 and "Power has to be at least 1");
2831 assert(power <= current_power and "This power of the MPO has not been calculated!");
2832 if(power == 1)
2833 {
2834 return qOp;
2835 }
2836 else
2837 {
2838 return qOp_powers[power-2];
2839 }
2840}
2841
2842template<typename Symmetry, typename Scalar> bool MpoTerms<Symmetry,Scalar>::
2843check_qPhys () const
2844{
2845 bool all = true;
2846 for(std::size_t loc=0; loc<N_sites; ++loc)
2847 {
2848 if(!GOT_QPHYS[loc])
2849 {
2850 all = false;
2851 }
2852 }
2853 return all;
2854}
2855
2856template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
2857scale (const Scalar factor, const Scalar offset, const std::size_t power, const double tolerance)
2858{
2859 std::size_t calc_to_power = (power != 0 ? power : current_power);
2860
2861 if (std::abs(factor-1.) > ::mynumeric_limits<double>::epsilon() or std::abs(offset) > tolerance)
2862 {
2863 got_update();
2864 }
2865
2866 if (std::abs(factor-1.) > ::mynumeric_limits<double>::epsilon())
2867 {
2868// lout << termcolor::blue << "SCALING" << ", std::abs(factor-1.)=" << std::abs(factor-1.) << termcolor::reset << endl;
2869
2870// bool sign_factor = (factor < 0. ? true : false);
2871 bool sign_factor = (std::abs(std::arg(factor)) > 0. ? true : false);
2872
2873 double factor_per_site = std::pow(std::abs(factor), 1./(1.*N_sites));
2874 for(std::size_t loc=0; loc<N_sites; ++loc)
2875 {
2876 for(const auto &[qIn, rows] : auxdim[loc])
2877 {
2878 for(const auto &[qOut, cols] : auxdim[loc+1])
2879 {
2880 auto it = O[loc].find({qIn,qOut});
2881 assert(it != O[loc].end());
2882 for(std::size_t row=0; row<rows; ++row)
2883 {
2884 for(std::size_t col=0; col<cols; ++col)
2885 {
2886 std::map<qType,OperatorType> &existing_ops = (it->second)[row][col];
2887 for(auto &[q,op] : existing_ops)
2888 {
2889 op = factor_per_site*op;
2890 }
2891 }
2892 }
2893 }
2894 }
2895 }
2896 if(sign_factor)
2897 {
2898 if(boundary_condition == BC::INFINITE or status == MPO_STATUS::ALTERABLE)
2899 {
2900 for(std::size_t loc=0; loc<N_sites; ++loc)
2901 {
2902 for(const auto &[qOut, cols] : auxdim[loc+1])
2903 {
2904 auto it = O[loc].find({qVac,qOut});
2905 assert(it != O[loc].end());
2906 for(std::size_t col=0; col<cols; ++col)
2907 {
2908 if(col == pos_qVac)
2909 {
2910 continue;
2911 }
2912 std::map<qType,OperatorType> &existing_ops = (it->second)[pos_qVac][col];
2913 for(auto &[q,op] : existing_ops)
2914 {
2915 if constexpr(std::is_same<Scalar,complex<double>>::value)
2916 {
2917 op = exp(1.i*std::arg(factor))*op;
2918 }
2919 else
2920 {
2921 op = -1.*op;
2922 }
2923 }
2924 }
2925 }
2926 }
2927 }
2928 else
2929 {
2930 for(const auto &[qIn,rows] : auxdim[0])
2931 {
2932 for(const auto &[qOut,cols] : auxdim[1])
2933 {
2934 auto it = O[0].find({qIn,qOut});
2935 assert(it != O[0].end());
2936 for(std::size_t row=0; row<rows; ++row)
2937 {
2938 for(std::size_t col=0; col<cols; ++col)
2939 {
2940 std::map<qType,OperatorType> &existing_ops = (it->second)[row][col];
2941 for(auto &[q,op] : existing_ops)
2942 {
2943 if constexpr(std::is_same<Scalar,complex<double>>::value)
2944 {
2945 op = exp(1.i*std::arg(factor))*op;
2946 }
2947 else
2948 {
2949 op = -1.*op;
2950 }
2951 }
2952 }
2953 }
2954 }
2955 }
2956 }
2957 }
2958 }
2959 if (std::abs(offset) > tolerance)
2960 {
2961 //bool sign_offset = (offset < 0. ? true : false);
2962 //cout << boolalpha << "sign_offset=" << sign_offset << endl;
2963 double offset_per_site = std::abs(offset)/(1.*N_sites);
2964 //cout << "offset_per_site=" << offset_per_site << endl;
2965 if(boundary_condition == BC::OPEN)
2966 {
2967 assert(qTot == qVac and "For adding an offset, the MPO needs to be a singlet.");
2968 assert(get_auxdim(0,qVac) == 1 and get_auxdim(N_sites,qVac) == 1 and "Ill-formed auxiliar basis for open boundary condition");
2969 for(std::size_t loc=0; loc<N_sites-1; ++loc)
2970 {
2971 increment_auxdim(loc+1, qVac);
2972 auto it = O[loc].find({qVac,qVac});
2973 assert(it != O[loc].end());
2974 std::map<qType,OperatorType> &existing_ops = (it->second)[get_auxdim(loc,qVac)-1][get_auxdim(loc+1,qVac)-1];
2976 Id.data = Matrix<Scalar,Dynamic,Dynamic>::Identity(hilbert_dimension[loc],hilbert_dimension[loc]).sparseView();
2977 if(loc == N_sites/2) // Muss fuer Spektralfunktionen in der Mitte sein, sonst Phasenshift um pi
2978 {
2979 if constexpr(std::is_same<Scalar,complex<double>>::value)
2980 {
2981 Id.data *= exp(1.i*std::arg(offset));
2982 }
2983 else
2984 {
2985 Id.data *= (offset<0.)? -1.:+1.;
2986 }
2987 }
2988 #ifdef OPLABELS
2989 Id.label = "id";
2990 #endif
2991 auto itQ = existing_ops.find(qVac);
2992 if(itQ == existing_ops.end())
2993 {
2994 existing_ops.insert({qVac,offset_per_site*Id});
2995 }
2996 else
2997 {
2998 (itQ->second) += offset_per_site*Id;
2999 }
3000 }
3001 auto it = O[N_sites-1].find({qVac,qVac});
3002 assert(it != O[N_sites-1].end());
3003 std::map<qType,OperatorType> &existing_ops = (it->second)[get_auxdim(N_sites-1,qVac)-1][get_auxdim(N_sites,qVac)-1];
3005 Id.data = Matrix<Scalar,Dynamic,Dynamic>::Identity(hilbert_dimension[N_sites-1],hilbert_dimension[N_sites-1]).sparseView();
3006 #ifdef OPLABELS
3007 Id.label = "id";
3008 #endif
3009 auto itQ = existing_ops.find(qVac);
3010 if(itQ == existing_ops.end())
3011 {
3012 existing_ops.insert({qVac,offset_per_site*Id});
3013 }
3014 else
3015 {
3016 (itQ->second) += offset_per_site*Id;
3017 }
3018 compress(tolerance);
3019 }
3020 else if(boundary_condition == BC::INFINITE)
3021 {
3022 for(std::size_t loc=0; loc<N_sites; ++loc)
3023 {
3024 auto it = O[loc].find({qVac,qVac});
3025 assert(it != O[loc].end());
3026 std::map<qType,OperatorType> &existing_ops = (it->second)[pos_qVac][pos_qTot];
3028 Id.data = Matrix<Scalar,Dynamic,Dynamic>::Identity(hilbert_dimension[loc],hilbert_dimension[loc]).sparseView();
3029 #ifdef OPLABELS
3030 Id.label = "id";
3031 #endif
3032 auto op_it = existing_ops.find(qVac);
3033 if(op_it == existing_ops.end())
3034 {
3035 existing_ops.insert({qVac,offset_per_site*Id});
3036 }
3037 else
3038 {
3039 (op_it->second) = (op_it->second) + offset_per_site*Id;
3040 }
3041 }
3042 }
3043 }
3044
3045 if (std::abs(factor-1.) > ::mynumeric_limits<double>::epsilon() or std::abs(offset) > tolerance)
3046 {
3047 std::stringstream new_name;
3048 if(std::abs(offset) > ::mynumeric_limits<double>::epsilon())
3049 {
3050 new_name << "[";
3051 }
3052 std::size_t curr_prec = std::cout.precision();
3053 if(std::abs(factor-1.) > ::mynumeric_limits<double>::epsilon())
3054 {
3055 new_name << setprecision(3) << "(" << factor << "*" << label << ")" << setprecision(curr_prec);
3056 }
3057 if(std::abs(offset) > ::mynumeric_limits<double>::epsilon())
3058 {
3059 new_name << " + " << setprecision(3) << offset << setprecision(curr_prec) << "]";
3060 }
3061
3062 if(new_name.str().length() < MAX_SUMPROD_STRINGLENGTH)
3063 {
3064 set_name(new_name.str());
3065 }
3066 else
3067 {
3068 set_name(label+"+[...]");
3069 }
3070
3071 calc(calc_to_power);
3072 }
3073}
3074
3075template<typename Symmetry, typename Scalar> template<typename OtherScalar> MpoTerms<Symmetry, OtherScalar> MpoTerms<Symmetry,Scalar>::
3076cast ()
3077{
3078 MpoTerms<Symmetry, OtherScalar> other(N_sites, boundary_condition);
3079 other.set_name(label);
3080 for(std::size_t loc=0; loc<N_sites; ++loc)
3081 {
3082 for(const auto &[qIn, rows] : auxdim[loc])
3083 {
3084 for(const auto &[qOut, cols] : auxdim[loc+1])
3085 {
3086 auto it = O[loc].find({qIn,qOut});
3087 assert(it != O[loc].end());
3088 for(std::size_t row=0; row<rows; ++row)
3089 {
3090 for(std::size_t col=0; col<cols; ++col)
3091 {
3092 std::map<qType,OperatorType> &existing_ops = (it->second)[row][col];
3093 for(auto &[q,op] : existing_ops)
3094 {
3095 op.template cast<OtherScalar>();
3096 }
3097 }
3098 }
3099 }
3100 }
3101 }
3102 for(std::size_t loc=0; loc<N_sites; ++loc)
3103 {
3104 for(std::size_t i=0; i<info[loc].size(); ++i)
3105 {
3106 other.save_label(loc, info[loc][i]);
3107 }
3108 }
3109 return other;
3110}
3111
3112template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
3113transform_base (const qType &qShift, const bool PRINT, const int factor, const std::size_t power)
3114{
3115 std::size_t calc_to_power = (power != 0ul ? power : current_power);
3116 int length = (factor==-1)? static_cast<int>(qPhys.size()):factor;
3117 ::transform_base<Symmetry>(qPhys, qShift, PRINT, false, length); // from symmery/functions.h, BACK=false
3118
3119 std::vector<std::map<std::array<qType, 2>, std::vector<std::vector<std::map<qType,OperatorType>>>>> O_new(N_sites);
3120 std::vector<std::map<qType, std::size_t>> auxdim_new(N_sites+1);
3121
3122 if(qShift != Symmetry::qvacuum())
3123 {
3124 std::vector<std::size_t> symmetries_to_transform;
3125 for(std::size_t n=0; n<Symmetry::Nq; ++n)
3126 {
3127 if(Symmetry::kind()[n] != Sym::KIND::S and Symmetry::kind()[n] != Sym::KIND::T)
3128 {
3129 symmetries_to_transform.push_back(n);
3130 }
3131 }
3132
3133 for(std::size_t n=0; n<symmetries_to_transform.size(); ++n)
3134 {
3135 qTot[symmetries_to_transform[n]] *= length;
3136 qVac[symmetries_to_transform[n]] *= length;
3137 }
3138
3139 for(std::size_t loc=0; loc<N_sites; ++loc)
3140 {
3141 for(const auto &[qs_key, ops] : O[loc])
3142 {
3143
3144 qType qIn = std::get<0>(qs_key);
3145 qType qOut = std::get<1>(qs_key);
3146 for(std::size_t n=0; n<symmetries_to_transform.size(); ++n)
3147 {
3148 qIn[symmetries_to_transform[n]] *= length;
3149 qOut[symmetries_to_transform[n]] *= length;
3150 }
3151 std::map<qType,OperatorType> empty_op_map;
3152 std::vector<std::map<qType,OperatorType>> temp_row(ops[0].size(), empty_op_map);
3153 std::vector<std::vector<std::map<qType,OperatorType>>> ops_new(ops.size(), temp_row);
3154 for(std::size_t row=0; row<ops.size(); ++row)
3155 {
3156 for(std::size_t col=0; col<ops[row].size(); ++col)
3157 {
3158 for(const auto &[q,op] : ops[row][col])
3159 {
3160 qType q_new = q;
3161 OperatorType op_new = op;
3162 for(std::size_t n=0; n<symmetries_to_transform.size(); ++n)
3163 {
3164 q_new[symmetries_to_transform[n]] *= length;
3165 op_new.Q[symmetries_to_transform[n]] *= length ;
3166 }
3167 ops_new[row][col].insert({q_new,op_new});
3168 }
3169 }
3170 }
3171 O_new[loc].insert({{qIn,qOut},ops_new});
3172 }
3173 }
3174
3175 for(std::size_t loc=0; loc<N_sites+1; ++loc)
3176 {
3177 for(const auto &[q_key, deg] : auxdim[loc])
3178 {
3179 qType q = q_key;
3180 for(std::size_t n=0; n<symmetries_to_transform.size(); ++n)
3181 {
3182 q[symmetries_to_transform[n]] *= length;
3183 }
3184 auxdim_new[loc].insert({q,deg});
3185 }
3186 }
3187
3188 O = O_new;
3189 auxdim = auxdim_new;
3190 got_update();
3191 calc(calc_to_power);
3192 }
3193}
3194
3195template<typename Symmetry, typename Scalar> std::vector<std::vector<TwoSiteData<Symmetry,Scalar>>> MpoTerms<Symmetry,Scalar>::
3196calc_TwoSiteData () const
3197{
3198 std::vector<std::vector<TwoSiteData<Symmetry,Scalar>>> tsd(N_sites-1);
3199
3200 for(std::size_t loc=0; loc<N_sites-1; ++loc)
3201 {
3202 Qbasis<Symmetry> loc12; loc12.pullData(qPhys[loc]);
3203 Qbasis<Symmetry> loc34; loc34.pullData(qPhys[loc+1]);
3204 Qbasis<Symmetry> tensor_basis = loc12.combine(loc34);
3205
3206 // auto tensor_basis = Symmetry::tensorProd(qPhys[loc], qPhys[loc+1]);
3207 for(std::size_t n_lefttop=0; n_lefttop<qPhys[loc].size(); ++n_lefttop)
3208 {
3209 for(std::size_t n_leftbottom=0; n_leftbottom<qPhys[loc].size(); ++n_leftbottom)
3210 {
3211 for(std::size_t t_left=0; t_left<qOp[loc].size(); ++t_left)
3212 {
3213 if(std::array<qType,3> qCheck = {qPhys[loc][n_leftbottom], qOp[loc][t_left], qPhys[loc][n_lefttop]}; !Symmetry::validate(qCheck))
3214 {
3215 continue;
3216 }
3217 for(std::size_t n_righttop=0; n_righttop<qPhys[loc+1].size(); ++n_righttop)
3218 {
3219 for(std::size_t n_rightbottom=0; n_rightbottom<qPhys[loc+1].size(); ++n_rightbottom)
3220 {
3221 for(std::size_t t_right=0; t_right<qOp[loc+1].size(); ++t_right)
3222 {
3223 if(std::array<qType,3> qCheck = {qPhys[loc+1][n_rightbottom], qOp[loc+1][t_right], qPhys[loc+1][n_righttop]}; !Symmetry::validate(qCheck))
3224 {
3225 continue;
3226 }
3227
3228 auto qOp_merges = Symmetry::reduceSilent(qOp[loc][t_left], qOp[loc+1][t_right]);
3229
3230 for(const auto &qOp_merge : qOp_merges)
3231 {
3232 if(!qAux[loc+1].find(qOp_merge))
3233 {
3234 continue;
3235 }
3236
3237 auto qPhys_tops = Symmetry::reduceSilent(qPhys[loc][n_lefttop], qPhys[loc+1][n_righttop]);
3238 auto qPhys_bottoms = Symmetry::reduceSilent(qPhys[loc][n_leftbottom], qPhys[loc+1][n_rightbottom]);
3239 for(const auto &qPhys_top : qPhys_tops)
3240 {
3241 for(const auto &qPhys_bottom : qPhys_bottoms)
3242 {
3243 // auto qTensor_top = make_tuple(qPhys[loc][n_lefttop], n_lefttop, qPhys[loc+1][n_righttop], n_righttop, qPhys_top);
3244 // std::size_t n_top = distance(tensor_basis.begin(), find(tensor_basis.begin(), tensor_basis.end(), qTensor_top));
3245 // std::size_t n_top = tensor_basis.outer_num(qPhys_top) + tensor_basis.leftAmount(qPhys_top,{qPhys[loc][n_lefttop],qPhys[loc+1][n_righttop]}) +
3246 // loc12.inner_num(n_lefttop) + loc34.inner_num(n_righttop)*loc12.inner_dim(qPhys[loc][n_lefttop]);
3247 size_t n_top = tensor_basis.outer_num(qPhys_top) + tensor_basis.leftOffset(qPhys_top,{qPhys[loc][n_lefttop],qPhys[loc+1][n_righttop]},
3248 {loc12.inner_num(n_lefttop),loc34.inner_num(n_righttop)});
3249 // auto qTensor_bottom = make_tuple(qPhys[loc][n_leftbottom], n_leftbottom, qPhys[loc+1][n_rightbottom], n_rightbottom, qPhys_bottom);
3250 // std::size_t n_bottom = distance(tensor_basis.begin(), find(tensor_basis.begin(), tensor_basis.end(), qTensor_bottom));
3251 // std::size_t n_bottom = tensor_basis.outer_num(qPhys_bottom) + tensor_basis.leftAmount(qPhys_bottom,{qPhys[loc][n_leftbottom],qPhys[loc+1][n_rightbottom]}) +
3252 // loc12.inner_num(n_leftbottom) + loc34.inner_num(n_rightbottom)*loc12.inner_dim(qPhys[loc][n_leftbottom]);
3253 size_t n_bottom = tensor_basis.outer_num(qPhys_bottom) + tensor_basis.leftOffset(qPhys_bottom,{qPhys[loc][n_leftbottom],qPhys[loc+1][n_rightbottom]},
3254 {loc12.inner_num(n_leftbottom),loc34.inner_num(n_rightbottom)});
3255 Scalar factor_cgc = 1.;
3256 if(Symmetry::NON_ABELIAN)
3257 {
3258 factor_cgc = Symmetry::coeff_tensorProd(qPhys[loc][n_leftbottom], qPhys[loc+1][n_rightbottom], qPhys_bottom, qOp[loc][t_left], qOp[loc+1][t_right], qOp_merge, qPhys[loc][n_lefttop], qPhys[loc+1][n_righttop], qPhys_top);
3259 }
3260 if(std::abs(factor_cgc) < mynumeric_limits<double>::epsilon())
3261 {
3262 continue;
3263 }
3264 TwoSiteData<Symmetry,Scalar> entry({{n_lefttop,n_leftbottom,n_righttop,n_rightbottom,n_top,n_bottom}}, {{qPhys_top,qPhys_bottom}}, {{t_left,t_right}}, qOp_merge, factor_cgc);
3265 tsd[loc].push_back(entry);
3266 }
3267 }
3268 }
3269 }
3270 }
3271 }
3272 }
3273 }
3274 }
3275 }
3276 return tsd;
3277}
3278
3279template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
3280got_update ()
3281{
3282 GOT_W = false;
3283 GOT_QOP = false;
3284 GOT_QAUX = false;
3285 current_power = 1;
3286}
3287
3288template<typename Symmetry, typename Scalar> MpoTerms<Symmetry,Scalar> MpoTerms<Symmetry,Scalar>::
3289prod (const MpoTerms<Symmetry,Scalar> &top, const MpoTerms<Symmetry,Scalar> &bottom, const qType &qTot, const double tolerance)
3290{
3291 typedef typename Symmetry::qType qType;
3293 typedef Eigen::SparseMatrix<Scalar,Eigen::ColMajor,EIGEN_DEFAULT_SPARSE_INDEX_TYPE> MatrixType;
3294 DMRG::VERBOSITY::OPTION VERB = std::max(top.get_verbosity(), bottom.get_verbosity());
3295
3297 {
3298 lout << "MPO multiplication of " << top.get_name() << "*" << bottom.get_name() << " to quantum number {" << Sym::format<Symmetry>(qTot) << "}" << std::endl;
3299 }
3300 assert(bottom.is_finalized() and top.is_finalized() and "Error: Multiplying non-finalized MPOs");
3301 assert(bottom.size() == top.size() and "Error: Multiplying two MPOs of different size");
3302 assert(bottom.get_boundary_condition() == top.get_boundary_condition() and "Error: Multiplying two MPOs with different boundary conditions");
3303 BC boundary_condition = bottom.get_boundary_condition();
3304
3305 std::vector<qType> qTots = Symmetry::reduceSilent(bottom.get_qTot(), top.get_qTot());
3306 auto it = std::find(qTots.begin(), qTots.end(), qTot);
3307 if (it==qTots.end())
3308 {
3309 lout << "qTot=" << qTot << endl;
3310 for (const auto& qTotVal:qTots)
3311 {
3312 lout << "val=" << qTotVal << endl;
3313 }
3314 assert(it != qTots.end() and "Cannot multiply these two operators to an operator with target quantum number");
3315 }
3316
3317 std::vector<std::map<std::array<qType, 2>, std::vector<std::vector<std::map<qType,OperatorType>>>>> O_bottom, O_top, O;
3318 std::vector<Qbasis<Symmetry>> qAux_bottom, qAux_top, qAux;
3319 std::vector<std::vector<qType>> qPhys, qPhys_check;
3320 std::vector<std::vector<qType>> qOp_bottom, qOp_top;
3321
3322 std::map<qType,OperatorType> empty_op_map;
3323
3324 qPhys = bottom.get_qPhys();
3325 qPhys_check = top.get_qPhys();
3326
3327 O_bottom = bottom.get_O();
3328 O_top = top.get_O();
3329
3330 qAux_bottom = bottom.get_qAux();
3331 qAux_top = top.get_qAux();
3332
3333 qOp_bottom = bottom.get_qOp();
3334 qOp_top = top.get_qOp();
3335
3336 std::size_t N_sites = bottom.size();
3337 O.resize(N_sites);
3338 qAux.resize(N_sites+1);
3339
3340 std::size_t pos_qTot_out = 0;
3341 if(qTot == Symmetry::qvacuum())
3342 {
3343 pos_qTot_out = 1;
3344 }
3345
3346 std::vector<std::size_t> row_qVac(N_sites);
3347 std::vector<std::size_t> col_qVac(N_sites);
3348 std::vector<std::size_t> row_qTot(N_sites);
3349 std::vector<std::size_t> col_qTot(N_sites);
3350
3351
3352 qAux[0] = qAux_bottom[0].combine(qAux_top[0]);
3353
3354
3355 for(std::size_t loc=0; loc<N_sites; ++loc)
3356 {
3357 std::size_t hilbert_dimension = qPhys[loc].size();
3358
3359 assert(hilbert_dimension != 0 and "Not all Hilbert space dimensions have been set!");
3360 assert(hilbert_dimension == qPhys_check[loc].size() and "Local Hilbert space dimensions do not match!");
3361
3362 qAux[loc+1] = qAux_bottom[loc+1].combine(qAux_top[loc+1]);
3363 for(const auto &entry_left : qAux[loc])
3364 {
3365 for(const auto &entry_right : qAux[loc+1])
3366 {
3367 std::size_t rows = std::get<2>(entry_left).size();
3368 std::size_t cols = std::get<2>(entry_right).size();
3369 qType Qin = std::get<0>(entry_left);
3370 qType Qout = std::get<0>(entry_right);
3371 std::vector<std::map<qType,OperatorType>> temp_row(cols, empty_op_map);
3372 std::vector<std::vector<std::map<qType,OperatorType>>> temp(rows, temp_row);
3373 O[loc].insert({{Qin,Qout},temp});
3374 }
3375 }
3376 #if DEBUG_VERBOSITY > 1
3378 {
3379 lout << "Lattice site " << loc << ":" << std::endl;
3380 }
3381 #endif
3382 std::vector<qType> Qins = qAux[loc].qs();
3383 for(const auto &Qin : Qins)
3384 {
3385 std::size_t total_rows = qAux[loc].inner_dim(Qin);
3386 auto qins = Sym::split<Symmetry>(Qin,qAux_top[loc].qs(), qAux_bottom[loc].qs());
3387 for(const auto &[qin_top, qin_bottom] : qins)
3388 {
3389 std::size_t rows_bottom = qAux_bottom[loc].inner_dim(qin_bottom);
3390 std::size_t rows_top = qAux_top[loc].inner_dim(qin_top);
3391 #if DEBUG_VERBOSITY > 1
3393 {
3394 lout << "\tQin = {" << Sym::format<Symmetry>(Qin) << "} can be reached by {" << Sym::format<Symmetry>(qin_bottom) << "} + {" << Sym::format<Symmetry>(qin_top) << "}" << std::endl;
3395 }
3396 #endif
3397 std::vector<qType> Qouts = qAux[loc+1].qs();
3398 for(const auto &Qout : Qouts)
3399 {
3400 if(boundary_condition == BC::OPEN and (loc+1 == N_sites) and (Qout != qTot))
3401 {
3402 continue;
3403 }
3404 std::size_t total_cols = qAux[loc+1].inner_dim(Qout);
3405 auto qouts = Sym::split<Symmetry>(Qout,qAux_top[loc+1].qs(), qAux_bottom[loc+1].qs());
3406 for(const auto &[qout_top, qout_bottom] : qouts)
3407 {
3408 std::size_t cols_bottom = qAux_bottom[loc+1].inner_dim(qout_bottom);
3409 std::size_t cols_top = qAux_top[loc+1].inner_dim(qout_top);
3410 #if DEBUG_VERBOSITY > 1
3412 {
3413 lout << "\t\tQout = {" << Sym::format<Symmetry>(Qout) << "} can be reached by {" << Sym::format<Symmetry>(qout_bottom) << "} + {" << Sym::format<Symmetry>(qout_top) << "}" << std::endl;
3414 }
3415 #endif
3416 auto it = O[loc].find({Qin, Qout});
3417 auto it_bottom = O_bottom[loc].find({qin_bottom, qout_bottom});
3418 auto it_top = O_top[loc].find({qin_top, qout_top});
3419 std::size_t in_pos = qAux[loc].leftAmount(Qin, {qin_bottom, qin_top});
3420 std::size_t out_pos = qAux[loc+1].leftAmount(Qout, {qout_bottom, qout_top});
3421 for(std::size_t row_bottom=0; row_bottom<rows_bottom; ++row_bottom)
3422 {
3423 for(std::size_t row_top=0; row_top<rows_top; ++row_top)
3424 {
3425 std::size_t total_row = in_pos + row_bottom*rows_top + row_top;
3426 if((qin_bottom == bottom.qVac and row_bottom == bottom.pos_qVac) and (qin_top == top.qVac and row_top == top.pos_qVac) and total_row != row_qVac[loc])
3427 {
3428 row_qVac[loc] = total_row;
3429 }
3430 if((qin_bottom == bottom.qTot and row_bottom == bottom.pos_qTot) and (qin_top == top.qTot and row_top == top.pos_qTot) and total_row != row_qTot[loc])
3431 {
3432 row_qTot[loc] = total_row;
3433 }
3434 for(std::size_t col_bottom=0; col_bottom<cols_bottom; ++col_bottom)
3435 {
3436 for(std::size_t col_top=0; col_top<cols_top; ++col_top)
3437 {
3438 for(const auto &[qOp_bottom,op_bottom] : (it_bottom->second)[row_bottom][col_bottom])
3439 {
3440 for(const auto &[qOp_top,op_top] : (it_top->second)[row_top][col_top])
3441 {
3442 std::size_t total_col = out_pos + col_bottom*cols_top + col_top;
3443 if((qout_bottom == bottom.qVac and col_bottom == bottom.pos_qVac) and (qout_top == top.qVac and col_top == top.pos_qVac) and total_col != col_qVac[loc])
3444 {
3445 col_qVac[loc] = total_col;
3446 }
3447 if((qout_bottom == bottom.qTot and col_bottom == bottom.pos_qTot) and (qout_top == top.qTot and col_top == top.pos_qTot) and total_col != col_qTot[loc])
3448 {
3449 col_qTot[loc] = total_col;
3450 }
3451 std::map<qType,OperatorType> &ops = (it->second)[total_row][total_col];
3452 std::vector<qType> Qops = Symmetry::reduceSilent(qOp_bottom, qOp_top);
3453 for(const auto &Qop : Qops)
3454 {
3455 if(std::array<qType,3> qCheck = {Qin,Qop,Qout}; !Symmetry::validate(qCheck))
3456 {
3457 continue;
3458 }
3459 #ifdef OPLABELS
3460 OperatorType op(Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>::Zero(hilbert_dimension, hilbert_dimension).sparseView(), Qop, op_top.label+"*"+op_bottom.label);
3461 #if DEBUG_VERBOSITY > 1
3463 {
3464 lout << "\t\t\tBlock {" << Sym::format<Symmetry>(Qin) << "}->{" << Sym::format<Symmetry>(Qout) << "},\tPosition [" << total_row << "|" << total_col << "], " << op.label << " {" << Sym::format<Symmetry>(Qop) << "}" << std::endl;
3465 }
3466 #endif
3467 #else
3468 OperatorType op(Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>::Zero(hilbert_dimension,hilbert_dimension).sparseView(), Qop);
3469 #if DEBUG_VERBOSITY > 1
3471 {
3472 lout << "\t\t\tBlock {" << Sym::format<Symmetry>(Qin) << "}->{" << Sym::format<Symmetry>(Qout) << "},\tPosition [" << total_row << "|" << total_col << "], Operator {" << Sym::format<Symmetry>(Qop) << "}" << std::endl;
3473 }
3474 #endif
3475 #endif
3476 Scalar factor_9j = Symmetry::coeff_tensorProd(qin_bottom, qin_top, Qin, qOp_bottom, qOp_top, Qop, qout_bottom, qout_top, Qout);
3477 if(std::abs(factor_9j) < ::mynumeric_limits<double>::epsilon())
3478 {
3479 continue;
3480 }
3481 for(std::size_t n_bottom=0; n_bottom<hilbert_dimension; ++n_bottom)
3482 {
3483 for(std::size_t n_top=0; n_top<hilbert_dimension; ++n_top)
3484 {
3485 if(std::array<qType,3> qCheck = {qPhys[loc][n_bottom], Qop, qPhys[loc][n_top]}; !Symmetry::validate(qCheck))
3486 {
3487 continue;
3488 }
3489 #if DEBUG_VERBOSITY > 2
3491 {
3492 lout << "\t\t\t\tmat(" << n_top << "," << n_bottom << ") = 0";
3493 }
3494 #endif
3495
3496 Scalar val = 0;
3497 for(std::size_t n_middle=0; n_middle<hilbert_dimension; ++n_middle)
3498 {
3499 if(std::array<qType,3> qCheck = {qPhys[loc][n_bottom], qOp_bottom, qPhys[loc][n_middle]}; !Symmetry::validate(qCheck))
3500 {
3501 continue;
3502 }
3503 if(std::array<qType,3> qCheck = {qPhys[loc][n_middle], qOp_top, qPhys[loc][n_top]}; !Symmetry::validate(qCheck))
3504 {
3505 continue;
3506 }
3507 if(std::abs(op_top.data.coeff(n_top, n_middle)) < ::mynumeric_limits<double>::epsilon() or std::abs(op_bottom.data.coeff(n_middle, n_bottom)) < ::mynumeric_limits<double>::epsilon())
3508 {
3509 continue;
3510 }
3511 Scalar factor_6j = Symmetry::coeff_Apair(qPhys[loc][n_top], qOp_top, qPhys[loc][n_middle], qOp_bottom, qPhys[loc][n_bottom], Qop);
3512 if(std::abs(factor_6j) < ::mynumeric_limits<double>::epsilon())
3513 {
3514 continue;
3515 }
3516 val += op_top.data.coeff(n_top, n_middle) * op_bottom.data.coeff(n_middle, n_bottom) * factor_9j * factor_6j;
3517 #if DEBUG_VERBOSITY > 2
3519 {
3520 lout << " + " << op_top.data.coeff(n_top, n_middle) << "*" << op_bottom.data.coeff(n_middle, n_bottom) << "*" << factor_9j*factor_6j;
3521 }
3522 #endif
3523 }
3524 if(std::abs(val) < ::mynumeric_limits<double>::epsilon())
3525 {
3526 #if DEBUG_VERBOSITY > 2
3528 {
3529 lout << " = 0" << std::endl;
3530 }
3531 #endif
3532 continue;
3533 }
3534 op.data.coeffRef(n_top, n_bottom) = val;
3535 #if DEBUG_VERBOSITY > 2
3537 {
3538 lout << " = " << val << std::endl;
3539 }
3540 #endif
3541 }
3542 }
3543 if(op.data.norm() > ::mynumeric_limits<double>::epsilon())
3544 {
3545 auto it_op = ops.find(Qop);
3546 if(it_op != ops.end())
3547 {
3548 (it_op->second) = (it_op->second) + op;
3549 }
3550 else
3551 {
3552 ops.insert({Qop,op});
3553 }
3554 }
3555 }
3556 }
3557 }
3558 }
3559 }
3560 }
3561 }
3562 }
3563 }
3564 }
3565 }
3566 }
3567 if(boundary_condition == BC::INFINITE)
3568 {
3569 #if DEBUG_VERBOSITY > 1
3571 {
3572 lout << "Infinite system: Swap rows and columns to ensure identity operators to be at [0|0] and [1|1]" << std::endl;
3573 }
3574 #endif
3575 prod_swap_IBC(O, row_qVac, col_qVac, row_qTot, col_qTot);
3576 }
3577 if(boundary_condition == BC::OPEN)
3578 {
3579 #if DEBUG_VERBOSITY > 1
3581 {
3582 lout << "Open system: Delete columns at last lattice site which do not match target quantum number" << std::endl;
3583 }
3584 #endif
3585 prod_delZeroCols_OBC(O[N_sites-1], qAux[N_sites], qAux[N_sites-1], qTot, col_qTot[N_sites-1]);
3586 }
3587 MpoTerms<Symmetry,Scalar> out(N_sites, boundary_condition, qTot, VERB);
3588 out.reconstruct(O, qAux, qPhys, true, boundary_condition, qTot);
3589 auto [name_top, power_top] = detect_and_remove_power(top.get_name());
3590 auto [name_bot, power_bot] = detect_and_remove_power(bottom.get_name());
3591
3592 if ((top.get_name()+"\n+"+bottom.get_name()).length() < MAX_SUMPROD_STRINGLENGTH)
3593 {
3594 if(name_top == name_bot)
3595 {
3596 out.set_name(name_top + power_to_string(power_top+power_bot));
3597 }
3598 else
3599 {
3600 out.set_name("⦅"+top.get_name()+"⦆*⦅"+bottom.get_name()+"⦆");
3601 }
3602 }
3603 else if ((top.get_name()+"\n+"+bottom.get_name()).length() >= MAX_SUMPROD_STRINGLENGTH and top.get_name().substr(top.get_name().length()-5) != "[...]")
3604 {
3605 out.set_name(top.get_name()+"\n*[...]");
3606 }
3607 else
3608 {
3609 out.set_name(top.get_name());
3610 }
3611 out.compress(tolerance);
3612 out.calc(1);
3613 return out;
3614}
3615
3616template<typename Symmetry, typename Scalar> std::pair<std::string, std::size_t> MpoTerms<Symmetry,Scalar>::
3617detect_and_remove_power (const std::string &name_w_power)
3618{
3619 std::vector<std::string> str_powers(10);
3620 str_powers[0] = "⁰";
3621 str_powers[1] = "¹";
3622 str_powers[2] = "²";
3623 str_powers[3] = "³";
3624 str_powers[4] = "⁴";
3625 str_powers[5] = "⁵";
3626 str_powers[6] = "⁶";
3627 str_powers[7] = "⁷";
3628 str_powers[8] = "⁸";
3629 str_powers[9] = "⁹";
3630
3631 std::string name_wo_power = name_w_power;
3632 std::size_t power = 1ul;
3633 for(std::size_t ip=0; ip<str_powers.size(); ip++)
3634 {
3635 auto pos = name_wo_power.find(str_powers[ip]);
3636 if(pos == std::string::npos)
3637 {
3638 continue;
3639 }
3640 name_wo_power.erase(pos,pos+str_powers[ip].size());
3641 power = ip;
3642 break;
3643 }
3644 return std::make_pair(name_wo_power,power);
3645}
3646
3647template<typename Symmetry, typename Scalar> std::string MpoTerms<Symmetry,Scalar>::
3648power_to_string (std::size_t power)
3649{
3650 assert(power<10 and "power_to_string has only strings for power < 10.");
3651 std::vector<std::string> str_powers(10);
3652 str_powers[0] = "⁰";
3653 str_powers[1] = "¹";
3654 str_powers[2] = "²";
3655 str_powers[3] = "³";
3656 str_powers[4] = "⁴";
3657 str_powers[5] = "⁵";
3658 str_powers[6] = "⁶";
3659 str_powers[7] = "⁷";
3660 str_powers[8] = "⁸";
3661 str_powers[9] = "⁹";
3662 return str_powers[power];
3663}
3664
3665template<typename Symmetry, typename Scalar> MpoTerms<Symmetry,Scalar> MpoTerms<Symmetry,Scalar>::
3666sum (const MpoTerms<Symmetry,Scalar> &top, const MpoTerms<Symmetry,Scalar> &bottom, const double tolerance)
3667{
3668 typedef typename Symmetry::qType qType;
3670
3671 DMRG::VERBOSITY::OPTION VERB = std::max(top.get_verbosity(), bottom.get_verbosity());
3672
3674 {
3675 lout << "MPO addition of " << bottom.get_name() << "+" << top.get_name() << std::endl;
3676 }
3677
3678 assert(bottom.is_finalized() and top.is_finalized() and "Error: Adding non-finalized MPOs");
3679 assert(bottom.size() == top.size() and "Error: Adding two MPOs of different size");
3680
3681 assert(bottom.get_boundary_condition() == top.get_boundary_condition() and "Error: Adding two MPOs with different boundary conditions");
3682 BC boundary_condition_out = bottom.get_boundary_condition();
3683
3684 std::vector<std::map<std::array<qType, 2>, std::vector<std::vector<std::map<qType,OperatorType>>>>> O_bottom, O_top, O_out;
3685 std::vector<Qbasis<Symmetry>> qAux_bottom, qAux_top, qAux_out;
3686 std::vector<std::vector<qType>> qPhys, qPhys_check;
3687 std::vector<std::vector<qType>> qOp_bottom, qOp_top;
3688 std::map<qType,OperatorType> empty_op_map;
3689
3690 assert(bottom.get_qTot() == top.get_qTot() and "Addition only possible for MPOs with the same total quantum number.");
3691 qType qTot = bottom.get_qTot();
3692
3693 qPhys = bottom.get_qPhys();
3694 qPhys_check = top.get_qPhys();
3695
3696 O_bottom = bottom.get_O();
3697 O_top = top.get_O();
3698
3699 qAux_bottom = bottom.get_qAux();
3700 qAux_top = top.get_qAux();
3701
3702 qOp_bottom = bottom.get_qOp();
3703 qOp_top = top.get_qOp();
3704
3705 std::size_t N_sites = bottom.size();
3706 O_out.resize(N_sites);
3707 qAux_out.resize(N_sites+1);
3708
3709 std::vector<std::map<qType,std::size_t>> auxdim(N_sites+1);
3710 std::vector<std::size_t> auxdim_bottom_starts(N_sites+1);
3711
3712 for(std::size_t loc=0; loc<=N_sites; ++loc)
3713 {
3714 for(const auto &entry : qAux_top[loc])
3715 {
3716 qType q = std::get<0>(entry);
3717 std::size_t deg = std::get<2>(entry).size();
3718 auxdim[loc].insert({q,deg});
3719 if(q == Symmetry::qvacuum())
3720 {
3721 auxdim_bottom_starts[loc] = deg;
3722 }
3723 }
3724 for(const auto &entry : qAux_bottom[loc])
3725 {
3726 qType q = std::get<0>(entry);
3727 std::size_t deg = std::get<2>(entry).size();
3728 auto it = auxdim[loc].find(q);
3729 if(it != auxdim[loc].end())
3730 {
3731 (it->second) += deg;
3732 }
3733 else
3734 {
3735 auxdim[loc].insert({q,deg});
3736 }
3737 }
3738 for(const auto &[q,deg] : auxdim[loc])
3739 {
3740 qAux_out[loc].push_back(q,deg);
3741 }
3742 }
3743
3744 for(std::size_t loc=0; loc<N_sites; ++loc)
3745 {
3746 #if DEBUG_VERBOSITY > 1
3748 {
3749 lout << "Lattice site " << loc << std::endl;
3750 }
3751 #endif
3752 std::size_t hilbert_dimension = qPhys[loc].size();
3753 assert(hilbert_dimension == qPhys_check[loc].size() and "Local Hilbert space dimensions do not match!");
3754
3755 for(const auto &[qIn,rows] : auxdim[loc])
3756 {
3757 std::size_t row_start = 0;
3758 if(qAux_top[loc].find(qIn))
3759 {
3760 row_start = qAux_top[loc].inner_dim(qIn);
3761 }
3762
3763
3764 for(const auto &[qOut,cols] : auxdim[loc+1])
3765 {
3766 std::size_t col_start = 0;
3767 if(qAux_top[loc+1].find(qOut))
3768 {
3769 col_start = qAux_top[loc+1].inner_dim(qOut);
3770 }
3771 #if DEBUG_VERBOSITY > 1
3773 {
3774 lout << "\tqIn = {" << Sym::format<Symmetry>(qIn) << "} and qOut = {" << Sym::format<Symmetry>(qOut) << "} is a " << rows << "x" << cols << "-matrix:" << std::endl;
3775 }
3776 #endif
3777 std::vector<std::map<qType,OperatorType>> temp_row(cols, empty_op_map);
3778 std::vector<std::vector<std::map<qType,OperatorType>>> O_temp(rows, temp_row);
3779 auto it_top = O_top[loc].find({qIn,qOut});
3780 auto it_bottom = O_bottom[loc].find({qIn,qOut});
3781 if(it_top != O_top[loc].end())
3782 {
3783 const std::vector<std::vector<std::map<qType,OperatorType>>> &O_top_temp = it_top->second;
3784 std::size_t top_rows = O_top_temp.size();
3785 std::size_t top_cols = O_top_temp[0].size();
3786 #if DEBUG_VERBOSITY > 1
3788 {
3789 lout << "\t\t Block exists in top MPO and is written from [0|0] to [" << top_rows-1 << "|" << top_cols-1 << "]";
3790 }
3791 #endif
3792 for(std::size_t row=0; row<top_rows; ++row)
3793 {
3794 for(std::size_t col=0; col<top_cols; ++col)
3795 {
3796 O_temp[row][col] = O_top_temp[row][col];
3797 }
3798 }
3799 }
3800 #if DEBUG_VERBOSITY > 1
3801 else
3802 {
3804 {
3805 lout << "\t\t Block does not exist in top MPO";
3806 }
3807 }
3808 #endif
3809 if(it_bottom != O_bottom[loc].end())
3810 {
3811 const std::vector<std::vector<std::map<qType,OperatorType>>> &O_bottom_temp = it_bottom->second;
3812 std::size_t bottom_rows = O_bottom_temp.size();
3813 std::size_t bottom_cols = O_bottom_temp[0].size();
3814 #if DEBUG_VERBOSITY > 1
3816 {
3817 lout << "\t|\t Block exists in bottom MPO and is written from [" << row_start << "|" << col_start << "] to [" << row_start+bottom_rows-1 << "|" << col_start+bottom_cols-1 << "]" << std::endl;
3818 }
3819 #endif
3820 for(std::size_t row=0; row<bottom_rows; ++row)
3821 {
3822 for(std::size_t col=0; col<bottom_cols; ++col)
3823 {
3824 O_temp[row_start+row][col_start+col] = O_bottom_temp[row][col];
3825 }
3826 }
3827 }
3828 #if DEBUG_VERBOSITY > 1
3829 else
3830 {
3832 {
3833 lout << "\t|\t Block does not exist in bottom MPO" << std::endl;
3834 }
3835 }
3836 #endif
3837 O_out[loc].insert({{qIn,qOut},O_temp});
3838 }
3839 }
3840 }
3841
3842 MpoTerms<Symmetry,Scalar> out(N_sites,boundary_condition_out,qTot,VERB);
3843 out.reconstruct(O_out, qAux_out, qPhys, true, boundary_condition_out,qTot);
3844 if(boundary_condition_out == BC::OPEN)
3845 {
3846 #if DEBUG_VERBOSITY > 1
3848 {
3849 lout << "Open System: Add both rows at first lattice site and both columns at last lattice site" << std::endl;
3850 }
3851 #endif
3852 out.add_to_row(0, Symmetry::qvacuum(), 0, out.delete_row(0, Symmetry::qvacuum(),1,false),1.);
3853 out.decrement_first_auxdim_OBC(Symmetry::qvacuum());
3854 out.add_to_col(N_sites-1, qTot, 0, out.delete_col(N_sites-1, qTot,1,false),1.);
3855 out.decrement_last_auxdim_OBC(qTot);
3856 }
3857 else
3858 {
3859 #if DEBUG_VERBOSITY > 1
3861 {
3862 lout << "Infinite System: Add both incoming operator columns and both outgoing operator rows at each lattice site" << std::endl;
3863 }
3864 #endif
3865 for(std::size_t loc=0; loc<N_sites; ++loc)
3866 {
3867 out.delete_col(loc, Symmetry::qvacuum(), auxdim_bottom_starts[loc+1],false);
3868 out.delete_row(loc, Symmetry::qvacuum(), auxdim_bottom_starts[loc]+bottom.get_pos_qTot(),false);
3869 out.add_to_col(loc, Symmetry::qvacuum(), top.get_pos_qTot(), out.delete_col(loc, Symmetry::qvacuum(), auxdim_bottom_starts[loc+1],false),1.);
3870 out.add_to_row(loc, Symmetry::qvacuum(), 0, out.delete_row(loc, Symmetry::qvacuum(), auxdim_bottom_starts[loc],false),1.);
3871 }
3872 for(std::size_t loc=0; loc<N_sites; ++loc)
3873 {
3874 out.decrement_auxdim(loc, Symmetry::qvacuum());
3875 out.decrement_auxdim(loc, Symmetry::qvacuum());
3876 }
3877 }
3878 if ((top.get_name()+"\n+"+bottom.get_name()).length() < MAX_SUMPROD_STRINGLENGTH)
3879 {
3880 out.set_name(top.get_name()+"\n+"+bottom.get_name());
3881 }
3882 else if ((top.get_name()+"\n+"+bottom.get_name()).length() >= MAX_SUMPROD_STRINGLENGTH and top.get_name().substr(top.get_name().length()-5) != "[...]")
3883 {
3884 out.set_name(top.get_name()+"\n+[...]");
3885 }
3886 else
3887 {
3888 out.set_name(top.get_name());
3889 }
3890 out.compress(tolerance);
3891 out.calc(1);
3892 return out;
3893}
3894
3895template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
3896prod_delZeroCols_OBC (std::map<std::array<qType, 2>, std::vector<std::vector<std::map<qType,OperatorType>>>> &O_last, Qbasis<Symmetry> &qAux_last, Qbasis<Symmetry> &qAux_prev, const qType &qTot, const std::size_t col_qTot)
3897{
3898 std::map<std::array<qType, 2>, std::vector<std::vector<std::map<qType,OperatorType>>>> O_new;
3899 Qbasis<Symmetry> qAux_new;
3900 qAux_new.push_back(qTot,1);
3901 for(const auto &entry : qAux_prev)
3902 {
3903 qType qIn = std::get<0>(entry);
3904 std::size_t rows = std::get<2>(entry).size();
3905 std::map<qType,OperatorType> empty_op_map;
3906 std::vector<std::map<qType,OperatorType>> temp_row(1,empty_op_map);
3907 std::vector<std::vector<std::map<qType,OperatorType>>> temp(rows,temp_row);
3908 auto it = O_last.find({qIn,qTot});
3909 assert(it != O_last.end());
3910 for(std::size_t row=0; row<rows; ++row)
3911 {
3912 temp[row][0] = (it->second)[row][col_qTot];
3913 }
3914 O_new.insert({{qIn,qTot},temp});
3915 }
3916 qAux_last.clear();
3917 qAux_last = qAux_new;
3918 O_last = O_new;
3919}
3920
3921template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
3922prod_swap_IBC (std::vector<std::map<std::array<qType, 2>, std::vector<std::vector<std::map<qType,OperatorType>>>>> &O_out, std::vector<std::size_t> &row_qVac, std::vector<std::size_t> &col_qVac, std::vector<std::size_t> &row_qTot, std::vector<std::size_t> &col_qTot)
3923{
3924 std::size_t N_sites = O_out.size();
3925 qType qVac = Symmetry::qvacuum();
3926
3927 for(std::size_t loc=0; loc<N_sites; ++loc)
3928 {
3929 if(row_qVac[loc] != 0)
3930 {
3931 for(auto &[qs, ops] : O_out[loc])
3932 {
3933 if(std::get<0>(qs) != qVac)
3934 {
3935 continue;
3936 }
3937 std::vector<std::map<qType,OperatorType>> temp = ops[0];
3938 ops[0] = ops[row_qVac[loc]];
3939 ops[row_qVac[loc]] = temp;
3940 }
3941 if(row_qTot[loc] == 0)
3942 {
3943 row_qTot[loc] = row_qVac[0];
3944 }
3945 }
3946 if(col_qVac[loc] != 0)
3947 {
3948 for(auto &[qs, ops] : O_out[loc])
3949 {
3950 if(std::get<1>(qs) != qVac)
3951 {
3952 continue;
3953 }
3954 std::size_t rows = ops.size();
3955 for(std::size_t row=0; row<rows; ++row)
3956 {
3957 std::map<qType,OperatorType> temp = ops[row][0];
3958 ops[row][0] = ops[row][col_qVac[loc]];
3959 ops[row][col_qVac[loc]] = temp;
3960 }
3961 }
3962 if(col_qTot[loc] == 0)
3963 {
3964 col_qTot[loc] = col_qVac[0];
3965 }
3966 }
3967 if(row_qTot[loc] != 1)
3968 {
3969 for(auto &[qs, ops] : O_out[loc])
3970 {
3971 if(std::get<0>(qs) != qVac)
3972 {
3973 continue;
3974 }
3975 std::vector<std::map<qType,OperatorType>> temp = ops[1];
3976 ops[1] = ops[row_qTot[loc]];
3977 ops[row_qTot[loc]] = temp;
3978 }
3979 }
3980 if(col_qTot[loc] != 1)
3981 {
3982 for(auto &[qs, ops] : O_out[loc])
3983 {
3984 if(std::get<1>(qs) != qVac)
3985 {
3986 continue;
3987 }
3988 std::size_t rows = ops.size();
3989 for(std::size_t row=0; row<rows; ++row)
3990 {
3991 std::map<qType,OperatorType> temp = ops[row][1];
3992 ops[row][1] = ops[row][col_qTot[loc]];
3993 ops[row][col_qTot[loc]] = temp;
3994 }
3995 }
3996 }
3997 }
3998}
3999template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
4000set_Identity (const typename Symmetry::qType &Q)
4001{
4002 got_update();
4003 O.clear();
4004 O.resize(N_sites);
4005 auxdim.clear();
4006 auxdim.resize(N_sites+1);
4007 label = "Id";
4008 for(std::size_t loc=0; loc<N_sites; ++loc)
4009 {
4010 auxdim[loc].insert({Q,1});
4011 std::map<qType,OperatorType> op_map;
4012 OperatorType op = OperatorType(Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>::Identity(qPhys[loc].size(),qPhys[loc].size()).sparseView(),Symmetry::qvacuum());
4013 #ifdef OPLABELS
4014 op.label = "id";
4015 #endif
4016 op_map.insert({Symmetry::qvacuum(),op});
4017 std::vector<std::map<qType,OperatorType>> temp(1,op_map);
4018 std::vector<std::vector<std::map<qType,OperatorType>>> Oloc(1,temp);
4019 O[loc].insert({{Q,Q},Oloc});
4020 }
4021 auxdim[N_sites].insert({Q,1});
4022 status = MPO_STATUS::FINALIZED;
4023 calc(1);
4024}
4025
4026template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
4027set_Zero ()
4028{
4029 got_update();
4030 O.clear();
4031 O.resize(N_sites);
4032 auxdim.clear();
4033 auxdim.resize(N_sites+1);
4034 label = "Zero";
4035 for(std::size_t loc=0; loc<N_sites; ++loc)
4036 {
4037 auxdim[loc].insert({qVac,1});
4038 std::map<qType,OperatorType> op_map;
4039 OperatorType op = OperatorType(Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>::Zero(qPhys[loc].size(),qPhys[loc].size()).sparseView(),qVac);
4040 #ifdef OPLABELS
4041 op.label = "Zero";
4042 #endif
4043 op_map.insert({qVac,op});
4044 std::vector<std::map<qType,OperatorType>> temp(1,op_map);
4045 std::vector<std::vector<std::map<qType,OperatorType>>> Oloc(1,temp);
4046 O[loc].insert({{qVac,qVac},Oloc});
4047 }
4048 auxdim[N_sites].insert({qVac,1});
4049 status = MPO_STATUS::FINALIZED;
4050 calc(1);
4051}
4052
4053template<typename Symmetry, typename Scalar> std::vector<std::pair<typename Symmetry::qType, std::size_t>> MpoTerms<Symmetry,Scalar>::
4054base_order_IBC (const std::size_t power) const
4055{
4056 assert(boundary_condition == BC::INFINITE);
4057 assert(power > 0 and power <= current_power);
4058 const std::vector<Qbasis<Symmetry>> &qAux_ = (power == 1) ? qAux : qAux_powers[power-2];
4059 const std::vector<std::vector<std::vector<std::vector<Biped<Symmetry,MatrixType>>>>> &W_ = (power == 1) ? W : W_powers[power-2];
4060 std::vector<std::pair<qType, std::size_t>> vout(0);
4061 std::vector<std::pair<qType, std::size_t>> vout_temp(0);
4062 std::size_t hd = hilbert_dimension[0];
4063 vout.push_back({qVac, pos_qTot});
4064 for(std::size_t i=0; i<qAux_[0].data_.size(); ++i)
4065 {
4066 qType qIn = std::get<0>(qAux_[0].data_[i]);
4067 std::size_t dim = std::get<2>(qAux_[0].data_[i]).size();
4068 for(std::size_t row=0; row<dim; row++)
4069 {
4070 if(qIn == qVac and row == pos_qVac)
4071 {
4072 continue;
4073 }
4074 if(qIn == qTot and row == pos_qTot)
4075 {
4076 continue;
4077 }
4078 bool isZeroOp = true;
4079 for(std::size_t m=0; m<hd; ++m)
4080 {
4081 for(std::size_t n=0; n<hd; ++n)
4082 {
4083 for(std::size_t t=0; t<W_[0][m][n].size(); ++t)
4084 {
4085 auto it = W_[0][m][n][t].dict.find({qIn,qVac});
4086 if(it != W_[0][m][n][t].dict.end() and
4087 std::abs(W_[0][m][n][t].block[it->second].coeff(row,pos_qTot)) > ::mynumeric_limits<double>::epsilon())
4088 {
4089 isZeroOp = false;
4090 break;
4091 }
4092 }
4093 if(!isZeroOp) break;
4094 }
4095 if(!isZeroOp) break;
4096 }
4097 if(!isZeroOp)
4098 {
4099 vout.push_back({qIn,row});
4100 }
4101 else
4102 {
4103 vout_temp.push_back({qIn,row});
4104 }
4105 }
4106 }
4107 vout.insert(vout.end(), vout_temp.begin(), vout_temp.end());
4108 vout.push_back({qVac, pos_qVac});
4109 #if DERBUG_VERBOSITY > 0
4110 lout << "Base order for VUMPS:" << std::endl;
4111 for(std::size_t i=0; i<vout.size(); ++i)
4112 {
4113 lout << "\t#" << i << ": {" << Sym::format<Symmetry>(std::get<0>(vout[i])) << "}[" << std::get<1>(vout[i]) << "]" << std::endl;
4114 }
4115 #endif
4116 return vout;
4117}
4118
4119template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
4120renormalize ()
4121{
4122 got_update();
4123 std::vector<double> norm(N_sites, 0.);
4124 for(std::size_t loc=0; loc<N_sites; ++loc)
4125 {
4126 for(const auto &[qs,ops] : O[loc])
4127 {
4128 for(std::size_t row=0; row<ops.size(); ++row)
4129 {
4130 for(std::size_t col=0; col<ops[row].size(); ++col)
4131 {
4132 for(const auto &[Q,op] : ops[row][col])
4133 {
4134 norm[loc] += op.data.norm();
4135 }
4136 }
4137 }
4138 }
4139 }
4140 double overall_norm = 1;
4141 for(std::size_t loc=0; loc<N_sites; ++loc)
4142 {
4143 overall_norm *= norm[loc];
4144 }
4145 overall_norm = std::pow(overall_norm, 1.0/N_sites);
4146 for(std::size_t loc=0; loc<N_sites; ++loc)
4147 {
4148 for(auto &[qs,ops] : O[loc])
4149 {
4150 for(std::size_t row=0; row<ops.size(); ++row)
4151 {
4152 for(std::size_t col=0; col<ops[row].size(); ++col)
4153 {
4154 for(auto &[Q,op] : ops[row][col])
4155 {
4156 double factor = overall_norm/norm[loc];
4157 op.data = factor * op.data;
4158 }
4159 }
4160 }
4161 }
4162 }
4163}
4164
4165template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
4167{
4168 for(std::size_t loc=0; loc<N_sites; ++loc)
4169 {
4170 for(auto &[qs,ops] : O[loc])
4171 {
4172 for(std::size_t row=0; row<ops.size(); ++row)
4173 {
4174 for(std::size_t col=0; col<ops[row].size(); ++col)
4175 {
4176 for(auto &[Q,op] : ops[row][col])
4177 {
4178 op.label = "";
4179 }
4180 }
4181 }
4182 }
4183 }
4184}
4185
4186template<typename Symmetry, typename Scalar> std::tuple<std::size_t,std::size_t,std::size_t,std::size_t> MpoTerms<Symmetry,Scalar>::
4187auxdim_infos () const
4188{
4189 std::size_t total_auxdim = 0;
4190 std::size_t maximum_local_auxdim = 0;
4191 std::size_t total_full_auxdim = 0;
4192 std::size_t maximum_local_full_auxdim = 0;
4193 for(std::size_t bond=0; bond<N_sites; ++bond)
4194 {
4195 std::size_t local_auxdim = 0;
4196 std::size_t local_full_auxdim = 0;
4197 for(const auto &[q,deg] : auxdim[bond])
4198 {
4199 local_auxdim += deg;
4200 local_full_auxdim += deg * Symmetry::degeneracy(q);
4201 }
4202 total_auxdim += local_auxdim;
4203 total_full_auxdim += local_full_auxdim;
4204 if(local_auxdim > maximum_local_auxdim)
4205 {
4206 maximum_local_auxdim = local_auxdim;
4207 }
4208 if(local_full_auxdim > maximum_local_full_auxdim)
4209 {
4210 maximum_local_full_auxdim = local_full_auxdim;
4211 }
4212 }
4213 return std::make_tuple(total_auxdim,maximum_local_auxdim,total_full_auxdim,maximum_local_full_auxdim);
4214}
4215
4216template<typename Symmetry, typename Scalar> double MpoTerms<Symmetry,Scalar>::
4217memory (MEMUNIT memunit) const
4218{
4219 double mem_O = 0.;
4220 for(std::size_t loc=0; loc<O.size(); ++loc)
4221 {
4222 mem_O += calc_memory<std::size_t>(2 * Symmetry::Nq * O[loc].size(),memunit);
4223 for(const auto &[qs,ops] : O[loc])
4224 {
4225 for(std::size_t row=0; row<ops.size(); ++row)
4226 {
4227 for(std::size_t col=0; col<ops[row].size(); ++col)
4228 {
4229 mem_O += calc_memory<std::size_t>(Symmetry::Nq * ops[row][col].size(),memunit);
4230 for(const auto &[Q,op] : ops[row][col])
4231 {
4232 mem_O += calc_memory(op.data,memunit) + calc_memory(op.label,memunit);
4233 }
4234 }
4235 }
4236 }
4237 }
4238
4239 double mem_auxdim = 0.;
4240 for(std::size_t loc=0; loc<=N_sites; ++loc)
4241 {
4242 mem_auxdim += calc_memory<std::size_t>((Symmetry::Nq + 1) * auxdim[loc].size(),memunit);
4243 }
4244
4245 double mem_qAux = 0.;
4246 if(GOT_QAUX)
4247 {
4248 for(std::size_t loc=0; loc<qAux.size(); ++loc)
4249 {
4250 for(std::size_t i=0; i<qAux[loc].data_.size(); ++i)
4251 {
4252 mem_qAux += calc_memory<std::size_t>(Symmetry::Nq + 1,memunit);
4253 mem_qAux += std::get<2>(qAux[loc].data_[i]).size() * (calc_memory("",memunit)+calc_memory<std::size_t>(1ul,memunit));
4254 }
4255 mem_qAux += calc_memory<std::size_t>(Symmetry::Nq * qAux[loc].history.size(),memunit);
4256 for(const auto &[q,vec] : qAux[loc].history)
4257 {
4258 mem_qAux += calc_memory<std::size_t>((2*Symmetry::Nq + 1) * vec.size(), memunit);
4259 }
4260 }
4261 }
4262
4263 double mem_qOp = 0.;
4264 if(GOT_QOP)
4265 {
4266 for(std::size_t loc=0; loc<qOp.size(); ++loc)
4267 {
4268 mem_qOp += Symmetry::Nq * calc_memory<std::size_t>(qOp[loc].size(), memunit);
4269 }
4270 }
4271
4272 double mem_qPhys = 0.;
4273 for(std::size_t loc=0; loc<qPhys.size(); ++loc)
4274 {
4275 if(GOT_QPHYS[loc])
4276 {
4277 mem_qOp += Symmetry::Nq * calc_memory<std::size_t>(qPhys[loc].size(), memunit);
4278 }
4279 }
4280
4281 double mem_W = 0.;
4282 if(GOT_W)
4283 {
4284 for(std::size_t loc=0; loc<W.size(); ++loc)
4285 {
4286 for(std::size_t m=0; m<W[loc].size(); ++m)
4287 {
4288 for(std::size_t n=0; n<W[loc][m].size(); ++n)
4289 {
4290 for(std::size_t t=0; t<W[loc][m][n].size(); ++t)
4291 {
4292 mem_W += W[loc][m][n][t].memory(memunit) + W[loc][m][n][t].overhead(memunit);
4293 }
4294 }
4295 }
4296 }
4297 }
4298
4299 double mem_info = 0.;
4300 mem_info += calc_memory(label,memunit);
4301 for(std::size_t loc=0; loc<info.size(); ++loc)
4302 {
4303 for(std::size_t i=0; i<info[loc].size(); ++i)
4304 {
4305 mem_info += calc_memory(info[loc][i],memunit);
4306 }
4307 }
4308
4309 double mem_powers = 0.;
4310 for(std::size_t power=2; power<=current_power; ++power)
4311 {
4312 for(std::size_t loc=0; loc<W_powers[power-2].size(); ++loc)
4313 {
4314 for(std::size_t m=0; m<W_powers[power-2][loc].size(); ++m)
4315 {
4316 for(std::size_t n=0; n<W_powers[power-2][loc][m].size(); ++n)
4317 {
4318 for(std::size_t t=0; t<W_powers[power-2][loc][m][n].size(); ++t)
4319 {
4320 mem_powers += W_powers[power-2][loc][m][n][t].memory(memunit) + W_powers[power-2][loc][m][n][t].overhead(memunit);
4321 }
4322 }
4323 }
4324 mem_powers += Symmetry::Nq * calc_memory<std::size_t>(qOp_powers[power-2][loc].size(), memunit);
4325 for(std::size_t i=0; i<qAux_powers[power-2][loc].data_.size(); ++i)
4326 {
4327 mem_powers += calc_memory<std::size_t>(Symmetry::Nq + 1,memunit);
4328 mem_powers += std::get<2>(qAux_powers[power-2][loc].data_[i]).size() * (calc_memory("",memunit)+calc_memory<std::size_t>(1ul,memunit));
4329 }
4330 mem_powers += calc_memory<std::size_t>(Symmetry::Nq * qAux_powers[power-2][loc].history.size(),memunit);
4331 for(const auto &[q,vec] : qAux_powers[power-2][loc].history)
4332 {
4333 mem_powers += calc_memory<std::size_t>((2*Symmetry::Nq + 1) * vec.size(), memunit);
4334 }
4335 }
4336 }
4337
4338 return mem_O + mem_auxdim + mem_qAux + mem_qOp + mem_qPhys + mem_W + mem_info + mem_powers;
4339}
4340
4341template<typename Symmetry, typename Scalar> double MpoTerms<Symmetry,Scalar>::
4342sparsity (const std::size_t power, const bool PER_MATRIX) const
4343{
4344 assert(power > 0 and power <= current_power);
4345 assert(GOT_W);
4346 assert(GOT_QAUX);
4347 assert(!PER_MATRIX and "? TODO");
4348 std::size_t nonzero_elements = 0;
4349 std::size_t overall_elements = 0;
4350 const std::vector<Qbasis<Symmetry>> &qAux_ = (power == 1) ? qAux : qAux_powers[power-2];
4351 const std::vector<std::vector<std::vector<std::vector<Biped<Symmetry,MatrixType>>>>> &W_ = (power == 1) ? W : W_powers[power-2];
4352 std::vector<std::size_t> dims(N_sites+1);
4353 for(std::size_t i=0; i<qAux_[0].data_.size(); ++i)
4354 {
4355 dims[0] += std::get<2>(qAux_[0].data_[i]).size();
4356 }
4357 for(std::size_t loc=0; loc<N_sites; ++loc)
4358 {
4359 for(std::size_t i=0; i<qAux_[loc+1].data_.size(); ++i)
4360 {
4361 dims[loc+1] += std::get<2>(qAux_[loc+1].data_[i]).size();
4362 }
4363 std::size_t hd = hilbert_dimension[loc];
4364 overall_elements += hd * hd * dims[loc] * dims[loc+1];
4365 for(std::size_t m=0; m<hd; ++m)
4366 {
4367 for(std::size_t n=0; n<hd; ++n)
4368 {
4369 const auto &left = qAux_[loc].data_;
4370 const auto &right = qAux_[loc+1].data_;
4371 for(std::size_t i=0; i<left.size(); ++i)
4372 {
4373 for(std::size_t j=0; j<right.size(); ++j)
4374 {
4375 Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic> entries = Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>::Zero(std::get<2>(left[i]).size(),std::get<2>(right[j]).size());
4376 for(std::size_t t=0; t<W_[loc][m][n].size(); ++t)
4377 {
4378 auto it = W_[loc][m][n][t].dict.find({std::get<0>(left[i]),std::get<0>(right[j])});
4379 if(it != W_[loc][m][n][t].dict.end())
4380 {
4381 const MatrixType &mat = W_[loc][m][n][t].block[it->second];
4382 assert(mat.rows() == std::get<2>(left[i]).size());
4383 assert(mat.cols() == std::get<2>(right[j]).size());
4384 for(std::size_t row=0; row<mat.rows(); ++row)
4385 {
4386 for(std::size_t col=0; col<mat.cols(); ++col)
4387 {
4388 if(entries(row,col) == 0 and std::abs(mat.coeff(row,col)) > ::mynumeric_limits<double>::epsilon())
4389 {
4390 nonzero_elements++;
4391 entries(row,col) = 1;
4392 }
4393 }
4394 }
4395 }
4396 }
4397 }
4398 }
4399 }
4400 }
4401 }
4402 return (nonzero_elements+0.)/(overall_elements+0.);
4403}
4404
4405#ifdef USE_HDF5_STORAGE
4406template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
4407save (std::string filename)
4408{
4409 assert(GOT_W and "W has to be calculated before saving.");
4410 assert(GOT_QAUX and "qAux has to be calculated before saving.");
4411 assert(GOT_QOP and "qOp has to be calculated before saving.");
4412 filename+=".h5";
4413 lout << termcolor::green << "Saving MPO to path " << filename << termcolor::reset << std::endl;
4414 HDF5Interface target(filename, WRITE);
4415
4416 target.save_scalar(N_sites,"L");
4417 target.save_scalar(N_phys,"vol");
4418 target.save_scalar(static_cast<int>(boundary_condition),"boundary_condition");
4419 target.save_scalar(static_cast<int>(status),"status");
4420 std::string labelstring = "Label";
4421 target.save_char(label,labelstring.c_str());
4422 target.save_scalar(current_power,"maxPower");
4423
4424 target.create_group("qTot");
4425 for(std::size_t nq=0; nq<Symmetry::Nq; ++nq)
4426 {
4427 std::stringstream ss;
4428 ss << "nq=" << nq;
4429 target.save_scalar(qTot[nq],ss.str(),"qTot");
4430 }
4431
4432 target.create_group("qPhys");
4433 for(std::size_t loc=0; loc<N_sites; ++loc)
4434 {
4435 std::stringstream ss_hd;
4436 ss_hd << "loc=" << loc << ",hd";
4437 target.save_scalar(hilbert_dimension[loc],ss_hd.str(),"qPhys");
4438 for(std::size_t n=0; n<hilbert_dimension[loc]; ++n)
4439 {
4440 for(std::size_t nq=0; nq<Symmetry::Nq; ++nq)
4441 {
4442 std::stringstream ss;
4443 ss << "loc=" << loc << ",n=" << n << ",nq=" << nq;
4444 target.save_scalar((qPhys[loc][n])[nq],ss.str(),"qPhys");
4445 }
4446 }
4447 }
4448
4449 for(std::size_t power = 1; power<=current_power; ++power)
4450 {
4451 std::stringstream ss;
4452 ss << "^" << power;
4453 std::string powerstring = (power == 1 ? "" : ss.str());
4454
4455 std::vector<Qbasis<Symmetry>> &qAux_ = (power == 1 ? qAux : qAux_powers[power-2]);
4456 std::vector<std::vector<qType>> &qOp_ = (power == 1 ? qOp : qOp_powers[power-2]);
4457 std::vector<std::vector<std::vector<std::vector<Biped<Symmetry,MatrixType>>>>> &W_ = (power == 1 ? W : W_powers[power-2]);
4458
4459 std::vector<std::vector<qType>> qAuxVec_(N_sites+1);
4460 std::vector<std::vector<std::size_t>> qAuxVec_deg_(N_sites+1);
4461 for(std::size_t loc=0; loc<=N_sites; ++loc)
4462 {
4463 for(std::size_t k=0; k<qAux_[loc].data_.size(); ++k)
4464 {
4465 qAuxVec_[loc].push_back(std::get<0>(qAux_[loc].data_[k]));
4466 qAuxVec_deg_[loc].push_back(std::get<2>(qAux_[loc].data_[k]).size());
4467 }
4468 }
4469
4470
4471 target.create_group("qAux"+powerstring);
4472 for(std::size_t loc=0; loc<=N_sites; ++loc)
4473 {
4474 std::stringstream ss_size;
4475 ss_size << "loc=" << loc << ",size";
4476 target.save_scalar(qAuxVec_[loc].size(),ss_size.str(),"qAux"+powerstring);
4477 for(std::size_t k=0; k<qAuxVec_[loc].size(); ++k)
4478 {
4479 std::stringstream ss_deg;
4480 ss_deg << "loc=" << loc << ",k=" << k << ",deg";
4481 target.save_scalar(qAuxVec_deg_[loc][k], ss_deg.str(),"qAux"+powerstring);
4482 for(std::size_t nq=0; nq<Symmetry::Nq; ++nq)
4483 {
4484 std::stringstream ss_quantum;
4485 ss_quantum << "loc=" << loc << ",k=" << k << ",nq=" << nq;
4486 target.save_scalar((qAuxVec_[loc][k])[nq], ss_quantum.str(),"qAux"+powerstring);
4487 }
4488 }
4489 }
4490
4491 target.create_group("qOp"+powerstring);
4492 for(std::size_t loc=0; loc<N_sites; ++loc)
4493 {
4494 std::stringstream ss_size;
4495 ss_size << "loc=" << loc << ",size";
4496 target.save_scalar(qOp_[loc].size(),ss_size.str(),"qOp"+powerstring);
4497 for(std::size_t t=0; t<qOp_[loc].size(); ++t)
4498 {
4499 for(std::size_t nq=0; nq<Symmetry::Nq; ++nq)
4500 {
4501 std::stringstream ss;
4502 ss << "loc=" << loc << ",t=" << t << ",nq=" << nq;
4503 target.save_scalar((qOp_[loc][t])[nq],ss.str(),"qOp"+powerstring);
4504 }
4505 }
4506 }
4507
4508 target.create_group("W"+powerstring);
4509 for(std::size_t loc=0; loc<N_sites; ++loc)
4510 {
4511 for(std::size_t m=0; m<hilbert_dimension[loc]; ++m)
4512 {
4513 for(std::size_t n=0; n<hilbert_dimension[loc]; ++n)
4514 {
4515 for(std::size_t t=0; t<qOp_[loc].size(); ++t)
4516 {
4517 Biped<Symmetry,MatrixType>& bip = W_[loc][m][n][t];
4518 std::vector<std::size_t> ins, outs;
4519 for(std::size_t entry=0; entry<bip.dim; ++entry)
4520 {
4521 auto it_in = find(qAuxVec_[loc].begin(), qAuxVec_[loc].end(), bip.in[entry]);
4522 auto it_out = find(qAuxVec_[loc+1].begin(), qAuxVec_[loc+1].end(), bip.out[entry]);
4523 assert(it_in != qAuxVec_[loc].end() and it_out != qAuxVec_[loc+1].end());
4524 std::size_t qAux_in_pos = std::distance(qAuxVec_[loc].begin(),it_in);
4525 std::size_t qAux_out_pos = std::distance(qAuxVec_[loc+1].begin(),it_out);
4526 ins.push_back(qAux_in_pos);
4527 outs.push_back(qAux_out_pos);
4528 std::stringstream ss;
4529 ss << "loc=" << loc <<",m=" << m << ",n=" << n << ",t=" << t << ",k'=" << qAux_in_pos << ",k=" << qAux_out_pos;
4530 if constexpr(std::is_same<Scalar,std::complex<double>>::value)
4531 {
4532 target.save_matrix(Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>(bip.block[entry].real()), ss.str()+",Re", "W"+powerstring);
4533 target.save_matrix(Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>(bip.block[entry].imag()), ss.str()+",Im", "W"+powerstring);
4534 }
4535 else
4536 {
4537 target.save_matrix(Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>(bip.block[entry]),ss.str(),"W"+powerstring);
4538 }
4539 }
4540 Eigen::Matrix<std::size_t,Eigen::Dynamic,Eigen::Dynamic> entries(ins.size(),2);
4541 for(std::size_t i=0; i<ins.size(); ++i)
4542 {
4543 entries(i,0) = ins[i];
4544 entries(i,1) = outs[i];
4545 }
4546 std::stringstream ss_entries;
4547 ss_entries << "loc=" << loc << ",m=" << m << ",n=" << n << ",t=" << t << ",entries";
4548 target.save_matrix(entries,ss_entries.str(),"W"+powerstring);
4549 }
4550 }
4551 }
4552 }
4553 }
4554 target.close();
4555}
4556
4557template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
4558load (std::string filename)
4559{
4560 filename+=".h5";
4561 lout << termcolor::green << "Loading MPO from path " << filename << termcolor::reset << std::endl;
4562 HDF5Interface source(filename, READ);
4563
4564 source.load_scalar(N_sites,"L");
4565 source.load_scalar(N_phys,"vol");
4566 source.load_scalar(current_power,"maxPower");
4567 int boundary;
4568 source.load_scalar(boundary,"boundary_condition");
4569 boundary_condition = static_cast<BC>(boundary);
4570 int stat;
4571 source.load_scalar(stat,"status");
4572 status = static_cast<MPO_STATUS::OPTION>(stat);
4573 //source.load_char("Label",label); // old HDF5Interface
4574 source.load_char(label,"Label");
4575
4576 status = MPO_STATUS::FINALIZED;
4577
4578 for(std::size_t nq=0; nq<Symmetry::Nq; ++nq)
4579 {
4580 std::stringstream ss;
4581 ss << "nq=" << nq;
4582 source.load_scalar(qTot[nq],ss.str(),"qTot");
4583 }
4584
4585 hilbert_dimension.clear();
4586 hilbert_dimension.resize(N_sites,0);
4587 GOT_QPHYS.clear();
4588 GOT_QPHYS.resize(N_sites,true);
4589 qPhys.clear();
4590 qPhys.resize(N_sites);
4591 for(std::size_t loc=0; loc<N_sites; ++loc)
4592 {
4593 std::stringstream ss_hd;
4594 ss_hd << "loc=" << loc << ",hd";
4595 source.load_scalar(hilbert_dimension[loc],ss_hd.str(),"qPhys");
4596 qPhys[loc].resize(hilbert_dimension[loc]);
4597 for(std::size_t n=0; n<hilbert_dimension[loc]; ++n)
4598 {
4599 for(std::size_t nq=0; nq<Symmetry::Nq; ++nq)
4600 {
4601 std::stringstream ss;
4602 ss << "loc=" << loc << ",n=" << n << ",nq=" << nq;
4603 source.load_scalar((qPhys[loc][n])[nq],ss.str(),"qPhys");
4604 }
4605 }
4606 }
4607
4608 qAux_powers.clear();
4609 W_powers.clear();
4610 qOp_powers.clear();
4611 if(current_power > 1)
4612 {
4613 qAux_powers.resize(current_power-1);
4614 W_powers.resize(current_power-1);
4615 qOp_powers.resize(current_power-1);
4616 }
4617
4618 for(std::size_t power = 1; power<=current_power; ++power)
4619 {
4620 std::stringstream ss;
4621 ss << "^" << power;
4622 std::string powerstring = (power == 1 ? "" : ss.str());
4623 std::vector<Qbasis<Symmetry>> &qAux_ = (power == 1 ? qAux : qAux_powers[power-2]);
4624 std::vector<std::vector<qType>> &qOp_ = (power == 1 ? qOp : qOp_powers[power-2]);
4625 std::vector<std::vector<std::vector<std::vector<Biped<Symmetry,MatrixType>>>>> &W_ = (power == 1 ? W : W_powers[power-2]);
4626
4627 qAux_.clear();
4628 qAux_.resize(N_sites+1);
4629 qOp_.clear();
4630 qOp_.resize(N_sites);
4631 W_.clear();
4632 W_.resize(N_sites);
4633
4634 std::vector<std::vector<qType>> qAuxVec_(N_sites+1);
4635 std::vector<std::vector<std::size_t>> qAuxVec_deg_(N_sites+1);
4636 for(std::size_t loc=0; loc<=N_sites; ++loc)
4637 {
4638 std::stringstream ss_size;
4639 ss_size << "loc=" << loc << ",size";
4640 std::size_t size;
4641 source.load_scalar(size,ss_size.str(),"qAux"+powerstring);
4642 qAuxVec_[loc].resize(size);
4643 qAuxVec_deg_[loc].resize(size);
4644 for(std::size_t k=0; k<qAuxVec_[loc].size(); ++k)
4645 {
4646 std::stringstream ss_deg;
4647 ss_deg << "loc=" << loc << ",k=" << k << ",deg";
4648 source.load_scalar(qAuxVec_deg_[loc][k], ss_deg.str(),"qAux"+powerstring);
4649 for(std::size_t nq=0; nq<Symmetry::Nq; ++nq)
4650 {
4651 std::stringstream ss_quantum;
4652 ss_quantum << "loc=" << loc << ",k=" << k << ",nq=" << nq;
4653 source.load_scalar((qAuxVec_[loc][k])[nq], ss_quantum.str(),"qAux"+powerstring);
4654 }
4655 }
4656 }
4657 qAux_.resize(N_sites+1);
4658 for(std::size_t loc=0; loc<=N_sites; ++loc)
4659 {
4660 qAux_[loc].clear();
4661 for(std::size_t k=0; k<qAuxVec_[loc].size(); ++k)
4662 {
4663 qAux_[loc].push_back(qAuxVec_[loc][k],qAuxVec_deg_[loc][k]);
4664 }
4665 }
4666
4667
4668 for(std::size_t loc=0; loc<N_sites; ++loc)
4669 {
4670 std::stringstream ss_size;
4671 ss_size << "loc=" << loc << ",size";
4672 std::size_t size;
4673 source.load_scalar(size,ss_size.str(),"qOp"+powerstring);
4674 qOp_[loc].resize(size);
4675 for(std::size_t t=0; t<qOp_[loc].size(); ++t)
4676 {
4677 for(std::size_t nq=0; nq<Symmetry::Nq; ++nq)
4678 {
4679 std::stringstream ss;
4680 ss << "loc=" << loc << ",t=" << t << ",nq=" << nq;
4681 source.load_scalar((qOp_[loc][t])[nq],ss.str(),"qOp"+powerstring);
4682 }
4683 }
4684 }
4685
4686 for(std::size_t loc=0; loc<N_sites; ++loc)
4687 {
4688 W_[loc].resize(hilbert_dimension[loc]);
4689 for(std::size_t m=0; m<hilbert_dimension[loc]; ++m)
4690 {
4691 W_[loc][m].resize(hilbert_dimension[loc]);
4692 for(std::size_t n=0; n<hilbert_dimension[loc]; ++n)
4693 {
4694 W_[loc][m][n].resize(qOp_[loc].size());
4695 for(std::size_t t=0; t<qOp_[loc].size(); ++t)
4696 {
4697 Biped<Symmetry,MatrixType>& bip = W_[loc][m][n][t];
4698 Eigen::Matrix<std::size_t, Eigen::Dynamic, Eigen::Dynamic> entries;
4699 std::stringstream ss_entries;
4700 ss_entries << "loc=" << loc << ",m=" << m << ",n=" << n << ",t=" << t << ",entries";
4701 source.load_matrix(entries,ss_entries.str(),"W"+powerstring);
4702 for(std::size_t i=0; i<entries.rows(); ++i)
4703 {
4704 std::stringstream ss_mat;
4705 ss_mat << "loc=" << loc <<",m=" << m << ",n=" << n << ",t=" << t << ",k'=" << entries(i,0) << ",k=" << entries(i,1);
4706 if constexpr(std::is_same<Scalar,std::complex<double>>::value)
4707 {
4708 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> Real;
4709 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> Imag;
4710 source.load_matrix(Real,ss_mat.str()+",Re","W"+powerstring);
4711 source.load_matrix(Imag,ss_mat.str()+",Im","W"+powerstring);
4712 bip.push_back(qAuxVec_[loc][entries(i,0)],qAuxVec_[loc+1][entries(i,1)],(Real+1.i*Imag).sparseView());
4713 }
4714 else
4715 {
4716 Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> mat;
4717 source.load_matrix(mat,ss_mat.str(),"W"+powerstring);
4718 bip.push_back(qAuxVec_[loc][entries(i,0)],qAuxVec_[loc+1][entries(i,1)],mat.sparseView());
4719 }
4720 }
4721 }
4722 }
4723 }
4724 }
4725 }
4726 GOT_QOP = true;
4727 GOT_QAUX = true;
4728 GOT_W = true;
4729 source.close();
4730 fill_O_from_W();
4731}
4732
4733#endif
4734
4735template<typename Symmetry, typename Scalar> void MpoTerms<Symmetry,Scalar>::
4737{
4738 auxdim.resize(N_sites+1);
4739 O.resize(N_sites);
4740 std::map<qType,OperatorType> empty_op_map;
4741 for(std::size_t k=0; k<qAux[0].data_.size(); ++k)
4742 {
4743 auxdim[0].insert({std::get<0>(qAux[0].data_[k]),std::get<2>(qAux[0].data_[k]).size()});
4744 }
4745 for(std::size_t loc=0; loc<N_sites; ++loc)
4746 {
4747 std::size_t hd = hilbert_dimension[loc];
4748 std::size_t od = qOp[loc].size();
4749 for(std::size_t k=0; k<qAux[loc+1].data_.size(); ++k)
4750 {
4751 auxdim[loc+1].insert({std::get<0>(qAux[loc+1].data_[k]),std::get<2>(qAux[loc+1].data_[k]).size()});
4752 }
4753 for(const auto &[qIn,rows] : auxdim[loc])
4754 {
4755 std::map<std::array<qType, 2>,std::vector<std::vector<std::map<qType,OperatorType>>>> O_loc;
4756 for(const auto &[qOut,cols] : auxdim[loc+1])
4757 {
4758 std::vector<std::map<qType,OperatorType>> temp_col(cols,empty_op_map);
4759 std::vector<std::vector<std::map<qType,OperatorType>>> temp_ops(rows,temp_col);
4760
4761 std::vector<Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>> operator_entries_Qs(od, Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>::Zero(hd,hd));
4762 std::vector<std::vector<Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>>> operator_entries_col(cols,operator_entries_Qs);
4763 std::vector<std::vector<std::vector<Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>>>> operator_entries(rows,operator_entries_col);
4764
4765 for(std::size_t m=0; m<hd; ++m)
4766 {
4767 for(std::size_t n=0; n<hd; ++n)
4768 {
4769 for(std::size_t t=0; t<od; ++t)
4770 {
4771 auto it = W[loc][m][n][t].dict.find({qIn,qOut});
4772 if(it != W[loc][m][n][t].dict.end())
4773 {
4774 Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> mat = W[loc][m][n][t].block[it->second];
4775 for(std::size_t row=0; row<rows; ++row)
4776 {
4777 for(std::size_t col=0; col<cols; ++col)
4778 {
4779 (operator_entries[row][col][t]).coeffRef(m,n) = mat(row,col);
4780 }
4781 }
4782 }
4783 }
4784 }
4785 }
4786
4787 for(std::size_t row=0; row<rows; ++row)
4788 {
4789 for(std::size_t col=0; col<cols; ++col)
4790 {
4791 for(std::size_t t=0; t<od; ++t)
4792 {
4793 if(operator_entries[row][col][t].norm() > ::mynumeric_limits<double>::epsilon())
4794 {
4796 op.data = operator_entries[row][col][t].sparseView();
4797 op.Q = qOp[loc][t];
4798 temp_ops[row][col].insert({qOp[loc][t], op});
4799 }
4800 }
4801 }
4802 }
4803 O[loc].insert({{qIn,qOut},temp_ops});
4804 }
4805 }
4806 }
4807}
4808
4809#endif
double norm(const PivotMatrix0< Symmetry, Scalar, MpoScalar > &H)
size_t dim(const PivotMatrix0< Symmetry, Scalar, MpoScalar > &H)
BC
Definition: DmrgTypedefs.h:161
@ OPEN
Definition: DmrgTypedefs.h:163
@ INFINITE
Definition: DmrgTypedefs.h:164
#define MAX_SUMPROD_STRINGLENGTH
Definition: MpoTerms.h:9
void calc_W()
Definition: MpoTerms.h:1176
static MpoTerms< Symmetry, Scalar > prod(const MpoTerms< Symmetry, Scalar > &top, const MpoTerms< Symmetry, Scalar > &bottom, const qType &qTot, const double tolerance=::mynumeric_limits< double >::epsilon())
Definition: MpoTerms.h:3289
void decrement_auxdim(const std::size_t loc, const qType &q)
Definition: MpoTerms.h:2425
MpoTerms(const std::size_t L=0, const BC boundary_condition_in=BC::OPEN, const qType &qTot_in=Symmetry::qvacuum(), const DMRG::VERBOSITY::OPTION &VERB_in=DMRG::VERBOSITY::OPTION::SILENT)
Definition: MpoTerms.h:732
const std::vector< Qbasis< Symmetry > > & get_qAux_power(std::size_t power) const
Definition: MpoTerms.h:2812
std::vector< int > hilbert_dimension
Definition: MpoTerms.h:92
void renormalize()
Definition: MpoTerms.h:4120
const std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > & Wsq_at(const std::size_t loc) const
Definition: MpoTerms.h:718
std::vector< bool > GOT_QPHYS
Definition: MpoTerms.h:133
void show() const
Definition: MpoTerms.h:1034
const Qbasis< Symmetry > & outBasis(const std::size_t loc) const
Definition: MpoTerms.h:708
void fill_O_from_W()
Definition: MpoTerms.h:4736
std::vector< std::vector< std::string > > info
Definition: MpoTerms.h:86
static void prod_swap_IBC(std::vector< std::map< std::array< qType, 2 >, std::vector< std::vector< std::map< qType, OperatorType > > > > > &O_out, std::vector< std::size_t > &row_qVac, std::vector< std::size_t > &col_qVac, std::vector< std::size_t > &row_qTot, std::vector< std::size_t > &col_qTot)
Definition: MpoTerms.h:3922
std::size_t N_phys
Definition: MpoTerms.h:400
bool GOT_QOP
Definition: MpoTerms.h:117
void set_Zero()
Definition: MpoTerms.h:4027
void finalize(const bool COMPRESS=true, const std::size_t power=1, const double tolerance=::mynumeric_limits< double >::epsilon())
Definition: MpoTerms.h:1281
const Qbasis< Symmetry > & auxBasis(const std::size_t loc) const
Definition: MpoTerms.h:706
void set_verbosity(const DMRG::VERBOSITY::OPTION VERB_in)
Definition: MpoTerms.h:881
const std::size_t get_pos_qTot() const
Definition: MpoTerms.h:589
const std::vector< qType > & opBasisSq(const std::size_t loc) const
Definition: MpoTerms.h:719
std::size_t N_sites
Definition: MpoTerms.h:395
const std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > & W_at(const std::size_t loc) const
Definition: MpoTerms.h:699
const qType & get_qVac() const
Definition: MpoTerms.h:579
std::vector< std::string > get_info() const
Definition: MpoTerms.h:2755
double sparsity(bool USE_SQUARE, bool PER_MATRIX) const
Definition: MpoTerms.h:722
void scale(const Scalar factor, const Scalar offset=0., const std::size_t power=0ul, const double tolerance=1.e-14)
Definition: MpoTerms.h:2857
const bool check_SQUARE() const
Definition: MpoTerms.h:721
void setLocBasis(const std::vector< std::vector< qType > > &q)
Definition: MpoTerms.h:715
std::vector< std::map< std::array< qType, 2 >, std::vector< std::vector< std::map< qType, OperatorType > > > > > O
Definition: MpoTerms.h:47
std::vector< std::vector< qType > > qPhys
Definition: MpoTerms.h:366
void reconstruct(const std::vector< std::map< std::array< qType, 2 >, std::vector< std::vector< std::map< qType, OperatorType > > > > > &O_in, const std::vector< Qbasis< Symmetry > > &qAux_in, const std::vector< std::vector< qType > > &qPhys_in, const bool FINALIZED_IN, const BC boundary_condition_in, const qType &qTot_in=Symmetry::qvacuum())
Definition: MpoTerms.h:811
bool check_qPhys() const
Definition: MpoTerms.h:2843
const std::vector< std::map< std::array< qType, 2 >, std::vector< std::vector< std::map< qType, OperatorType > > > > > & get_O() const
Definition: MpoTerms.h:526
void got_update()
Definition: MpoTerms.h:3280
void save(std::string filename)
const std::vector< std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > > & W_full() const
Definition: MpoTerms.h:700
void assert_hilbert(const std::size_t loc, const std::size_t dim)
Definition: MpoTerms.h:2728
DMRG::VERBOSITY::OPTION VERB
Definition: MpoTerms.h:102
static MpoTerms< Symmetry, Scalar > sum(const MpoTerms< Symmetry, Scalar > &top, const MpoTerms< Symmetry, Scalar > &bottom, const double tolerance=::mynumeric_limits< double >::epsilon())
Definition: MpoTerms.h:3666
const std::vector< std::vector< qType > > & get_qOp() const
Definition: MpoTerms.h:541
virtual void push(const std::size_t loc, const std::vector< OperatorType > &opList, const std::vector< qType > &qList, const Scalar lambda=1.0)
Definition: MpoTerms.h:893
void add_to_row(const std::size_t loc, const qType &qIn, const std::size_t row, const std::map< qType, std::vector< std::map< qType, OperatorType > > > &ops, const Scalar factor)
Definition: MpoTerms.h:1912
std::vector< Qbasis< Symmetry > > qAux
Definition: MpoTerms.h:360
double memory(MEMUNIT memunit=kB) const
Definition: MpoTerms.h:4217
std::size_t size() const
Definition: MpoTerms.h:610
qType qVac
Definition: MpoTerms.h:65
std::size_t pos_qVac
Definition: MpoTerms.h:75
bool GOT_W
Definition: MpoTerms.h:127
bool eliminate_linearlyDependent_rows(const std::size_t loc, const qType &qIn, const double tolerance)
Definition: MpoTerms.h:1593
void decrement_first_auxdim_OBC(const qType &qIn)
Definition: MpoTerms.h:2586
DMRG::VERBOSITY::OPTION get_verbosity() const
Definition: MpoTerms.h:693
MPO_STATUS::OPTION status
Definition: MpoTerms.h:97
const std::vector< std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > > & get_W() const
Definition: MpoTerms.h:531
std::vector< std::vector< qType > > qOp
Definition: MpoTerms.h:354
bool eliminate_linearlyDependent_cols(const std::size_t loc, const qType &qOut, const double tolerance)
Definition: MpoTerms.h:1752
void calc_qAux()
Definition: MpoTerms.h:1265
void compress(const double tolerance)
Definition: MpoTerms.h:1438
void setQtarget(const qType &q)
Definition: MpoTerms.h:725
MpoTerms< Symmetry, OtherScalar > cast()
Definition: MpoTerms.h:3076
void push(const std::size_t loc, const std::vector< OperatorType > &opList, const Scalar lambda=1.0)
Definition: MpoTerms.h:455
std::size_t pos_qTot
Definition: MpoTerms.h:70
std::vector< std::vector< std::vector< qType > > > qOp_powers
Definition: MpoTerms.h:378
const std::vector< qType > & opBasis(const std::size_t loc) const
Definition: MpoTerms.h:711
std::vector< std::vector< TwoSiteData< Symmetry, Scalar > > > calc_TwoSiteData() const
Definition: MpoTerms.h:3196
void clear_opLabels()
Definition: MpoTerms.h:4166
const std::vector< std::vector< qType > > & locBasis() const
Definition: MpoTerms.h:702
std::vector< std::map< qType, std::size_t > > auxdim
Definition: MpoTerms.h:55
const std::vector< qType > & locBasis(const std::size_t loc) const
Definition: MpoTerms.h:703
void calc(const std::size_t power)
Definition: MpoTerms.h:1135
std::vector< std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > > W
Definition: MpoTerms.h:372
void set_qPhys(const std::size_t loc, const std::vector< qType > &qPhys_in)
Definition: MpoTerms.h:500
const Qbasis< Symmetry > & inBasis(const std::size_t loc) const
Definition: MpoTerms.h:707
std::size_t current_power
Definition: MpoTerms.h:112
void decrement_last_auxdim_OBC(const qType &qOut)
Definition: MpoTerms.h:2643
const std::vector< std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > > & get_W_power(std::size_t power) const
Definition: MpoTerms.h:2797
static std::pair< std::string, std::size_t > detect_and_remove_power(const std::string &name_w_power)
Definition: MpoTerms.h:3617
const std::string get_name() const
Definition: MpoTerms.h:476
static std::string power_to_string(std::size_t power)
Definition: MpoTerms.h:3648
void initialize(const std::size_t L, const BC boundary_condition_in, const qType &qTot_in)
Definition: MpoTerms.h:802
const std::vector< std::vector< qType > > & get_qOp_power(std::size_t power) const
Definition: MpoTerms.h:2828
std::vector< std::vector< Qbasis< Symmetry > > > qAux_powers
Definition: MpoTerms.h:384
void transform_base(const qType &qShift, const bool PRINT=false, const int factor=-1, const std::size_t powre=0ul)
Definition: MpoTerms.h:3113
BC get_boundary_condition() const
Definition: MpoTerms.h:574
std::size_t get_auxdim(const std::size_t loc, const qType &q) const
Definition: MpoTerms.h:2705
void load(std::string filename)
std::map< qType, std::vector< std::map< qType, OperatorType > > > delete_row(const std::size_t loc, const qType &qIn, const std::size_t row_to_delete, const bool SAMESITE)
Definition: MpoTerms.h:1990
const qType & get_qTot() const
Definition: MpoTerms.h:584
void calc_qOp()
Definition: MpoTerms.h:1236
bool is_finalized() const
Definition: MpoTerms.h:521
void set_name(const std::string &label_in)
Definition: MpoTerms.h:471
bool check_power(std::size_t power) const
Definition: MpoTerms.h:600
std::string before_verb_set
Definition: MpoTerms.h:107
Symmetry::qType qType
Definition: MpoTerms.h:38
const std::vector< std::vector< qType > > & get_qPhys() const
Definition: MpoTerms.h:546
Eigen::SparseMatrix< Scalar, Eigen::ColMajor, EIGEN_DEFAULT_SPARSE_INDEX_TYPE > MatrixType
Definition: MpoTerms.h:39
std::size_t maxPower() const
Definition: MpoTerms.h:605
void set_Identity(const typename Symmetry::qType &Q=Symmetry::qvacuum())
Definition: MpoTerms.h:4000
bool GOT_QAUX
Definition: MpoTerms.h:122
static void prod_delZeroCols_OBC(std::map< std::array< qType, 2 >, std::vector< std::vector< std::map< qType, OperatorType > > > > &O_last, Qbasis< Symmetry > &qAux_last, Qbasis< Symmetry > &qAux_prev, const qType &qTot, const std::size_t col_qTot)
Definition: MpoTerms.h:3896
const std::vector< Qbasis< Symmetry > > & get_qAux() const
Definition: MpoTerms.h:536
void increment_last_auxdim_OBC(const qType &qOut)
Definition: MpoTerms.h:2363
std::vector< std::pair< qType, std::size_t > > base_order_IBC(const std::size_t power=1) const
Definition: MpoTerms.h:4054
SiteOperator< Symmetry, Scalar > OperatorType
Definition: MpoTerms.h:37
std::tuple< std::size_t, std::size_t, std::size_t, std::size_t > auxdim_infos() const
Definition: MpoTerms.h:4187
reversedData reversed
Definition: MpoTerms.h:409
std::vector< qType > calc_qList(const std::vector< OperatorType > &opList)
Definition: MpoTerms.h:962
void increment_auxdim(const std::size_t loc, const qType &q)
Definition: MpoTerms.h:2106
const std::vector< std::vector< qType > > & opBasisSq() const
Definition: MpoTerms.h:720
void increment_first_auxdim_OBC(const qType &qIn)
Definition: MpoTerms.h:2303
void add(const std::size_t loc, const OperatorType &op, const qType &qIn, const qType &qOut, const std::size_t IndexIn, const std::size_t IndexOut)
Definition: MpoTerms.h:2074
void save_label(const std::size_t loc, const std::string &info_label)
Definition: MpoTerms.h:2745
std::vector< std::vector< std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > > > W_powers
Definition: MpoTerms.h:390
void setLocBasis(const std::vector< qType > &q, std::size_t loc)
Definition: MpoTerms.h:716
void initialize()
Definition: MpoTerms.h:742
const std::vector< std::vector< qType > > & opBasis() const
Definition: MpoTerms.h:710
std::map< qType, std::vector< std::map< qType, OperatorType > > > delete_col(const std::size_t loc, const qType &qOut, const std::size_t col_to_delete, const bool SAMESITE)
Definition: MpoTerms.h:2032
qType qTot
Definition: MpoTerms.h:60
BC boundary_condition
Definition: MpoTerms.h:80
const qType & Qtarget() const
Definition: MpoTerms.h:713
std::string label
Definition: MpoTerms.h:615
void add_to_col(const std::size_t loc, const qType &qOut, const std::size_t col, const std::map< qType, std::vector< std::map< qType, OperatorType > > > &ops, const Scalar factor)
Definition: MpoTerms.h:1951
std::size_t get_hilbert_dimension(const std::size_t loc) const
Definition: MpoTerms.h:569
const std::vector< Qbasis< Symmetry > > & auxBasis() const
Definition: MpoTerms.h:705
double sparsity(const std::size_t power=1, const bool PER_MATRIX=false) const
Definition: MpoTerms.h:4342
Definition: Qbasis.h:39
void push_back(const std::tuple< qType, Eigen::Index, std::vector< std::string > > &state)
Definition: Qbasis.h:214
Eigen::Index inner_num(const Eigen::Index &outer_num) const
Definition: Qbasis.h:335
Qbasis< Symmetry > combine(const Qbasis< Symmetry > &other, bool FLIP=false) const
Definition: Qbasis.h:686
Eigen::Index leftOffset(const qType &qnew, const std::array< qType, 2 > &qold, const std::array< Eigen::Index, 2 > &plain_old) const
Definition: Qbasis.h:440
void pullData(const vector< Biped< Symmetry, MatrixType > > &A, const Eigen::Index &leg)
Definition: Qbasis.h:486
void clear()
Definition: Qbasis.h:147
Eigen::Index outer_num(const qType &q) const
Definition: Qbasis.h:378
@ ALTERABLE
Definition: MpoTerms.h:31
@ FINALIZED
Definition: MpoTerms.h:31
Definition: Biped.h:64
std::vector< MatrixType_ > block
Definition: Biped.h:96
std::vector< qType > in
Definition: Biped.h:87
void push_back(qType qin, qType qout, const MatrixType_ &M)
Definition: Biped.h:529
std::size_t dim
Definition: Biped.h:82
std::vector< qType > out
Definition: Biped.h:90
std::vector< Qbasis< Symmetry > > qAux
Definition: MpoTerms.h:405
std::vector< std::vector< std::vector< std::vector< Biped< Symmetry, MatrixType > > > > > W
Definition: MpoTerms.h:404
std::string label
Definition: SiteOperator.h:71
Eigen::SparseMatrix< Scalar_ > data
Definition: SiteOperator.h:41
Symmetry::qType Q
Definition: SiteOperator.h:40