1#ifndef SITEOPERATORQ_H_
2#define SITEOPERATORQ_H_
5#include <unsupported/Eigen/KroneckerProduct>
10#include "numeric_limits.h"
13template<
typename Symmetry,
typename Scalar>
struct SiteOperator;
15template<
typename Operator>
18 typedef typename Operator::qType
qType;
22 EDSolver(
const Operator &Op_in,
const std::vector<qType> &blocks_in={}, Eigen::DecompositionOptions opt_in=Eigen::DecompositionOptions::EigenvaluesOnly)
23 {
compute(Op_in,blocks_in,opt_in);}
25 void compute(
const Operator &Op,
const std::vector<qType> &blocks={}, Eigen::DecompositionOptions opt=Eigen::DecompositionOptions::EigenvaluesOnly);
38template<
typename Operator>
40compute(
const Operator &Op,
const std::vector<qType> &blocks, Eigen::DecompositionOptions opt)
42 eigvals_.data().clear(); eigvecs_.data().clear();
43 eigvals_.Q() = Op.Q(); eigvecs_.Q() = Op.Q();
44 eigvals_.basis() = Op.basis(); eigvecs_.basis() = Op.basis();
46 for(std::size_t nu=0; nu<Op.data().size(); nu++)
48 if(blocks.size()>0) {
if(
auto it = std::find(blocks.begin(),blocks.end(),Op.data().in[nu]); it == blocks.end()) {
continue;} }
49 Mtmp = Op.data().block[nu];
50 Eigen::SelfAdjointEigenSolver<MatrixType> John(Mtmp,opt);
51 eigva = John.eigenvalues();
52 eigvals_.data().push_back(Op.data().in[nu],Op.data().out[nu],eigva);
53 if(opt == Eigen::DecompositionOptions::ComputeEigenvectors)
55 eigve = John.eigenvectors();
56 eigvecs_.data().push_back(Op.data().in[nu],Op.data().out[nu],eigve);
63template<
typename Operator>
67 assert(COMPUTED and
"First diagonalize the operator before accessing the groundstate!");
68 auto all_gs = eigenvectors();
69 Operator out(all_gs.Q(),all_gs.basis());
70 auto it = all_gs.data().dict.find({Q,Q});
71 assert(it != all_gs.data().dict.end() and
"The groundstate to the given Q is not present.");
72 out.data().push_back(all_gs.data().in[it->second],all_gs.data().out[it->second],all_gs.data().block[it->second]);
88template<
typename Symmetry,
typename MatrixType_>
96 typedef typename Symmetry::qType
qType;
98 typedef typename MatrixType::Scalar
Scalar;
144 auto target = Symmetry::reduceSilent(O1.
Q(),O2.
Q());
145 assert(target.size() == 1 and
"Use other outerprod!");
151 typename MatrixType_::Scalar
norm()
const;
153 template<
typename Scalar>
160 std::string
print (
bool PRINT_BASIS=
false)
const;
162 template<
typename OtherScalar>
165 SiteOperatorQ<Symmetry,Eigen::Matrix<OtherScalar, -1, -1 > > Oout;
167 Oout.basis() =
basis();
168 Oout.data() =
data().template
cast<Eigen::Matrix<OtherScalar, -1, -1> >();
169 Oout.label() =
label();
182template<
typename Symmetry,
typename MatrixType_>
186 std::array<qType,2> index = {bra,ket};
187 auto it = data_.dict.find(index);
188 if ( it != data_.dict.end() ) {
return data_.block[it->second]; }
191 Eigen::Index dim1 = basis_.inner_dim(bra);
192 Eigen::Index dim2 = basis_.inner_dim(ket);
194 data_.push_back(index,
A);
195 return data_.block[data_.size()-1];
199template<
typename Symmetry,
typename MatrixType_>
203 std::array<qType,2> index = {bra,ket};
204 auto it = data_.dict.find(index);
205 assert( it != data_.dict.end() and
"The element does not exist in the SiteOperatorQ." );
206 return data_.block[it->second];
209template<
typename Symmetry,
typename MatrixType_>
211operator() (
const std::string& bra,
const std::string& ket )
213 qType bra_ = basis_.find(bra);
214 qType ket_ = basis_.find(ket);
215 std::array<qType,2> index = {bra_,ket_};
216 auto it = data_.dict.find(index);
217 if ( it != data_.dict.end() )
219 Eigen::Index i = basis_.location(bra);
220 Eigen::Index j = basis_.location(ket);
221 if constexpr ( std::is_same<MatrixType_,Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> >::value )
223 return data_.block[it->second](i,j);
225 else if constexpr ( std::is_same<MatrixType_,Eigen::SparseMatrix<Scalar> >::value )
227 return data_.block[it->second].coeffRef(i,j);
232 Eigen::Index dim1 = basis_.inner_dim(bra_);
233 Eigen::Index dim2 = basis_.inner_dim(ket_);
235 Eigen::Index i = basis_.location(bra);
236 Eigen::Index j = basis_.location(ket);
237 data_.push_back(index,
A);
238 if constexpr ( std::is_same<MatrixType_,Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> >::value )
240 return data_.block[data_.size()-1](i,j);
242 else if constexpr ( std::is_same<MatrixType_,Eigen::SparseMatrix<Scalar> >::value )
244 return data_.block[data_.size()-1].coeffRef(i,j);
249template<
typename Symmetry,
typename MatrixType_>
251operator() (
const std::string& bra,
const std::string& ket )
const
253 qType bra_ = basis_.find(bra);
254 qType ket_ = basis_.find(ket);
255 std::array<qType,2> index = {bra_,ket_};
256 auto it = data_.dict.find(index);
257 assert( it != data_.dict.end() and
"The element does not exist in the SiteOperatorQ." );
258 Eigen::Index i = basis_.location(bra);
259 Eigen::Index j = basis_.location(ket);
260 return data_.block[it->second](i,j);
263template<
typename Symmetry,
typename MatrixType_>
265diagonalize (
const std::vector<qType> &blocks, Eigen::DecompositionOptions opt)
const
267 assert(this->Q() == Symmetry::qvacuum() and
"Only a singlet operator can get diagonalized.");
271 for( std::size_t nu=0; nu<this->data().size(); nu++ )
273 if(blocks.size()>0) {
if(
auto it = std::find(blocks.begin(),blocks.end(),this->data().in[nu]); it == blocks.end()) {
continue;} }
274 Mtmp = this->data().block[nu];
275 Eigen::SelfAdjointEigenSolver<MatrixType> John(Mtmp);
276 res = John.eigenvalues().asDiagonal();
277 out.
data().
push_back(this->data().in[nu],this->data().out[nu],res);
282template<
typename Symmetry,
typename MatrixType_>
287 return tmp.data().trace();
290template<
typename Symmetry,
typename MatrixType_>
296 for( std::size_t nu=0; nu<this->data().size(); nu++ )
298 std::array<qType,2> index = {this->data().out[nu],this->data().in[nu]};
300 A *= Symmetry::coeff_adjoint(this->data().in[nu],this->data().out[nu],this->Q());
303 out.
label() = this->label() +
"†";
307template<
typename Symmetry,
typename MatrixType_>
313 for( std::size_t nu=0; nu<this->data().size(); nu++ )
315 std::array<qType,2> index = {this->data().out[nu],this->data().in[nu]};
323template<
typename Symmetry,
typename MatrixType_>
324template<
typename Scalar>
329 MatrixType_ Mtmp(basis().size(), basis().size()); Mtmp.setZero();
330 for(
auto itQ = basis().cbegin(); itQ != basis().cend(); itQ++ )
332 auto [qVal,qNum,qPlain] = *itQ;
333 for(
auto itP = basis().cbegin(); itP != basis().cend(); itP++ )
335 auto [pVal,pNum,pPlain] = *itP;
336 if(
auto it = data().dict.find({{qVal,pVal}}); it != data().dict.end() )
338 Mtmp.block(qNum,pNum,qPlain.size(),pPlain.size()) = data().block[it->second];
350 out.
data = Mtmp.sparseView();
352 out.
label = this->label();
391template<
typename Symmetry,
typename MatrixType_>
395 for(
const auto& q : basis().qloc())
401template<
typename Symmetry,
typename MatrixType_>
405 for(
const auto& q : basis().qloc())
407 (*this)(q,q).setIdentity();
411template<
typename Symmetry,
typename MatrixType_>
415 for(
const auto& q : basis().qloc())
417 (*this)(q,q).setRandom();
421template<
typename Symmetry,
typename MatrixType_>
425 std::array<qType,3> checkIndex = {O1.
Q(),O2.
Q(),target};
426 assert( Symmetry::validate(checkIndex) and
"Operators O1 and O2 cannot get multplied to a quantum number target operator" );
427 assert( O1.
basis() == O2.
basis() and
"For a prod() operation the two operators need to have the same basis" );
431 std::array<qType,2> totIndex, index;
434 for ( std::size_t nu=0; nu<O1.
data().size(); nu++ )
436 auto qvec = Symmetry::reduceSilent(O1.
data().
out[nu],Symmetry::flip(O2.
Q()));
437 for (
const auto& q : qvec)
440 auto it = O2.
data().
dict.find(index);
441 if (it == O2.
data().
dict.end()) {
continue;}
442 std::size_t mu = it->second;
443 factor_cgc = Symmetry::coeff_prod( O1.
data().
in[nu], O1.
Q(), O1.
data().
out[nu],
447 if ( std::abs(factor_cgc) < std::abs(::mynumeric_limits<Scalar>::epsilon()) ) {
continue; }
451 auto check = out.
data().
dict.find(totIndex);
452 if ( check == out.
data().
dict.end() )
456 else { out.
data().
block[check->second] +=
A; }
490 out.
label() = ss.str();
495template<
typename Symmetry,
typename MatrixType_>
499 std::array<qType,3> checkIndex = {O1.
Q(),O2.
Q(),target};
500 assert(Symmetry::validate(checkIndex) and
"Operators O1 and O2 cannot get multiplied to an operator with quantum number = target");
502 auto TensorBasis = O1.
basis().combine(O2.
basis());
506 std::array<qType,2> totIndex;
511 for (std::size_t nu=0; nu<O1.
data().size(); nu++)
512 for (std::size_t mu=0; mu<O2.
data().size(); mu++)
514 auto reduce1 = Symmetry::reduceSilent(O1.
data().
in[nu], O2.
data().
in[mu]);
515 auto reduce2 = Symmetry::reduceSilent(O1.
data().
out[nu], O2.
data().
out[mu]);
516 for (
const auto& q1:reduce1)
517 for (
const auto& q2:reduce2)
519 factor_cgc = Symmetry::coeff_tensorProd(O1.
data().
out[nu], O2.
data().
out[mu], q2,
520 O1.
Q(), O2.
Q(), target,
522 if (std::abs(factor_cgc) < ::mynumeric_limits<Scalar>::epsilon()) {
continue;}
523 totIndex = { q1, q2 };
526 Atmp.resize(rows,cols);
529 Index left1 = TensorBasis.leftAmount (q1,{O1.
data().in[nu], O2.
data().
in[mu]});
530 Index right1 = TensorBasis.rightAmount(q1,{O1.
data().in[nu], O2.
data().
in[mu]});
531 Index left2 = TensorBasis.leftAmount (q2,{O1.
data().out[nu], O2.
data().
out[mu]});
532 Index right2 = TensorBasis.rightAmount(q2,{O1.
data().out[nu], O2.
data().
out[mu]});
533 A.resize(rows+left1+right1,cols+left2+right2);
A.setZero();
534 A.block(left1,left2,rows,cols) = Atmp;
536 auto it = out.
data().
dict.find(totIndex);
543 out.
data().
block[it->second] += factor_cgc *
A;
549 out.
label() = ss.str();
553template<
typename Symmetry,
typename MatrixType_>
560template<
typename Symmetry,
typename MatrixType_>
567template<
typename Symmetry,
typename MatrixType_>
569print(
bool PRINT_BASIS)
const
571 std::stringstream out;
572 out <<
"Operator " << label() << endl;
573 if (PRINT_BASIS) {out << basis() << endl;}
574 out << data().print(
true) << endl;
578template<
typename Symmetry,
typename MatrixType_>
586template<
typename Symmetry,
typename MatrixType_>
589 auto Qtots = Symmetry::reduceSilent(O1.
Q(), O2.
Q());
590 assert(Qtots.size() == 1 and
"The operator * for SiteOperatorQ can only be used uf the target quantumnumber is unique. Use SiteOperatorQ::prod() insteat.");
595template<
typename Symmetry,
typename MatrixType_>
598 assert(O1.
basis() == O2.
basis() and
"For addition of SiteOperatorQs the basis needs to be the same.");
599 assert(O1.
Q() == O2.
Q() and
"For addition of SiteOperatorQs the operator quantum number needs to be the same.");
603 ss <<
"(" << O1.
label() <<
"+" << O2.
label() <<
")";
604 out.
label() = ss.str();
609template<
typename Symmetry,
typename MatrixType_>
612 assert(O1.
basis() == O2.
basis() and
"For subtraction of SiteOperatorQs the basis needs to be the same.");
613 assert(O1.
Q() == O2.
Q() and
"For subtraction of SiteOperatorQs the operator quantum number needs to be the same.");
617 ss <<
"(" << O1.
label() <<
"-" << O2.
label() <<
")";
618 out.
label() = ss.str();
622template<
typename Symmetry,
typename MatrixType_>
628template<
typename Symmetry,
typename MatrixType_>
631 os << Op.
print(
true);
void setZero(PivotVector< Symmetry, Scalar_ > &V)
SiteOperatorQ< Symmetry, MatrixType_ > operator*(const typename MatrixType_::Scalar &s, const SiteOperatorQ< Symmetry, MatrixType_ > &op)
std::ostream & operator<<(std::ostream &os, const SiteOperatorQ< Symmetry, MatrixType_ > &Op)
SiteOperatorQ< Symmetry, MatrixType_ > kroneckerProduct(const SiteOperatorQ< Symmetry, MatrixType_ > &O1, const SiteOperatorQ< Symmetry, MatrixType_ > &O2)
SiteOperatorQ< Symmetry, MatrixType_ > operator+(const SiteOperatorQ< Symmetry, MatrixType_ > &O1, const SiteOperatorQ< Symmetry, MatrixType_ > &O2)
SiteOperatorQ< Symmetry, MatrixType_ > operator-(const SiteOperatorQ< Symmetry, MatrixType_ > &O1, const SiteOperatorQ< Symmetry, MatrixType_ > &O2)
void compute(const Operator &Op, const std::vector< qType > &blocks={}, Eigen::DecompositionOptions opt=Eigen::DecompositionOptions::EigenvaluesOnly)
const Operator & eigenvalues() const
const Operator & eigenvectors() const
EDSolver(const Operator &Op_in, const std::vector< qType > &blocks_in={}, Eigen::DecompositionOptions opt_in=Eigen::DecompositionOptions::EigenvaluesOnly)
Operator::MatrixType MatrixType
Operator groundstate(qType Q) const
SiteOperatorQ< Symmetry, MatrixType_ > diagonalize(const std::vector< qType > &blocks={}, Eigen::DecompositionOptions opt=Eigen::DecompositionOptions::EigenvaluesOnly) const
SiteOperatorQ(const qType &Q_in, const Qbasis< Symmetry > &basis_in, const base &data_in)
MatrixType_::Scalar norm() const
static SiteOperatorQ< Symmetry, MatrixType_ > outerprod(const SiteOperatorQ< Symmetry, MatrixType_ > &O1, const SiteOperatorQ< Symmetry, MatrixType_ > &O2)
std::string print(bool PRINT_BASIS=false) const
const Qbasis< Symmetry > & basis() const
SiteOperator< Symmetry, Scalar > plain() const
SiteOperatorQ< Symmetry, Eigen::Matrix< OtherScalar, -1, -1 > > cast() const
SiteOperatorQ< Symmetry, MatrixType_ > & operator+=(const SiteOperatorQ< Symmetry, MatrixType_ > &Op)
static SiteOperatorQ< Symmetry, MatrixType_ > prod(const SiteOperatorQ< Symmetry, MatrixType_ > &O1, const SiteOperatorQ< Symmetry, MatrixType_ > &O2, const qType &target)
SiteOperatorQ< Symmetry, MatrixType_ > hermitian_conj() const
const std::string & label() const
SiteOperatorQ< Symmetry, MatrixType_ > adjoint() const
const base & data() const
SiteOperatorQ(const qType &Q_in, const Qbasis< Symmetry > &basis_in, std::string label_in="")
Qbasis< Symmetry > basis_
SiteOperatorQ< Symmetry, MatrixType_ > & operator-=(const SiteOperatorQ< Symmetry, MatrixType_ > &Op)
static SiteOperatorQ< Symmetry, MatrixType_ > outerprod(const SiteOperatorQ< Symmetry, MatrixType_ > &O1, const SiteOperatorQ< Symmetry, MatrixType_ > &O2, const qType &target)
Qbasis< Symmetry > & basis()
MatrixType::Scalar Scalar
MatrixType operator()(const qType &bra, const qType &ket) const
Biped< Symmetry, MatrixType_ > base
std::unordered_map< std::array< qType, 2 >, std::size_t > dict
std::vector< MatrixType_ > block
void push_back(qType qin, qType qout, const MatrixType_ &M)
Eigen::SparseMatrix< Scalar_ > data