https://github.com/ITensor/ITensor
Tip revision: 5c026b64ac7a623739d814f46158b8e029091211 authored by Matthew Fishman on 16 August 2019, 21:23:30 UTC
Add partial direct sum of ITensors
Add partial direct sum of ITensors
Tip revision: 5c026b6
itensor_test.cc
#include "test.h"
#include "itensor/itensor.h"
#include "itensor/util/cplx_literal.h"
#include "itensor/util/iterate.h"
#include "itensor/util/set_scoped.h"
#include "itensor/util/print_macro.h"
#include <cstdlib>
using namespace std;
using namespace itensor;
struct CalcNrm
{
Real & nrm;
CalcNrm(Real & nrm_) : nrm(nrm_) { }
template<typename T>
void
operator()(T el) { nrm += std::norm(el); }
};
class Functor
{
public:
template<typename T>
T
operator()(T x) const
{
return x*x;
}
};
enum class Type {
NoType,
DenseReal,
DenseCplx,
DiagReal,
DiagRealAllSame,
DiagCplx,
DiagCplxAllSame,
Combiner,
QDenseReal
};
Type
typeOf(ITensor const& t)
{
struct GetType
{
Type operator()(DenseReal const& d) { return Type::DenseReal; }
Type operator()(DenseCplx const& d) { return Type::DenseCplx; }
Type operator()(Diag<Real> const& d) { return d.allSame() ? Type::DiagRealAllSame : Type::DiagReal; }
Type operator()(Diag<Cplx> const& d) { return d.allSame() ? Type::DiagCplxAllSame : Type::DiagCplx; }
Type operator()(Combiner const& d) { return Type::Combiner; }
Type operator()(QDenseReal const& d) { return Type::QDenseReal; }
};
return applyFunc(GetType{},t.store());
}
std::ostream&
operator<<(std::ostream& s, Type t)
{
if(t == Type::NoType) s << "NoType";
else if(t == Type::DenseReal) s << "DenseReal";
else if(t == Type::DenseCplx) s << "DenseCplx";
else if(t == Type::DiagReal) s << "DiagReal";
else if(t == Type::DiagRealAllSame) s << "DiagRealAllSame";
else if(t == Type::DiagCplx) s << "DiagCplx";
else if(t == Type::DiagCplxAllSame) s << "DiagCplxAllSame";
else if(t == Type::Combiner) s << "Combiner";
else if(t == Type::QDenseReal) s << "QDenseReal";
else Error("Unrecognized Type value");
return s;
}
std::vector<Real>
randomData(size_t size)
{
std::vector<Real> data(size);
for(auto& el : data) el = Global::random();
return data;
}
TEST_CASE("ITensor")
{
Index s1(2,"Site");
Index s2(2,"s2,Site");
Index s3(2,"s3,Site");
Index s4(2,"s4,Site");
Index l1(2,"l1,Link");
Index l2(2,"l2,Link");
Index l3(2,"l3,Link");
Index l4(2,"l4,Link");
Index l5(2,"l5,Link");
Index l6(2,"l6,Link");
Index l7(2,"l7,Link");
Index l8(2,"l8,Link");
Index a1(1,"a1,Link");
Index a2(1,"a2,Link");
Index a3(1,"a3,Link");
Index a4(1,"a4,Link");
Index b2(2,"b2,Link");
Index b3(3,"b3,Link");
Index b4(4,"b4,Link");
Index b5(5,"b5,Link");
Index b6(6,"b6,Link");
Index b7(7,"b7,Link");
Index b8(8,"b8,Link");
Index J(10,"J,Link"),
K(10,"K,Link"),
L(10,"L,Link"),
M(10,"M,Link");
auto S1 = Index(QN(-1),1,
QN(+1),1,"S1,Site");
auto S2 = Index(QN(-1),1,
QN(+1),1,"S2,Site");
auto S3 = Index(QN(-1),1,
QN(+1),1,"S3,Site");
auto S4 = Index(QN(-1),1,
QN(+1),1,"S4,Site");
auto L1 = Index(QN(+1),2,
QN( 0),2,
QN(-1),2,"L1,Link");
auto L2 = Index(QN(+2),2,
QN( 0),2,
QN(-2),2,"L2,Link");
IndexSet mixed_inds(a2,b3,l1,l2,a4,l4);
ITensor A,
B,
X,
Z;
{
auto s1p = prime(s1);
A = ITensor(s1,prime(s1));
A.set(s1(1),s1p(1),11);
A.set(s1(1),s1p(2),12);
A.set(s1(2),s1p(1),21);
A.set(s1(2),s1p(2),22);
}
{
B = ITensor(s1,s2);
B.set(s1(1),s2(1),110);
B.set(s1(1),s2(2),120);
B.set(s1(2),s2(1),210);
B.set(s1(2),s2(2),220);
}
{
X = ITensor(s1,s2);
X.set(s1(1),s2(2),1);
X.set(s1(2),s2(1),1);
}
{
Z = ITensor(s1,s2);
Z.set(s1(1),s2(1),1);
Z.set(s1(2),s2(2),1);
}
SECTION("Boolean")
{
ITensor t1;
CHECK(!t1);
ITensor t2(s1);
CHECK(t2);
}
SECTION("Constructors")
{
SECTION("Rank 1")
{
ITensor t1(l1);
//CHECK(typeOf(t1) == DenseReal);
CHECK_EQUAL(t1.r(),1);
CHECK(hasIndex(t1,l1));
//CHECK_DIFF(norm(t1),0,1E-10);
}
SECTION("Rank 2")
{
ITensor t2(l1,l2);
//CHECK(typeOf(t2) == DenseReal);
CHECK_EQUAL(t2.r(),2);
CHECK(hasIndex(t2,l1));
CHECK(hasIndex(t2,l2));
//CHECK_DIFF(norm(t2),0,1E-10);
}
SECTION("Rank 3")
{
ITensor t3(l1,l2,l3);
CHECK_EQUAL(t3.r(),3);
CHECK(hasIndex(t3,l1));
CHECK(hasIndex(t3,l2));
CHECK(hasIndex(t3,l3));
//CHECK_DIFF(norm(t3),0,1E-10);
}
SECTION("Rank 4")
{
ITensor t4(a1,l1);
CHECK_EQUAL(t4.r(),2);
CHECK(hasIndex(t4,a1));
CHECK(hasIndex(t4,l1));
//CHECK_DIFF(norm(t4),0,1E-10);
}
SECTION("Rank 5")
{
ITensor t5(l1,a1,l2);
CHECK_EQUAL(t5.r(),3);
CHECK(hasIndex(t5,a1));
CHECK(hasIndex(t5,l1));
CHECK(hasIndex(t5,l2));
//CHECK_DIFF(norm(t5),0,1E-10);
}
SECTION("Rank 6")
{
ITensor t6(l1,a1,l2,a2);
CHECK_EQUAL(t6.r(),4);
CHECK(hasIndex(t6,l1));
CHECK(hasIndex(t6,a1));
CHECK(hasIndex(t6,l2));
CHECK(hasIndex(t6,a2));
//CHECK_DIFF(norm(t6),0,1E-10);
}
SECTION("Rank 7")
{
ITensor t7(l1,l2);
Real a = -0.83;
t7.fill(a);
CHECK_EQUAL(t7.r(),2);
CHECK(hasIndex(t7,l1));
CHECK(hasIndex(t7,l2));
CHECK_DIFF(elt(t7,l1(1),l2(1)),a,1E-5);
CHECK_DIFF(elt(t7,l1(1),l2(2)),a,1E-5);
CHECK_DIFF(elt(t7,l1(2),l2(1)),a,1E-5);
CHECK_DIFF(elt(t7,l1(2),l2(2)),a,1E-5);
t7.set(l1(2),l2(2),1.5);
CHECK_DIFF(elt(t7,l1(2),l2(2)),1.5,1E-5);
}
SECTION("Real Scalar")
{
Real b = -1*Global::random();
ITensor t9(b);
CHECK_CLOSE(sumels(t9),b);
CHECK_CLOSE(norm(t9),fabs(b));
}
SECTION("Dense Rank 1 from container")
{
Index linkind(10,"linkind");
auto data = randomData(linkind.dim());
auto t10 = diagITensor(data,linkind);
CHECK_EQUAL(t10.r(),1);
CHECK(hasIndex(t10,linkind));
Real tot = 0;
for(auto& el : data) tot += el;
CHECK_DIFF(sumels(t10),tot,1E-10);
Real chknrm = 0;
for(auto el : data) chknrm += el*el;
CHECK_DIFF(norm(t10),std::sqrt(chknrm),1E-10);
}
SECTION("Diag Rank 2 from container")
{
Index i1(10,"i1"),
i2(10,"i2");
auto data = randomData(i1.dim());
auto T = diagITensor(data,i1,i2);
CHECK(typeOf(T) == Type::DiagReal);
CHECK_EQUAL(T.r(),2);
CHECK(hasIndex(T,i1));
CHECK(hasIndex(T,i2));
Real tot = 0,
nrm = 0;
for(auto& el : data) tot += el, nrm += el*el;
CHECK_DIFF(norm(T),std::sqrt(nrm),1E-10);
CHECK_DIFF(sumels(T),tot,1E-10);
}
}
SECTION("Write to Disk")
{
auto fname = "_write_test";
SECTION("Dense Real Storage")
{
auto T = randomITensor(s1,s2);
writeToFile(fname,T);
auto nT = readFromFile<ITensor>(fname);
CHECK(typeOf(nT) == Type::DenseReal);
CHECK(norm(T-nT) < 1E-12);
}
SECTION("Dense Cplx Storage")
{
auto T = randomITensorC(s1,s2);
writeToFile(fname,T);
auto nT = readFromFile<ITensor>(fname);
CHECK(typeOf(nT) == Type::DenseCplx);
CHECK(norm(T-nT) < 1E-12);
}
SECTION("Combiner Storage")
{
auto [C,ci] = combiner(s1,s2);
CHECK(hasIndex(C,ci));
writeToFile(fname,C);
auto nC = readFromFile<ITensor>(fname);
CHECK(hasIndex(nC,s1));
CHECK(hasIndex(nC,s2));
CHECK(typeOf(nC) == Type::Combiner);
}
SECTION("DiagRealAllSame Storage")
{
auto T = delta(s1,s2);
writeToFile(fname,T);
auto nT = readFromFile<ITensor>(fname);
CHECK(typeOf(nT) == Type::DiagRealAllSame);
}
SECTION("QDense Real Storage")
{
auto i = Index(QN(0),2,QN(-1),2,In,"i,Site");
auto j = Index(QN(0),2,QN(-1),3,Out,"j,Site");
auto T = randomITensor(QN(0),i,j);
writeToFile(fname,T);
auto nT = readFromFile<ITensor>(fname);
CHECK(typeOf(nT) == Type::QDenseReal);
CHECK(norm(T-nT) < 1E-12);
}
std::system(format("rm -f %s",fname).c_str());
}
SECTION("Set and Get Elements")
{
auto T = ITensor(s1,s2);
T.set(s1(1),s2(1),11);
T.set(s1(1),s2(2),12);
T.set(s1(2),s2(1),21);
T.set(s1(2),s2(2),22);
CHECK(!isComplex(T));
CHECK_CLOSE(elt(T,s1(1),s2(1)),11);
CHECK_CLOSE(elt(T,s1(1),s2(2)),12);
CHECK_CLOSE(elt(T,s1(2),s2(1)),21);
CHECK_CLOSE(elt(T,s1(2),s2(2)),22);
T.set(s2(2),s1(1),3);
CHECK_CLOSE(elt(T,s1(1),s2(2)),3);
T.set(s2(2),s1(1),3+5_i);
CHECK(isComplex(T));
CHECK_CLOSE(eltC(T,s1(1),s2(2)),3+5_i);
}
SECTION("Set and Get Elements Using int")
{
auto T = ITensor(s1,s2);
T.set(1,1,11);
T.set(1,2,12);
T.set(2,1,21);
T.set(2,2,22);
CHECK(!isComplex(T));
CHECK_CLOSE(elt(T,s1(1),s2(1)),11);
CHECK_CLOSE(elt(T,s1(1),s2(2)),12);
CHECK_CLOSE(elt(T,s1(2),s2(1)),21);
CHECK_CLOSE(elt(T,s1(2),s2(2)),22);
CHECK_CLOSE(elt(T,1,1),11);
CHECK_CLOSE(elt(T,1,2),12);
CHECK_CLOSE(elt(T,2,1),21);
CHECK_CLOSE(elt(T,2,2),22);
T.set(2,1,3+5_i);
CHECK(isComplex(T));
CHECK_CLOSE(eltC(T,s1(2),s2(1)),3+5_i);
CHECK_CLOSE(eltC(T,2,1),3+5_i);
}
SECTION("Set and Get Elements Using long int")
{
auto T = ITensor(s1,s2);
long int i1 = 1,
i2 = 2;
T.set(i1,i1,11);
T.set(1,i2,12);
T.set(i2,1,21);
T.set(i2,2,22);
CHECK(!isComplex(T));
CHECK_CLOSE(elt(T,s1(1),s2(1)),11);
CHECK_CLOSE(elt(T,s1(1),s2(2)),12);
CHECK_CLOSE(elt(T,s1(2),s2(1)),21);
CHECK_CLOSE(elt(T,s1(2),s2(2)),22);
CHECK_CLOSE(elt(T,i1,i1),11);
CHECK_CLOSE(elt(T,i1,2),12);
CHECK_CLOSE(elt(T,2,i1),21);
CHECK_CLOSE(elt(T,i2,2),22);
T.set(i2,i1,3+5_i);
CHECK(isComplex(T));
CHECK_CLOSE(eltC(T,s1(2),s2(1)),3+5_i);
CHECK_CLOSE(eltC(T,i2,i1),3+5_i);
}
SECTION("Set Using vector<IndexVal>")
{
auto T = ITensor(s1,s2);
auto v12 = vector<IndexVal>{{s2(2),s1(1)}};
T.set(v12,12);
auto v21 = vector<IndexVal>{{s1(2),s2(1)}};
T.set(v21,21);
CHECK_CLOSE(elt(T,s1(1),s2(2)),12);
CHECK_CLOSE(elt(T,s1(2),s2(1)),21);
CHECK_CLOSE(elt(T,vector<IndexVal>({s1(1),s2(2)})),12);
CHECK_CLOSE(elt(T,vector<IndexVal>({s1(2),s2(1)})),21);
}
SECTION("Set and Get Using vector<int>")
{
auto T = ITensor(s1,s2);
auto v12 = vector<int>{{1,2}};
T.set(v12,12);
auto v21 = vector<int>{{2,1}};
T.set(v21,21);
CHECK_CLOSE(elt(T,s1(1),s2(2)),12);
CHECK_CLOSE(elt(T,s1(2),s2(1)),21);
CHECK_CLOSE(elt(T,vector<int>{{1,2}}),12);
CHECK_CLOSE(elt(T,vector<int>{{2,1}}),21);
}
SECTION("IndexValConstructors")
{
SECTION("Rank 1")
{
auto t1 = setElt(l1(2));
CHECK_EQUAL(t1.r(),1);
CHECK(hasIndex(t1,l1));
CHECK_DIFF(elt(t1,l1(1)),0,1E-10);
CHECK_DIFF(elt(t1,l1(2)),1,1E-10);
CHECK_DIFF(sumels(t1),1,1E-10);
CHECK_DIFF(norm(t1),1,1E-10);
}
SECTION("Rank 2")
{
auto t2 = setElt(l1(2),l2(1));
CHECK_EQUAL(t2.r(),2);
CHECK(hasIndex(t2,l1));
CHECK(hasIndex(t2,l2));
CHECK_DIFF(elt(t2,l1(1),l2(1)),0,1E-10);
CHECK_DIFF(elt(t2,l1(1),l2(2)),0,1E-10);
CHECK_DIFF(elt(t2,l1(2),l2(1)),1,1E-10);
CHECK_DIFF(elt(t2,l1(2),l2(2)),0,1E-10);
CHECK_DIFF(sumels(t2),1,1E-10);
CHECK_DIFF(norm(t2),1,1E-10);
auto u2a = setElt(a1(1),l2(2));
CHECK_EQUAL(u2a.r(),2);
CHECK(hasIndex(u2a,a1));
CHECK(hasIndex(u2a,l2));
CHECK_DIFF(elt(u2a,a1(1),l2(1)),0,1E-10);
CHECK_DIFF(elt(u2a,a1(1),l2(2)),1,1E-10);
CHECK_DIFF(sumels(u2a),1,1E-10);
CHECK_DIFF(norm(u2a),1,1E-10);
auto u2b = setElt(l1(2),a2(1));
CHECK_EQUAL(u2b.r(),2);
CHECK(hasIndex(u2b,l1));
CHECK(hasIndex(u2b,a2));
CHECK_DIFF(elt(u2b,l1(1),a2(1)),0,1E-10);
CHECK_DIFF(elt(u2b,l1(2),a2(1)),1,1E-10);
CHECK_DIFF(sumels(u2b),1,1E-10);
CHECK_DIFF(norm(u2b),1,1E-10);
}
SECTION("Rank 3")
{
auto t3 = setElt(l1(2),l3(1),l2(1));
CHECK_EQUAL(t3.r(),3);
CHECK(hasIndex(t3,l1));
CHECK(hasIndex(t3,l2));
CHECK(hasIndex(t3,l3));
CHECK_DIFF(t3.elt(l1(1),l3(1),l2(1)),0,1E-10);
CHECK_DIFF(t3.elt(l1(2),l3(1),l2(1)),1,1E-10);
CHECK_DIFF(t3.elt(l1(1),l3(2),l2(1)),0,1E-10);
CHECK_DIFF(t3.elt(l1(2),l3(2),l2(2)),0,1E-10);
CHECK_DIFF(t3.elt(l1(1),l3(1),l2(2)),0,1E-10);
CHECK_DIFF(t3.elt(l1(2),l3(1),l2(2)),0,1E-10);
CHECK_DIFF(t3.elt(l1(1),l3(2),l2(2)),0,1E-10);
CHECK_DIFF(t3.elt(l1(2),l3(2),l2(2)),0,1E-10);
CHECK_DIFF(sumels(t3),1,1E-10);
CHECK_DIFF(norm(t3),1,1E-10);
auto t4 = setElt(a1(1),l3(2),l2(1));
CHECK_EQUAL(t4.r(),3);
CHECK(hasIndex(t4,a1));
CHECK(hasIndex(t4,l2));
CHECK(hasIndex(t4,l3));
CHECK_DIFF(t4.elt(l3(1),l2(1),a1(1)),0,1E-10);
CHECK_DIFF(t4.elt(l3(1),l2(2),a1(1)),0,1E-10);
CHECK_DIFF(t4.elt(l3(2),l2(1),a1(1)),1,1E-10);
CHECK_DIFF(t4.elt(l3(2),l2(2),a1(1)),0,1E-10);
CHECK_DIFF(sumels(t4),1,1E-10);
CHECK_DIFF(norm(t4),1,1E-10);
}
SECTION("Rank 4")
{
auto r4 = setElt(l1(1),l3(1),l2(2),l4(1));
CHECK_EQUAL(r4.r(),4);
CHECK(hasIndex(r4,l1));
CHECK(hasIndex(r4,l2));
CHECK(hasIndex(r4,l3));
CHECK(hasIndex(r4,l4));
CHECK_DIFF(r4.elt(l1(1),l3(1),l2(2),l4(1)),1,1E-10);
CHECK_DIFF(sumels(r4),1,1E-10);
CHECK_DIFF(norm(r4),1,1E-10);
}
SECTION("Rank 8")
{
auto t8 = setElt(l1(1),l2(2),l3(1),l4(2),l5(1),l6(2),l7(1),l8(2));
CHECK_EQUAL(t8.r(),8);
CHECK(hasIndex(t8,l1));
CHECK(hasIndex(t8,l2));
CHECK(hasIndex(t8,l3));
CHECK(hasIndex(t8,l4));
CHECK(hasIndex(t8,l5));
CHECK(hasIndex(t8,l6));
CHECK(hasIndex(t8,l7));
CHECK(hasIndex(t8,l8));
CHECK_DIFF(t8.elt(l1(1),l2(2),l3(1),l4(2),l5(1),l6(2),l7(1),l8(2)),1,1E-10);
CHECK_DIFF(norm(t8),1,1E-10);
}
}
SECTION("MultiIndexConstructors")
{
auto indices = IndexSet(a2,l3,l1,a4);
ITensor t1(indices);
CHECK_EQUAL(t1.r(),4);
CHECK(hasIndex(t1,a2));
CHECK(hasIndex(t1,l3));
CHECK(hasIndex(t1,l1));
CHECK(hasIndex(t1,a4));
//CHECK_DIFF(norm(t1),0,1E-10);
}
SECTION("Copy")
{
IndexSet indices(a2,l3,l1,a4);
auto t1 = randomITensor(indices);
auto t1nrm = norm(t1);
auto t1sum = sumels(t1);
CHECK_EQUAL(t1.r(),4);
CHECK(hasIndex(t1,a2));
CHECK(hasIndex(t1,l3));
CHECK(hasIndex(t1,l1));
CHECK(hasIndex(t1,a4));
//Use copy constructor
ITensor t2(t1);
t1 = ITensor(); //destroy t1
CHECK_EQUAL(t2.r(),4);
CHECK(hasIndex(t2,a2));
CHECK(hasIndex(t2,l3));
CHECK(hasIndex(t2,l1));
CHECK(hasIndex(t2,a4));
CHECK_DIFF(norm(t2),t1nrm,1E-10);
CHECK_DIFF(sumels(t2),t1sum,1E-10);
//Use operator=
ITensor t3 = t2;
t2 = ITensor(); //destroy t2
CHECK_EQUAL(t3.r(),4);
CHECK(hasIndex(t3,a2));
CHECK(hasIndex(t3,l3));
CHECK(hasIndex(t3,l1));
CHECK(hasIndex(t3,a4));
CHECK_DIFF(norm(t3),t1nrm,1E-10);
CHECK_DIFF(sumels(t3),t1sum,1E-10);
}
SECTION("ScalarMultiply")
{
SECTION("Real")
{
A *= -1;
auto s1P = prime(s1);
CHECK_EQUAL(elt(A,s1(1),s1P(1)),-11);
CHECK_EQUAL(elt(A,s1(1),s1P(2)),-12);
CHECK_EQUAL(elt(A,s1(2),s1P(1)),-21);
CHECK_EQUAL(elt(A,s1(2),s1P(2)),-22);
Real f = Global::random();
A *= -f;
CHECK_DIFF(elt(A,s1(1),s1P(1)),11*f,1E-10);
CHECK_DIFF(elt(A,s1(1),s1P(2)),12*f,1E-10);
CHECK_DIFF(elt(A,s1(2),s1P(1)),21*f,1E-10);
CHECK_DIFF(elt(A,s1(2),s1P(2)),22*f,1E-10);
B /= f;
CHECK_DIFF(elt(B,s1(1),s2(1)),110/f,1E-10);
CHECK_DIFF(elt(B,s1(1),s2(2)),120/f,1E-10);
CHECK_DIFF(elt(B,s1(2),s2(1)),210/f,1E-10);
CHECK_DIFF(elt(B,s1(2),s2(2)),220/f,1E-10);
}
SECTION("Complex Scalar Multiply")
{
CHECK(typeOf(A) == Type::DenseReal);
A *= 1_i;
CHECK(typeOf(A) == Type::DenseCplx);
auto s1P = prime(s1);
CHECK_EQUAL(eltC(A,s1(1),s1P(1)),11_i);
CHECK_EQUAL(eltC(A,s1(1),s1P(2)),12_i);
CHECK_EQUAL(eltC(A,s1(2),s1P(1)),21_i);
CHECK_EQUAL(eltC(A,s1(2),s1P(2)),22_i);
auto T = random(A);
CHECK(typeOf(T) == Type::DenseReal);
CHECK(typeOf(A) == Type::DenseCplx);
T.randomize("Complex");
CHECK(typeOf(T) == Type::DenseCplx);
auto z = 2.2-3.1_i;
auto cT = T;
T *= z;
CHECK_CLOSE(eltC(T,s1(1),s1P(1)),z * eltC(cT,s1(1),s1P(1)));
CHECK_CLOSE(eltC(T,s1(1),s1P(2)),z * eltC(cT,s1(1),s1P(2)));
CHECK_CLOSE(eltC(T,s1(2),s1P(1)),z * eltC(cT,s1(2),s1P(1)));
CHECK_CLOSE(eltC(T,s1(2),s1P(2)),z * eltC(cT,s1(2),s1P(2)));
}
}
SECTION("Apply / Visit / Generate")
{
// class Functor and the function Func
// are defined in test.h
SECTION("Apply Function Obj")
{
ITensor A1(A);
Functor f;
A1.apply(f);
auto s1P = prime(s1);
for(int n1 = 1; n1 <= s1.dim(); ++n1)
for(int n2 = 1; n2 <= s1P.dim(); ++n2)
{
CHECK_DIFF( f( elt(A,s1(n1),s1P(n2)) ), elt(A1,s1(n1),s1P(n2)) ,1E-10);
}
}
SECTION("Apply Real Lambda")
{
//apply a function that only accepts Real argument to real ITensor
auto rfunc = [](Real r) { return 2*r; };
auto T = randomITensor(b4,l2);
T.apply(rfunc);
}
SECTION("Visit Real")
{
//use visitor function that only accepts Real argument to real ITensor
auto T = randomITensor(b4,l2);
Real prod = 1;
T *= 2.; //modify T's scale factor
auto rvfunc = [&prod](Real r) { prod *= r; };
T.visit(rvfunc);
Real prod_check = 1;
for(auto i : range1(b4))
for(auto j : range1(l2))
{
prod_check *= elt(T,b4(i),l2(j));
}
CHECK_CLOSE(prod,prod_check);
}
SECTION("Diag Apply")
{
auto i = Index(4,"i");
auto j = Index(4,"j");
auto vr = vector<Real>{{3.,4.,5.,6.}};
auto vc = vector<Cplx>{{3._i,4.,5._i,6.}};
auto dr = diagITensor(vr,i,j);
auto dc = diagITensor(vc,i,j);
auto frr = [](Real r) { return 2*r; };
auto frc = [](Real r) { return 2_i*r; };
auto fcr = [](Cplx z) { return z.real(); };
auto fcc = [](Cplx z) { return 2*z; };
auto adrr = apply(dr,frr);
CHECK(not isComplex(adrr));
CHECK(norm(2*dr - adrr) < 1E-12);
auto adrc = apply(dr,frc);
CHECK(isComplex(adrc));
CHECK(norm(2_i*dr - adrc) < 1E-12);
auto adcr = apply(dc,fcr);
CHECK(not isComplex(adcr));
CHECK(norm(realPart(dc) - adcr) < 1E-12);
auto adcc = apply(dc,fcc);
CHECK(isComplex(adcc));
CHECK(norm(2*dc - adcc) < 1E-12);
}
SECTION("Diag Visit")
{
auto i = Index(4,"i");
auto j = Index(4,"j");
auto vr = vector<Real>{{3.,4.,5.,6.}};
auto vc = vector<Cplx>{{3._i,4.,5._i,6.}};
auto dr = diagITensor(vr,i,j);
auto dc = diagITensor(vc,i,j);
auto rtot1 = stdx::accumulate(vr,0.);
auto rtot2 = 0.;
auto doTotr = [&rtot2](Real r) { rtot2 += r; };
dr.visit(doTotr);
CHECK_CLOSE(rtot1,rtot2);
auto ctot1 = stdx::accumulate(vc,0._i);
auto ctot2 = 0._i;
auto doTotc = [&ctot2](Cplx c) { ctot2 += c; };
dc.visit(doTotc);
CHECK_CLOSE(ctot1,ctot2);
}
}
SECTION("SumDifference")
{
auto v = randomITensor(mixed_inds),
w = randomITensor(mixed_inds);
Real f1 = -Global::random(),
f2 = 0.1*f1;
ITensor r = f1*v + w/f2;
for(int j1 = 1; j1 <= 2; ++j1)
for(int j2 = 1; j2 <= 2; ++j2)
for(int k3 = 1; k3 <= 3; ++k3)
for(int j4 = 1; j4 <= 2; ++j4)
{
CHECK_CLOSE(elt(r,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)),
f1*elt(v,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))
+ elt(w,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))/f2);
}
ITensor d(v);
d -= w;
for(int j1 = 1; j1 <= 2; ++j1)
for(int j2 = 1; j2 <= 2; ++j2)
for(int k3 = 1; k3 <= 3; ++k3)
for(int j4 = 1; j4 <= 2; ++j4)
{
CHECK_CLOSE(elt(d,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)),
elt(v,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))-elt(w,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)));
}
f1 = 1; f2 = 1;
auto yy = randomITensor(mixed_inds),
zz = randomITensor(mixed_inds);
r = f1*yy + f2*zz;
for(int j1 = 1; j1 <= 2; ++j1)
for(int j2 = 1; j2 <= 2; ++j2)
for(int k3 = 1; k3 <= 3; ++k3)
for(int j4 = 1; j4 <= 2; ++j4)
{
CHECK_CLOSE(elt(r,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)),
f1*elt(yy,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))
+f2*elt(zz,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)));
}
IndexSet reordered(l2,l1,b3,a4,a2,l4);
w = randomITensor(reordered);
r = f1*v + w/f2;
for(int j1 = 1; j1 <= 2; ++j1)
for(int j2 = 1; j2 <= 2; ++j2)
for(int k3 = 1; k3 <= 3; ++k3)
for(int j4 = 1; j4 <= 2; ++j4)
{
CHECK_CLOSE(elt(r,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)),
f1*elt(v,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))
+ elt(w,l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))/f2);
}
SECTION("Reordered Case 2")
{
auto T1 = randomITensor(b6,s1,b5,s2),
T2 = randomITensor(s1,s2,b6,b5);
auto R = T1+T2;
for(int j6 = 1; j6 <= b6.dim(); ++j6)
for(int j5 = 1; j5 <= b5.dim(); ++j5)
for(int k1 = 1; k1 <= s1.dim(); ++k1)
for(int k2 = 1; k2 <= s2.dim(); ++k2)
{
auto val = elt(T1,b6(j6),s1(k1),b5(j5),s2(k2))+elt(T2,b6(j6),s1(k1),b5(j5),s2(k2));
CHECK_CLOSE(elt(R,b6(j6),s1(k1),b5(j5),s2(k2)),val);
}
}
SECTION("Add diag")
{
auto data1 = randomData(std::min(l6.dim(),b4.dim())),
data2 = randomData(std::min(l6.dim(),b4.dim()));
auto v1 = diagITensor(data1,l6,b4),
v2 = diagITensor(data2,b4,l6);
auto r = v1+v2;
for(int j1 = 1; j1 <= 2; ++j1)
for(int j2 = 1; j2 <= 4; ++j2)
{
//printfln("elt(r,l6(%d),b4(%d)) = %.10f",j1,j2,elt(r,l6(j1),b4(j2)));
CHECK_CLOSE(elt(r,l6(j1),b4(j2)),elt(v1,l6(j1),b4(j2))+elt(v2,l6(j1),b4(j2)));
}
}
}
SECTION("Complex SumDifference")
{
SECTION("Complex+-Complex")
{
SECTION("Case 1 - Same Order")
{
auto T1 = randomITensorC(l2,b4,b2);
auto T2 = randomITensorC(l2,b4,b2);
auto R = T1 + T2;
for(auto i2 : range1(l2.dim()))
for(auto j2 : range1(b2.dim()))
for(auto j4 : range1(b4.dim()))
{
CHECK_CLOSE(eltC(R,l2(i2),b2(j2),b4(j4)), eltC(T1,l2(i2),b2(j2),b4(j4))+eltC(T2,l2(i2),b2(j2),b4(j4)));
}
}
SECTION("Case 2 - Different Order")
{
auto T1 = randomITensorC(l2,b4,b2);
auto T2 = randomITensorC(b4,l2,b2);
auto R = T1 + T2;
for(auto i2 : range1(l2.dim()))
for(auto j2 : range1(b2.dim()))
for(auto j4 : range1(b4.dim()))
{
CHECK_CLOSE(eltC(R,l2(i2),b2(j2),b4(j4)), eltC(T1,l2(i2),b2(j2),b4(j4))+eltC(T2,l2(i2),b2(j2),b4(j4)));
}
}
SECTION("Case 3 - Subtract Different Order")
{
auto f1 = Global::random(),
f2 = Global::random();
auto T1 = randomITensorC(l2,b4,b2);
auto T2 = randomITensorC(b4,l2,b2);
auto R = f1*T1 - f2*T2;
for(auto i2 : range1(l2.dim()))
for(auto j2 : range1(b2.dim()))
for(auto j4 : range1(b4.dim()))
{
CHECK_CLOSE(eltC(R,l2(i2),b2(j2),b4(j4)), f1*eltC(T1,l2(i2),b2(j2),b4(j4))-f2*eltC(T2,l2(i2),b2(j2),b4(j4)));
}
}
}
SECTION("Real+-Complex")
{
auto f1 = Global::random(),
f2 = Global::random();
auto T1 = randomITensor(l2,b4,b2);
SECTION("Case 1: Real+Cplx, No Permute")
{
auto T2 = randomITensorC(l2,b4,b2);
//println("Case 1");
auto R = f1*T1 + f2*T2;
for(auto i2 : range1(l2.dim()))
for(auto j2 : range1(b2.dim()))
for(auto j4 : range1(b4.dim()))
{
CHECK_CLOSE(eltC(R,l2(i2),b2(j2),b4(j4)), f1*eltC(T1,l2(i2),b2(j2),b4(j4))+f2*eltC(T2,l2(i2),b2(j2),b4(j4)));
}
}
SECTION("Case 2: Real+Cplx, Permute")
{
auto T2 = randomITensorC(b4,l2,b2);
//println("Case 2");
auto R = f1*T1 + f2*T2;
for(auto i2 : range1(l2.dim()))
for(auto j2 : range1(b2.dim()))
for(auto j4 : range1(b4.dim()))
{
CHECK_CLOSE(eltC(R,l2(i2),b2(j2),b4(j4)), f1*eltC(T1,l2(i2),b2(j2),b4(j4))+f2*eltC(T2,l2(i2),b2(j2),b4(j4)));
}
}
SECTION("Case 3: Cplx+Real, No Permute")
{
auto T2 = randomITensorC(l2,b4,b2);
//println("Case 3");
auto R = f2*T2 + f1*T1;
for(auto i2 : range1(l2.dim()))
for(auto j2 : range1(b2.dim()))
for(auto j4 : range1(b4.dim()))
{
CHECK_CLOSE(eltC(R,l2(i2),b2(j2),b4(j4)), f1*eltC(T1,l2(i2),b2(j2),b4(j4))+f2*eltC(T2,l2(i2),b2(j2),b4(j4)));
}
}
SECTION("Case 4: Cplx+Real, Permute")
{
auto T2 = randomITensorC(b4,l2,b2);
//println("Case 4");
auto R = f2*T2 + f1*T1;
for(auto i2 : range1(l2.dim()))
for(auto j2 : range1(b2.dim()))
for(auto j4 : range1(b4.dim()))
{
CHECK_CLOSE(eltC(R,l2(i2),b2(j2),b4(j4)), f1*eltC(T1,l2(i2),b2(j2),b4(j4))+f2*eltC(T2,l2(i2),b2(j2),b4(j4)));
}
}
SECTION("Case 5: Cplx+Real, Permute")
{
auto T2 = randomITensorC(b2,l2,b4);
//println("Case 5");
auto R = f2*T2 + f1*T1;
for(auto i2 : range1(l2.dim()))
for(auto j2 : range1(b2.dim()))
for(auto j4 : range1(b4.dim()))
{
CHECK_CLOSE(eltC(R,l2(i2),b2(j2),b4(j4)), f1*eltC(T1,l2(i2),b2(j2),b4(j4))+f2*eltC(T2,l2(i2),b2(j2),b4(j4)));
}
}
}
}
SECTION("ContractingProduct")
{
//Check for order 0 ITensors
SECTION("Rank 0")
{
Real f = Global::random();
auto rZ = ITensor(f);
auto T = randomITensor(b2,a1,b4);
auto res = rZ * T;
CHECK_EQUAL(rZ.r(),0);
CHECK_EQUAL(res.r(),3);
for(int j2 = 1; j2 <= 2; ++j2)
for(int j4 = 1; j4 <= 4; ++j4)
{
Real val = f * elt(T,b2(j2),a1(1),b4(j4));
CHECK_CLOSE(elt(res,b2(j2),a1(1),b4(j4)),val);
}
}
auto L = randomITensor(b4,a1,b3,a2,b2),
R = randomITensor(b5,a1,b4,b2,b3);
SECTION("Case 1")
{
Real fL = Global::random(),
fR = Global::random();
auto Lf = L * fL;
auto Rf = R * fR;
auto res1 = Lf*Rf;
CHECK(hasIndex(res1,b5));
CHECK(hasIndex(res1,a2));
CHECK(!hasIndex(res1,a1));
CHECK(!hasIndex(res1,b2));
CHECK(!hasIndex(res1,b3));
CHECK(!hasIndex(res1,b4));
CHECK_EQUAL(res1.r(),2);
for(int j5 = 1; j5 <= b5.dim(); ++j5)
{
Real val = 0;
for(int j2 = 1; j2 <= 2; ++j2)
for(int j3 = 1; j3 <= 3; ++j3)
for(int j4 = 1; j4 <= 4; ++j4)
{
val += elt(L,a2(1),b2(j2),a1(1),b3(j3),b4(j4))*fL * elt(R,b5(j5),a1(1),b3(j3),b2(j2),b4(j4))*fR;
}
CHECK_DIFF(res1.elt(a2(1),b5(j5)),val,1E-10);
}
}
SECTION("Case 2")
{
auto res2 = R*L;
CHECK(hasIndex(res2,b5));
CHECK(hasIndex(res2,a2));
CHECK(!hasIndex(res2,a1));
CHECK(!hasIndex(res2,b2));
CHECK(!hasIndex(res2,b3));
CHECK(!hasIndex(res2,b4));
CHECK_EQUAL(res2.r(),2);
for(int j5 = 1; j5 <= b5.dim(); ++j5)
{
Real val = 0;
for(int j2 = 1; j2 <= 2; ++j2)
for(int j3 = 1; j3 <= 3; ++j3)
for(int j4 = 1; j4 <= 4; ++j4)
{
val += elt(L,a2(1),b2(j2),a1(1),b3(j3),b4(j4)) * elt(R,b5(j5),a1(1),b3(j3),b2(j2),b4(j4));
}
CHECK_DIFF(res2.elt(a2(1),b5(j5)),val,1E-10);
}
}
ITensor Q = randomITensor(a1,b4,a2,b2),
P = randomITensor(a2,a3,a1);
Real fQ = Global::random(),
fP = Global::random();
auto Qf = Q * fQ;
auto Pf = P * fP;
SECTION("Case 3")
{
auto res3 = Qf*Pf;
CHECK(hasIndex(res3,b4));
CHECK(hasIndex(res3,b2));
CHECK(hasIndex(res3,a3));
CHECK(!hasIndex(res3,a1));
CHECK(!hasIndex(res3,a2));
CHECK_EQUAL(res3.r(),3);
for(int j2 = 1; j2 <= b2.dim(); ++j2)
for(int j4 = 1; j4 <= b4.dim(); ++j4)
{
auto val = elt(Q,a1(1),b4(j4),a2(1),b2(j2))*fQ * elt(P,a2(1),a3(1),a1(1))*fP;
CHECK_DIFF(res3.elt(a3(1),b4(j4),b2(j2)),val,1E-10);
}
}
SECTION("Case 4")
{
auto res4 = Pf*Qf;
CHECK(hasIndex(res4,b4));
CHECK(hasIndex(res4,b2));
CHECK(hasIndex(res4,a3));
CHECK(!hasIndex(res4,a1));
CHECK(!hasIndex(res4,a2));
CHECK_EQUAL(res4.r(),3);
for(int j2 = 1; j2 <= 2; ++j2)
for(int j4 = 1; j4 <= 4; ++j4)
{
auto val = elt(Q,a1(1),b4(j4),a2(1),b2(j2))*fQ * elt(P,a2(1),a3(1),a1(1))*fP;
CHECK_DIFF(res4.elt(a3(1),b4(j4),b2(j2)),val,1E-10);
}
}
SECTION("Case 5")
{
auto psi = randomITensor(a1,a2,a3),
mpoh = randomITensor(l2,a1,prime(a1),a2,prime(a2));
auto Hpsi = mpoh * psi;
CHECK_EQUAL(Hpsi.r(),4);
CHECK(hasIndex(Hpsi,l2));
CHECK(hasIndex(Hpsi,prime(a1)));
CHECK(hasIndex(Hpsi,prime(a2)));
CHECK(hasIndex(Hpsi,a3));
CHECK(!hasIndex(Hpsi,a1));
CHECK(!hasIndex(Hpsi,a2));
}
SECTION("Case 6")
{
auto T1 = randomITensor(b3,b5,l6,a1,s3),
T2 = randomITensor(l6,s4,b3,a1);
auto R = T1*T2;
for(int j5 = 1; j5 <= 5; ++j5)
for(int i3 = 1; i3 <= 2; ++i3)
for(int i4 = 1; i4 <= 2; ++i4)
{
Real val = 0;
for(int j3 = 1; j3 <= 3; ++j3)
for(int k6 = 1; k6 <= 2; ++k6)
{
val += elt(T1,a1(1),b3(j3),b5(j5),l6(k6),s3(i3)) * elt(T2,a1(1),l6(k6),s4(i4),b3(j3));
}
CHECK_DIFF(elt(R,b5(j5),s3(i3),s4(i4)),val,1E-10);
}
}
SECTION("Scalar Result")
{
auto T1 = randomITensor(a1,b3,b4),
T2 = randomITensor(b4,a1,b3);
auto f = -0.2342;
T1 *= f;
auto R = T1*T2;
Real val = 0;
for(long j3 = 1; j3 <= b3.dim(); ++j3)
for(long j4 = 1; j4 <= b4.dim(); ++j4)
{
val += elt(T1,a1(1),b3(j3),b4(j4))*elt(T2,a1(1),b3(j3),b4(j4));
}
CHECK_CLOSE(val,elt(R));
}
}
//SECTION("Non-contracting Product")
//{
//auto i = Index(8,"i"),
// j = Index(3,"j"),
// k = Index(7,"k"),
// l = Index(10,"l");
//SECTION("Case 1")
// {
// auto A = randomITensor(i,l,j);
// auto B = randomITensor(k,j,l);
// auto C = A/B;
// auto diff = 0.;
// for(auto ii : range1(i.dim()))
// for(auto jj : range1(j.dim()))
// for(auto kk : range1(k.dim()))
// for(auto ll : range1(l.dim()))
// {
// diff += elt(C,i(ii),l(ll),j(jj),k(kk)) - elt(A,l(ll),i(ii),j(jj))*elt(B,j(jj),k(kk),l(ll));
// }
// CHECK(diff < 1E-13);
// }
//SECTION("Case 2")
// {
// auto A = randomITensor(i,l,j);
// auto B = randomITensor(l,j,k);
// auto C = A/B;
// auto diff = 0.;
// for(auto ii : range1(i.dim()))
// for(auto jj : range1(j.dim()))
// for(auto kk : range1(k.dim()))
// for(auto ll : range1(l.dim()))
// {
// diff += elt(C,i(ii),l(ll),j(jj),k(kk)) - elt(A,l(ll),i(ii),j(jj))*elt(B,j(jj),k(kk),l(ll));
// }
// CHECK(diff < 1E-11);
// }
//SECTION("Case 3")
// {
// auto A = randomITensor(i,l,j);
// auto B = randomITensor(l,j,k);
// auto C = B/A;
// auto diff = 0.;
// for(auto ii : range1(i.dim()))
// for(auto jj : range1(j.dim()))
// for(auto kk : range1(k.dim()))
// for(auto ll : range1(l.dim()))
// {
// diff += elt(C,i(ii),l(ll),j(jj),k(kk)) - elt(A,l(ll),i(ii),j(jj))*elt(B,j(jj),k(kk),l(ll));
// }
// CHECK(diff < 1E-13);
// }
//SECTION("Case 4")
// {
// auto A = randomITensor(i);
// auto B = randomITensor(j);
// auto C = B/A;
// auto diff = 0.;
// for(auto ii : range1(i.dim()))
// for(auto jj : range1(j.dim()))
// {
// diff += elt(C,i(ii),j(jj)) - elt(A,i(ii))*elt(B,j(jj));
// }
// CHECK(diff < 1E-13);
// }
//SECTION("Case 5")
// {
// auto A = randomITensor(i);
// auto B = randomITensor(j,k);
// auto C = B/A;
// auto diff = 0.;
// for(auto ii : range1(i.dim()))
// for(auto jj : range1(j.dim()))
// for(auto kk : range1(k.dim()))
// {
// diff += elt(C,k(kk),i(ii),j(jj)) - elt(A,i(ii))*elt(B,k(kk),j(jj));
// }
// CHECK(diff < 1E-13);
// }
//}
SECTION("Complex Contracting Product")
{
SECTION("Complex-Complex")
{
auto T1 = randomITensorC(b3,b5,l6,a1,s3),
T2 = randomITensorC(l6,s4,b3,a1);
auto R = T1*T2;
for(auto i : range1(b5))
for(auto j : range1(s3))
for(auto k : range1(s4))
{
Cplx val = 0;
for(auto l : range1(b3))
for(auto m : range1(l6))
{
val += eltC(T1,a1(1),b3(l),b5(i),l6(m),s3(j)) * eltC(T2,a1(1),l6(m),s4(k),b3(l));
}
CHECK_CLOSE(eltC(R,b5(i),s3(j),s4(k)),val);
}
}
SECTION("Real-Complex")
{
auto T1 = randomITensor(b3,b5,l6,a1,s3),
T2 = randomITensorC(l6,s4,b3,a1);
CHECK(!isComplex(T1));
CHECK(isComplex(T2));
auto R = T1*T2;
for(int j5 = 1; j5 <= 5; ++j5)
for(int i3 = 1; i3 <= 2; ++i3)
for(int i4 = 1; i4 <= 2; ++i4)
{
Complex val = 0;
for(int j3 = 1; j3 <= 3; ++j3)
for(int k6 = 1; k6 <= 2; ++k6)
{
val += eltC(T1,a1(1),b3(j3),b5(j5),l6(k6),s3(i3)) * eltC(T2,a1(1),l6(k6),s4(i4),b3(j3));
}
CHECK_CLOSE(eltC(R,b5(j5),s3(i3),s4(i4)),val);
}
}
SECTION("Real Times Scalar Complex")
{
auto T1 = randomITensor(b3,b5,a1),
T2 = randomITensorC(a1,a2);
CHECK(!isComplex(T1));
CHECK(isComplex(T2));
auto R1 = T1*T2;
for(int j5 = 1; j5 <= 5; ++j5)
for(int j3 = 1; j3 <= 3; ++j3)
{
auto val = eltC(T1,a1(1),b3(j3),b5(j5)) * eltC(T2,a1(1),a2(1));
CHECK_CLOSE(R1.eltC(a2(1),b5(j5),b3(j3)),val);
}
auto R2 = T2*T1;
for(int j5 = 1; j5 <= 5; ++j5)
for(int j3 = 1; j3 <= 3; ++j3)
{
auto val = eltC(T1,a1(1),b3(j3),b5(j5)) * eltC(T2,a1(1),a2(1));
CHECK_CLOSE(R2.eltC(a2(1),b5(j5),b3(j3)),val);
}
}
SECTION("Complex Times Scalar Real")
{
auto T1 = randomITensorC(b3,b5,a1),
T2 = randomITensor(a1,a2);
CHECK(isComplex(T1));
CHECK(!isComplex(T2));
auto R1 = T1*T2;
for(int j5 = 1; j5 <= 5; ++j5)
for(int j3 = 1; j3 <= 3; ++j3)
{
auto val = eltC(T1,b3(j3),b5(j5),a1(1)) * eltC(T2,a1(1),a2(1));
CHECK_CLOSE(R1.eltC(a2(1),b5(j5),b3(j3)),val);
}
auto R2 = T2*T1;
for(int j5 = 1; j5 <= 5; ++j5)
for(int j3 = 1; j3 <= 3; ++j3)
{
auto val = eltC(T1,b3(j3),b5(j5),a1(1)) * eltC(T2,a1(1),a2(1));
CHECK_CLOSE(R2.eltC(a2(1),b5(j5),b3(j3)),val);
}
}
SECTION("Complex Times Scalar Complex")
{
auto T1 = randomITensorC(b3,b5,a1),
T2 = randomITensorC(a1,a2);
CHECK(isComplex(T1));
CHECK(isComplex(T2));
auto R1 = T1*T2;
for(int j5 = 1; j5 <= 5; ++j5)
for(int j3 = 1; j3 <= 3; ++j3)
{
auto val = eltC(T1,b3(j3),b5(j5),a1(1)) * eltC(T2,a1(1),a2(1));
CHECK_CLOSE(R1.eltC(b5(j5),b3(j3),a2(1)),val);
}
auto R2 = T2*T1;
for(int j5 = 1; j5 <= 5; ++j5)
for(int j3 = 1; j3 <= 3; ++j3)
{
auto val = eltC(T1,b3(j3),b5(j5),a1(1)) * eltC(T2,a1(1),a2(1));
CHECK_CLOSE(R2.eltC(b5(j5),b3(j3),a2(1)),val);
}
}
}
SECTION("Prime Level Functions")
{
SECTION("Prime")
{
Index x(2,"x,Xtype"),
z(2,"z,Ztype"),
v(2,"v,Vtype");
ITensor T(x,z,v,prime(x));
T = prime(T);
CHECK(inds(T)(1) == prime(x));
CHECK(inds(T)(2) == prime(z));
CHECK(inds(T)(3) == prime(v));
CHECK(inds(T)(4) == prime(x,2));
}
SECTION("mapPrime")
{
auto i = Index(2,"i"),
j = Index(2,"j"),
k = Index(2,"k");
auto T = ITensor(i,prime(i),j,k);
auto T1 = T;
T1.mapPrime(0,2);
CHECK(inds(T1)(1) == prime(i,2));
CHECK(inds(T1)(2) == prime(i));
CHECK(inds(T1)(3) == prime(j,2));
CHECK(inds(T1)(4) == prime(k,2));
auto T2 = T;
T2.mapPrime(0,2,"i");
CHECK(inds(T2)(1) == prime(i,2));
CHECK(inds(T2)(2) == prime(i));
CHECK(inds(T2)(3) == j);
CHECK(inds(T2)(4) == k);
}
SECTION("SwapPrimeTest")
{
CHECK_EQUAL(elt(A,s1(1),prime(s1)(1)),11);
CHECK_EQUAL(elt(A,s1(2),prime(s1)(1)),21);
CHECK_EQUAL(elt(A,s1(1),prime(s1)(2)),12);
CHECK_EQUAL(elt(A,s1(2),prime(s1)(2)),22);
A = swapPrime(A,0,1);
CHECK_EQUAL(elt(A,prime(s1)(1),s1(1)),11);
CHECK_EQUAL(elt(A,prime(s1)(2),s1(1)),21);
CHECK_EQUAL(elt(A,prime(s1)(1),s1(2)),12);
CHECK_EQUAL(elt(A,prime(s1)(2),s1(2)),22);
}
SECTION("SwapTagsTest")
{
CHECK_EQUAL(elt(A,s1(1),prime(s1)(1)),11);
CHECK_EQUAL(elt(A,s1(2),prime(s1)(1)),21);
CHECK_EQUAL(elt(A,s1(1),prime(s1)(2)),12);
CHECK_EQUAL(elt(A,s1(2),prime(s1)(2)),22);
A = swapTags(A,"0","1");
CHECK_EQUAL(elt(A,prime(s1)(1),s1(1)),11);
CHECK_EQUAL(elt(A,prime(s1)(2),s1(1)),21);
CHECK_EQUAL(elt(A,prime(s1)(1),s1(2)),12);
CHECK_EQUAL(elt(A,prime(s1)(2),s1(2)),22);
}
SECTION("NoprimeTest")
{
SECTION("Case 1")
{
ITensor T(s1,s2);
T.prime();
CHECK(inds(T)[0] == prime(s1));
CHECK(inds(T)[1] == prime(s2));
T.noPrime();
CHECK(inds(T)[0] == s1);
CHECK(inds(T)[1] == s2);
}
SECTION("Case 2")
{
ITensor T(s1,prime(s1));
//Check that T.noPrime()
//throws an exception since it would
//lead to duplicate indices
CHECK_THROWS_AS(T.noPrime(),ITError);
}
}
SECTION("Prime using Tags")
{
Index x(2,"x,Xtype"),
z(2,"z,Ztype"),
v(2,"v,Vtype");
ITensor T(x,z,v);
//TODO: add functionality for listing multiple TagSets?
//T = prime(T,Ztype,Vtype);
T = prime(T,"Ztype");
T = prime(T,"Vtype");
CHECK(inds(T)[0] == x);
CHECK(inds(T)[1] == prime(z));
CHECK(inds(T)[2] == prime(v));
}
}
SECTION("Tag functions")
{
auto l = Index(3,"x,left,Link");
auto r = Index(3,"x,right,Link");
auto u = Index(3,"y,up,Link");
auto d = Index(3,"y,down,Link");
auto s = Index(2,"Site");
auto T = ITensor(l,r,u,d,s);
SECTION("addTags (all)")
{
auto T2 = addTags(T,"tag");
CHECK(hasIndex(T2,addTags(l,"tag")));
CHECK(hasIndex(T2,addTags(r,"tag")));
CHECK(hasIndex(T2,addTags(u,"tag")));
CHECK(hasIndex(T2,addTags(d,"tag")));
CHECK(hasIndex(T2,addTags(s,"tag")));
}
SECTION("addTags (match tags)")
{
auto T2 = addTags(T,"tag","x");
CHECK(hasIndex(T2,addTags(l,"tag")));
CHECK(hasIndex(T2,addTags(r,"tag")));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,s));
}
SECTION("addTags (match index)")
{
auto T2 = addTags(T,"tag",u);
CHECK(hasIndex(T2,l));
CHECK(hasIndex(T2,r));
CHECK(hasIndex(T2,addTags(u,"tag")));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,s));
}
SECTION("removeTags (all)")
{
auto T2 = removeTags(T,"Link");
CHECK(hasIndex(T2,removeTags(l,"Link")));
CHECK(hasIndex(T2,removeTags(r,"Link")));
CHECK(hasIndex(T2,removeTags(u,"Link")));
CHECK(hasIndex(T2,removeTags(d,"Link")));
CHECK(hasIndex(T2,s));
}
SECTION("removeTags (match tags)")
{
auto T2 = removeTags(T,"x","left");
CHECK(hasIndex(T2,removeTags(l,"x")));
CHECK(hasIndex(T2,r));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,s));
}
SECTION("removeTags (match index)")
{
auto T2 = removeTags(T,"Link",d);
CHECK(hasIndex(T2,l));
CHECK(hasIndex(T2,r));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,removeTags(d,"Link")));
CHECK(hasIndex(T2,s));
}
SECTION("setTags (all)")
{
auto T2 = setTags(T,"tag1,tag2,0");
CHECK(hasIndex(T2,setTags(l,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(l,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(r,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(r,"tag2,tag1")));
CHECK(hasIndex(T2,setTags(u,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(u,"tag2,tag1")));
CHECK(hasIndex(T2,setTags(d,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(d,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(s,"tag2,tag1")));
CHECK(hasIndex(T2,setTags(s,"tag2,tag1,0")));
}
SECTION("setTags (match tags)")
{
auto T2 = setTags(T,"tag1,tag2,0","x");
CHECK(hasIndex(T2,setTags(l,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(l,"tag2,tag1")));
CHECK(hasIndex(T2,setTags(r,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(r,"tag2,tag1")));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,s));
}
SECTION("setTags (match index)")
{
auto T2 = setTags(T,"tag1,tag2,0",s);
CHECK(equals(inds(T2),inds(setTags(T,"tag1,tag2",s))));
CHECK(hasIndex(T2,l));
CHECK(hasIndex(T2,r));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,setTags(s,"tag2,tag1,0")));
CHECK(hasIndex(T2,setTags(s,"tag2,tag1")));
}
SECTION("noTags (match index)")
{
auto T2 = noTags(T,s);
CHECK(hasIndex(T2,l));
CHECK(hasIndex(T2,r));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,noTags(s)));
}
SECTION("replaceTags (all)")
{
auto T2 = replaceTags(T,"Link","tag");
CHECK(hasIndex(T2,replaceTags(l,"Link","tag")));
CHECK(hasIndex(T2,replaceTags(r,"Link","tag")));
CHECK(hasIndex(T2,replaceTags(u,"Link","tag")));
CHECK(hasIndex(T2,replaceTags(d,"Link","tag")));
CHECK(hasIndex(T2,s));
}
SECTION("replaceTags (match tags)")
{
auto T2 = replaceTags(T,"Link","tag1,tag2","y");
CHECK(hasIndex(T2,l));
CHECK(hasIndex(T2,r));
CHECK(hasIndex(T2,replaceTags(u,"Link","tag2,tag1")));
CHECK(hasIndex(T2,replaceTags(d,"Link","tag2,tag1")));
CHECK(hasIndex(T2,s));
}
SECTION("replaceTags (match index)")
{
auto T2 = replaceTags(T,"Link","tag1,tag2",l);
CHECK(hasIndex(T2,replaceTags(l,"Link","tag2,tag1")));
CHECK(hasIndex(T2,r));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,s));
}
SECTION("swapTags (all)")
{
auto T2 = swapTags(T,"Link","Site");
CHECK(hasIndex(T2,replaceTags(l,"Link","Site")));
CHECK(hasIndex(T2,replaceTags(r,"Link","Site")));
CHECK(hasIndex(T2,replaceTags(u,"Link","Site")));
CHECK(hasIndex(T2,replaceTags(d,"Link","Site")));
CHECK(hasIndex(T2,replaceTags(s,"Site","Link")));
}
SECTION("swapTags (match tags)")
{
auto T2 = swapTags(T,"x","y","x");
CHECK(hasIndex(T2,replaceTags(l,"x","y")));
CHECK(hasIndex(T2,replaceTags(r,"x","y")));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,s));
}
SECTION("swapTags (match index)")
{
auto T2 = swapTags(T,"x","y",l);
CHECK(hasIndex(T2,replaceTags(l,"x","y")));
CHECK(hasIndex(T2,r));
CHECK(hasIndex(T2,u));
CHECK(hasIndex(T2,d));
CHECK(hasIndex(T2,s));
}
SECTION("Check error throws for duplicate indices")
{
auto T2 = ITensor(setTags(l,"Link,0"),setTags(l,"Link,n=2,0"));
//Check that remove the tag "2"
//throws an exception since it would
//lead to duplicate indices
CHECK_THROWS_AS(T2.removeTags("n=2"),ITError);
}
SECTION("Test contraction")
{
auto ll = setTags(l,"horiz,left,Link,0");
auto lr = setTags(l,"horiz,right,Link,0");
auto lu = setTags(l,"vert,up,Link,0");
auto ld = setTags(l,"vert,down,Link,0");
auto A = randomITensor(ll,lr,lu,ld,s);
// Contract over l,r,s
auto B = addTags(A,"bra","vert")*addTags(dag(A),"ket","vert");
CHECK(order(B) == 4);
CHECK(hasIndex(B,addTags(lu,"bra")));
CHECK(hasIndex(B,addTags(lu,"ket")));
CHECK(hasIndex(B,addTags(ld,"bra")));
CHECK(hasIndex(B,addTags(ld,"ket")));
}
}
SECTION("Access Primes Through TagSet")
{
auto s = Index(2);
auto l = addTags(s,"horiz");
auto r = replaceTags(l,"0","1");
auto u = replaceTags(l,"horiz","vert");
auto d = replaceTags(r,"horiz","vert");
auto A = randomITensor(l,r,u,d);
auto A1 = swapTags(A,"horiz","vert");
auto A2 = swapTags(A,"0","1");
auto A3 = swapTags(A,"horiz,0","vert,1");
for(auto ll : range1(dim(l)))
for(auto rr : range1(dim(r)))
for(auto uu : range1(dim(u)))
for(auto dd : range1(dim(d)))
{
CHECK(elt(A,l(ll),r(rr),u(uu),d(dd))==elt(A1,u(ll),d(rr),l(uu),r(dd)));
CHECK(elt(A,l(ll),r(rr),u(uu),d(dd))==elt(A2,r(ll),l(rr),d(uu),u(dd)));
CHECK(elt(A,l(ll),r(rr),u(uu),d(dd))==elt(A3,d(ll),r(rr),u(uu),l(dd)));
}
}
SECTION("CommonInds")
{
auto T1 = ITensor(s1,s2,l1,l2);
auto T2 = ITensor(s1,s2,l3);
CHECK(hasInds(T1,s1,s2));
CHECK(hasInds(T2,s1,s2));
auto cis = commonInds(T1,T2);
CHECK(hasSameInds(cis,{s1,s2}));
CHECK(order(commonInds(T1,T2,"Link")) == 0);
}
SECTION("CommonIndex")
{
ITensor T1(s1,s2,l1,l2),
T2(s1,l3),
T3(s3,l4);
CHECK(hasIndex(T1,s1));
CHECK(hasIndex(T2,s1));
Index c = commonIndex(T1,T3);
CHECK(!c);
c = commonIndex(T2,T3);
CHECK(!c);
CHECK(commonIndex(T1,T2) == s1);
CHECK(commonIndex(T1,T2,"Site") == s1);
c = commonIndex(T1,T2,"Link");
CHECK(!c);
}
SECTION("replaceInds")
{
auto A = randomITensor(s1,prime(s1),l1);
auto siml1 = sim(l1);
auto B = replaceInds(A,{s1,l1,prime(s1)},{prime(s1),siml1,s1});
for(auto ss1 : range1(dim(s1)))
for(auto ss1p : range1(dim(prime(s1))))
for(auto ll1 : range1(dim(l1)))
{
CHECK(elt(A,s1(ss1),prime(s1)(ss1p),l1(ll1))==elt(B,prime(s1)(ss1),s1(ss1p),siml1(ll1)));
}
}
SECTION("replaceInds (QNs)")
{
auto A = randomITensor(QN(),S1,prime(S1),L1);
auto simL1 = sim(L1);
auto B = replaceInds(A,{S1,L1,prime(S1)},{prime(S1),simL1,S1});
for(auto ss1 : range1(dim(S1)))
for(auto ss1p : range1(dim(prime(S1))))
for(auto ll1 : range1(dim(L1)))
{
CHECK(elt(A,S1(ss1),prime(S1)(ss1p),L1(ll1))==elt(B,prime(S1)(ss1),S1(ss1p),simL1(ll1)));
}
}
SECTION("Diag ITensor Contraction")
{
SECTION("Diag All Same")
{
auto op = delta(s1,a1); //all diag elements same
CHECK(typeOf(op) == Type::DiagRealAllSame);
auto r1 = randomITensor(s1,prime(s1,2));
auto res1 = op*r1;
CHECK(hasIndex(res1,a1));
CHECK(hasIndex(res1,prime(s1,2)));
for(int j1 = 1; j1 <= s1.dim(); ++j1)
{
CHECK_CLOSE(res1.elt(prime(s1,2)(j1),a1(1)), r1.elt(prime(s1,2)(j1),s1(1)));
}
}
SECTION("Diag")
{
std::vector<Real> v = {{1.23234, -0.9237}};
auto op = diagITensor(v,s1,b2);
CHECK(typeOf(op) == Type::DiagReal);
auto r2 = randomITensor(s1,s2);
auto res2 = op*r2;
CHECK(hasIndex(res2,s2));
CHECK(hasIndex(res2,b2));
auto diagm = std::min(s1.dim(),b2.dim());
for(int j2 = 1; j2 <= s2.dim(); ++j2)
for(int d = 1; d <= diagm; ++d)
{
CHECK_CLOSE(res2.elt(s2(j2),b2(d)), v.at(d-1) * r2.elt(s2(j2),s1(d)));
}
}
SECTION("Trace")
{
auto T = randomITensor(s1,s2,s3);
auto d = delta(s1,s2);
auto R = d*T;
for(auto i3 : range1(s3))
{
Real val = 0;
for(auto i12 : range1(s1))
{
val += elt(T,s1(i12),s2(i12),s3(i3));
}
CHECK_CLOSE(val,elt(R,s3(i3)));
}
}
SECTION("Tie Indices with Diag Tensor")
{
auto T = randomITensor(s1,s2,s3,s4);
auto tied1 = Index(s1.dim(),"tied1");
auto tt1 = delta(s1,s2,s3,tied1);
auto R1 = T*tt1;
for(int t = 1; t <= tied1.dim(); ++t)
for(int j4 = 1; j4 <= s4.dim(); ++j4)
{
CHECK_CLOSE(elt(T,s1(t),s2(t),s3(t),s4(j4)), elt(R1,tied1(t),s4(j4)));
}
auto tied2 = Index(s1.dim(),"tied2");
auto tt2 = delta(s1,s3,tied2);
auto R2 = T*tt2;
for(int t = 1; t <= tied1.dim(); ++t)
for(int j2 = 1; j2 <= s2.dim(); ++j2)
for(int j4 = 1; j4 <= s4.dim(); ++j4)
{
CHECK_CLOSE(elt(T,s1(t),s2(j2),s3(t),s4(j4)), elt(R2,tied2(t),s2(j2),s4(j4)));
}
}
SECTION("Contract All Dense Inds; Diag Scalar result")
{
auto T = randomITensor(J,K);
auto d1 = delta(J,K);
auto R = d1*T;
CHECK(typeOf(R) == Type::DiagRealAllSame);
Real val = 0;
auto minjk = std::min(J.dim(),K.dim());
for(long j = 1; j <= minjk; ++j)
val += elt(T,J(j),K(j));
CHECK_CLOSE(elt(R),val);
auto data = randomData(minjk);
auto d2 = diagITensor(data,J,K);
R = d2*T;
CHECK(typeOf(R) == Type::DiagRealAllSame);
val = 0;
for(long j = 1; j <= minjk; ++j)
val += data.at(j-1)*elt(T,J(j),K(j));
CHECK_CLOSE(elt(R),val);
}
SECTION("Contract All Dense Inds; Rank == 1 Diag result")
{
auto T = randomITensor(J,K);
auto d = delta(J,K,L);
auto R = d*T;
CHECK(typeOf(R) == Type::DenseReal);
CHECK(hasIndex(R,L));
auto minjkl = std::min(std::min(J.dim(),K.dim()),L.dim());
for(long j = 1; j <= minjkl; ++j)
CHECK_CLOSE(elt(R,L(j)), elt(T,J(j),K(j)));
}
SECTION("Contract All Dense Inds; Rank > 1 Diag result")
{
auto T = randomITensor(J,K);
auto d = delta(J,K,L,M);
auto R = d*T;
CHECK(typeOf(R) == Type::DiagReal);
CHECK(hasIndex(R,L));
CHECK(hasIndex(R,M));
auto minjkl = std::min(std::min(J.dim(),K.dim()),L.dim());
for(long j = 1; j <= minjkl; ++j)
CHECK_CLOSE(elt(R,L(j),M(j)), elt(T,J(j),K(j)));
}
SECTION("Two-index delta Tensor as Index Replacer")
{
auto d = delta(s1,s2);
CHECK(typeOf(d) == Type::DiagRealAllSame);
auto T1 = randomITensor(s1,s3);
auto R1a = d*T1;
CHECK(R1a.r() == 2);
CHECK(hasIndex(R1a,s2));
auto R1b = T1*d;
CHECK(R1b.r() == 2);
CHECK(hasIndex(R1b,s2));
for(int i3 = 1; i3 <= s3.dim(); ++i3)
for(int i12 = 1; i12 <= s1.dim(); ++i12)
{
CHECK_CLOSE(elt(T1,s1(i12),s3(i3)), R1a.elt(s2(i12),s3(i3)));
CHECK_CLOSE(elt(T1,s1(i12),s3(i3)), R1b.elt(s2(i12),s3(i3)));
}
auto T2 = randomITensor(s2,s3);
auto R2a = d*T2;
CHECK(R2a.r() == 2);
CHECK(hasIndex(R2a,s1));
auto R2b = T2*d;
CHECK(R2b.r() == 2);
CHECK(hasIndex(R2b,s1));
for(int i3 = 1; i3 <= s3.dim(); ++i3)
for(int i12 = 1; i12 <= s1.dim(); ++i12)
{
CHECK_CLOSE(elt(T2,s2(i12),s3(i3)), R2a.elt(s1(i12),s3(i3)));
CHECK_CLOSE(elt(T2,s2(i12),s3(i3)), R2b.elt(s1(i12),s3(i3)));
}
auto T3 = randomITensor(b8,s1,b6,a1);
auto R3a = d*T3;
auto R3b = T3*d;
CHECK(hasIndex(R3a,s2));
CHECK(hasIndex(R3b,s2));
auto T4 = randomITensor(b8,s2,b6,a1);
auto R4a = d*T4;
auto R4b = T4*d;
CHECK(hasIndex(R4a,s1));
CHECK(hasIndex(R4b,s1));
}
}
SECTION("Combiner")
{
SECTION("Two Index")
{
auto [C,ci] = combiner(s1,s2);
CHECK(typeOf(C) == Type::Combiner);
auto T1 = randomITensor(s1,s2,s3);
auto R1 = C*T1;
CHECK(hasIndex(R1,ci));
CHECK(ci.dim() == s1.dim()*s2.dim());
CHECK(ci == combinedIndex(C));
for(int i1 = 1; i1 <= s1.dim(); ++i1)
for(int i2 = 1; i2 <= s2.dim(); ++i2)
for(int i3 = 1; i3 <= s3.dim(); ++i3)
{
auto j = i1+(i2-1)*s2.dim();
CHECK_CLOSE(elt(T1,s1(i1),s2(i2),s3(i3)), elt(R1,ci(j),s3(i3)));
}
auto T2 = randomITensor(s1,s3,s2);
auto R2 = C*T2;
CHECK(R2.r() == 2);
ci = commonIndex(C,R2);
CHECK(ci);
CHECK(ci.dim() == s1.dim()*s2.dim());
for(int i1 = 1; i1 <= s1.dim(); ++i1)
for(int i2 = 1; i2 <= s2.dim(); ++i2)
for(int i3 = 1; i3 <= s3.dim(); ++i3)
{
auto j = i1+(i2-1)*s2.dim();
CHECK_CLOSE(elt(T2,s1(i1),s2(i2),s3(i3)), elt(R2,ci(j),s3(i3)));
}
}
SECTION("One Index")
{
auto T1 = randomITensor(s4,b5,s1,l2);
auto [cs4,cs4ind] = combiner(s4);
auto Rs4a = T1*cs4;
CHECK(!hasIndex(Rs4a,s4));
CHECK(cs4ind==commonIndex(cs4,Rs4a));
auto Rs4b = cs4*T1;
CHECK(!hasIndex(Rs4b,s4));
CHECK(commonIndex(cs4,Rs4b));
auto [cl2,cl2ind] = combiner(l2);
auto Rl2a = T1*cl2;
CHECK(!hasIndex(Rl2a,l2));
CHECK(hasIndex(Rl2a,cl2ind));
CHECK(commonIndex(cl2,Rl2a));
auto Rl2b = cl2*T1;
CHECK(commonIndex(cl2,Rl2b));
CHECK(!hasIndex(Rl2b,l2));
CHECK(hasIndex(Rl2b,s4));
CHECK(hasIndex(Rl2b,b5));
CHECK(hasIndex(Rl2b,s1));
}
SECTION("Scalar Case")
{
Index a(1,"a"),
b(1,"b"),
c(1,"c");
auto T = randomITensor(a,b,c);
auto [C,ci] = combiner(a,c);
auto R = T*C;
CHECK(hasIndex(R,ci));
CHECK(hasIndex(R,b));
CHECK_CLOSE(elt(T,a(1),b(1),c(1)),elt(R,ci(1),b(1)));
}
SECTION("Three Index")
{
Index i(4,"i"),
j(2,"j"),
k(3,"k");
auto T = randomITensor(i,j,k);
SECTION("Combine 1st,2nd")
{
auto [C,ci] = combiner(i,j);
auto R = C * T;
CHECK(hasIndex(R,ci));
CHECK_CLOSE(norm(R),norm(T));
for(auto i_ : range1(i.dim()))
for(auto j_ : range1(j.dim()))
for(auto k_ : range1(k.dim()))
{
auto ci_ = i_ + i.dim()*(j_-1);
CHECK_CLOSE(elt(R,ci(ci_),k(k_)), elt(T,i(i_),j(j_),k(k_)));
}
}
SECTION("Combine 1st,3rd")
{
auto [C,ci] = combiner(i,k);
auto R = C * T;
CHECK(hasIndex(R,ci));
CHECK_CLOSE(norm(R),norm(T));
for(auto i_ : range1(i.dim()))
for(auto j_ : range1(j.dim()))
for(auto k_ : range1(k.dim()))
{
auto ci_ = i_ + i.dim()*(k_-1);
CHECK_CLOSE(elt(R,ci(ci_),j(j_)), elt(T,i(i_),j(j_),k(k_)));
}
}
SECTION("Combine 2nd,3rd")
{
auto [C,ci] = combiner(k,j);
auto R = T * C;
CHECK(hasIndex(R,ci));
CHECK_CLOSE(norm(R),norm(T));
for(auto i_ : range1(i.dim()))
for(auto j_ : range1(j.dim()))
for(auto k_ : range1(k.dim()))
{
auto ci_ = k_ + k.dim()*(j_-1);
CHECK_CLOSE(elt(R,ci(ci_),i(i_)), elt(T,i(i_),j(j_),k(k_)));
}
}
SECTION("Combine 2nd,3rd (initializer_list constructor)")
{
auto [C,ci] = combiner({k,j});
auto R = T * C;
CHECK_CLOSE(norm(R),norm(T));
for(auto i_ : range1(i.dim()))
for(auto j_ : range1(j.dim()))
for(auto k_ : range1(k.dim()))
{
auto ci_ = k_ + k.dim()*(j_-1);
CHECK_CLOSE(elt(R,ci(ci_),i(i_)), elt(T,i(i_),j(j_),k(k_)));
}
}
SECTION("Combine 2nd,3rd (array constructor)")
{
auto [C,ci] = combiner(std::array<Index,2>({k,j}));
auto R = T * C;
CHECK_CLOSE(norm(R),norm(T));
for(auto i_ : range1(i.dim()))
for(auto j_ : range1(j.dim()))
for(auto k_ : range1(k.dim()))
{
auto ci_ = k_ + k.dim()*(j_-1);
CHECK_CLOSE(elt(R,ci(ci_),i(i_)), elt(T,i(i_),j(j_),k(k_)));
}
}
SECTION("Combine / Uncombine 4 - Permute (QN, initialize_list constructor)")
{
auto T = randomITensor(QN(),L1,L2,S1,S2);
auto [C,ci] = combiner({L1,S1});
auto R = T*C;
CHECK(hasIndex(R,ci));
CHECK_CLOSE(norm(T),norm(R));
CHECK(div(T) == div(R));
R *= dag(C); //uncombine
//Check that R equals original T
for(int i1 = 1; i1 <= L1.dim(); ++i1)
for(int i2 = 1; i2 <= L2.dim(); ++i2)
for(int j1 = 1; j1 <= S1.dim(); ++j1)
for(int j2 = 1; j2 <= S2.dim(); ++j2)
{
CHECK_CLOSE( elt(T,L1(i1),L2(i2),S1(j1),S2(j2)), elt(R,L1(i1),L2(i2),S1(j1),S2(j2)) );
}
}
SECTION("Combine / Uncombine 4 - Permute (QN, array constructor)")
{
auto T = randomITensor(QN(),L1,L2,S1,S2);
auto [C,ci] = combiner(std::array<Index,2>({L1,S1}));
auto R = T*C;
CHECK(hasIndex(R,ci));
CHECK_CLOSE(norm(T),norm(R));
CHECK(div(T) == div(R));
R *= dag(C); //uncombine
//Check that R equals original T
for(int i1 = 1; i1 <= L1.dim(); ++i1)
for(int i2 = 1; i2 <= L2.dim(); ++i2)
for(int j1 = 1; j1 <= S1.dim(); ++j1)
for(int j2 = 1; j2 <= S2.dim(); ++j2)
{
CHECK_CLOSE( elt(T,L1(i1),L2(i2),S1(j1),S2(j2)), elt(R,L1(i1),L2(i2),S1(j1),S2(j2)) );
}
}
//Uncombine back:
//auto TT = C * R;
//for(auto ii : range1(i.dim()))
//for(auto ij : range1(j.dim()))
//for(auto ik : range1(k.dim()))
// {
// CHECK_CLOSE(Telt(T,i(ii),j(ij),k(ik)), elt(T,i(ii),j(ij),k(ik)));
// }
}
SECTION("Five Index")
{
Index i(2,"i"),
j(3,"j"),
k(4,"k"),
l(5,"l"),
m(6,"m");
auto T = randomITensor(i,j,k,l,m);
SECTION("Combine 1,3,5")
{
auto [C,ci] = combiner(i,k,m);
auto R = C * T;
CHECK_CLOSE(norm(R),norm(T));
for(auto i_ : range1(i.dim()))
for(auto j_ : range1(j.dim()))
for(auto k_ : range1(k.dim()))
for(auto l_ : range1(l.dim()))
for(auto m_ : range1(m.dim()))
{
auto ci_ = i_+i.dim()*((k_-1)+k.dim()*(m_-1));
CHECK_CLOSE(elt(R,ci(ci_),j(j_),l(l_)), elt(T,i(i_),j(j_),k(k_),l(l_),m(m_)));
}
}
SECTION("Combine 2,3,4")
{
auto [C,ci] = combiner(k,j,l);
auto R = C * T;
CHECK_CLOSE(norm(R),norm(T));
for(auto i_ : range1(i))
for(auto j_ : range1(j))
for(auto k_ : range1(k))
for(auto l_ : range1(l))
for(auto m_ : range1(m))
{
auto ci_ = k_+k.dim()*((j_-1)+j.dim()*(l_-1));
CHECK_CLOSE(elt(R,ci(ci_),i(i_),m(m_)), elt(T,i(i_),j(j_),k(k_),l(l_),m(m_)));
}
}
//Uncombine back:
//auto TT = C * R;
//for(auto ii : range1(i.dim()))
//for(auto ij : range1(j.dim()))
//for(auto ik : range1(k.dim()))
//for(auto il : range1(l.dim()))
//for(auto im : range1(m.dim()))
// {
// CHECK_CLOSE(Telt(T,i(ii),j(ij),k(ik),l(il),m(im)), elt(T,i(ii),j(ij),k(ik),l(il),m(im)));
// }
}
}
SECTION("Norm")
{
Real nrm = 0;
auto calcnrm = CalcNrm(nrm);
//In C++14 can use:
//auto calcnrm = [&nrm](auto el) { nrm += std::norm(el); };
auto T = randomITensor(b2,b7,b8);
T.visit(calcnrm);
CHECK_CLOSE(std::sqrt(nrm),norm(T));
nrm = 0;
T = randomITensorC(b2,b7,b8);
CHECK(typeOf(T) == Type::DenseCplx);
T.visit(calcnrm);
CHECK_CLOSE(std::sqrt(nrm),norm(T));
}
SECTION("Conj")
{
auto T1 = randomITensorC(b2,b7);
CHECK(isComplex(T1));
auto T2 = conj(T1);
for(auto j2 = 1; j2 <= b2.dim(); ++j2)
for(auto j7 = 1; j7 <= b7.dim(); ++j7)
{
//printfln("T1 val = %f, conj = %f, T2 val = %f",
// eltC(T1,b2(j2),b7(j7)),std::conj(eltC(T1,b2(j2),b7(j7))),
// eltC(T2,b2(j2),b7(j7)));
CHECK_CLOSE(std::conj(eltC(T1,b2(j2),b7(j7))), eltC(T2,b2(j2),b7(j7)));
}
}
SECTION("SumEls")
{
auto T = randomITensor(b2,b7);
Real r = 0;
for(auto j2 = 1; j2 <= b2.dim(); ++j2)
for(auto j7 = 1; j7 <= b7.dim(); ++j7)
{
r += elt(T,b2(j2),b7(j7));
}
CHECK_CLOSE(sumels(T),r);
T = randomITensorC(b2,b7);
Complex z = 0;
for(auto j2 = 1; j2 <= b2.dim(); ++j2)
for(auto j7 = 1; j7 <= b7.dim(); ++j7)
{
z += eltC(T,b2(j2),b7(j7));
}
CHECK_CLOSE(sumelsC(T),z);
}
SECTION("Matrix Constructor Function")
{
Matrix M(2,2);
M(0,0) = 11;
M(0,1) = 12;
M(1,0) = 21;
M(1,1) = 22;
auto T = matrixITensor(move(M),l1,l2);
CHECK_CLOSE(elt(T,l1(1),l2(1)),11);
CHECK_CLOSE(elt(T,l1(1),l2(2)),12);
CHECK_CLOSE(elt(T,l1(2),l2(1)),21);
CHECK_CLOSE(elt(T,l1(2),l2(2)),22);
}
SECTION("Permute Test")
{
Index i(2,"i"),
j(3,"j"),
k(4,"k");
auto jp = prime(j);
//Check that permute works on tensor with null storage:
auto N = ITensor(i,j,k);
CHECK(index(N,1) == i);
CHECK(index(N,2) == j);
CHECK(index(N,3) == k);
N = permute(N,j,k,i);
CHECK(index(N,1) == j);
CHECK(index(N,2) == k);
CHECK(index(N,3) == i);
auto IT = randomITensor(i,j,jp,k);
auto O1 = permute(IT,jp,k,j,i);
CHECK(inds(IT)(1)==inds(O1)(4));
CHECK(inds(IT)(2)==inds(O1)(3));
CHECK(inds(IT)(3)==inds(O1)(1));
CHECK(inds(IT)(4)==inds(O1)(2));
for(auto ii : range1(dim(i)))
for(auto jj : range1(dim(j)))
for(auto jjp : range1(dim(jp)))
for(auto kk : range1(dim(k)))
{
CHECK_CLOSE(elt(IT,i(ii),j(jj),jp(jjp),k(kk)),elt(O1,i(ii),j(jj),jp(jjp),k(kk)));
}
auto O2 = permute(IT,j,i,k,jp);
CHECK(inds(IT)(1)==inds(O2)(2));
CHECK(inds(IT)(2)==inds(O2)(1));
CHECK(inds(IT)(3)==inds(O2)(4));
CHECK(inds(IT)(4)==inds(O2)(3));
for(auto ii : range1(i.dim()))
for(auto jj : range1(j.dim()))
for(auto jjp : range1(jp.dim()))
for(auto kk : range1(k.dim()))
{
CHECK_CLOSE(elt(IT,i(ii),j(jj),jp(jjp),k(kk)),elt(O2,i(ii),j(jj),jp(jjp),k(kk)));
}
auto CIT = randomITensorC(i,j,jp,k);
auto O3 = permute(CIT,jp,k,i,j);
CHECK(inds(CIT)(1)==inds(O3)(3));
CHECK(inds(CIT)(2)==inds(O3)(4));
CHECK(inds(CIT)(3)==inds(O3)(1));
CHECK(inds(CIT)(4)==inds(O3)(2));
for(auto ii : range1(i.dim()))
for(auto jj : range1(j.dim()))
for(auto jjp : range1(jp.dim()))
for(auto kk : range1(k.dim()))
{
CHECK_CLOSE(eltC(CIT,i(ii),j(jj),jp(jjp),k(kk)),eltC(O3,i(ii),j(jj),jp(jjp),k(kk)));
}
auto data = randomData(i.dim());
auto ITD = diagITensor(data,i,j,k);
auto O4 = permute(ITD,k,i,j);
CHECK(inds(ITD)(1)==inds(O4)(2));
CHECK(inds(ITD)(2)==inds(O4)(3));
CHECK(inds(ITD)(3)==inds(O4)(1));
for(auto ii : range1(i.dim()))
for(auto jj : range1(j.dim()))
for(auto kk : range1(k.dim()))
{
CHECK_CLOSE(elt(ITD,i(ii),j(jj),k(kk)),elt(O4,i(ii),j(jj),k(kk)));
}
}
SECTION("Index Test")
{
Index i(2,"i"),
j(2,"j"),
k(2,"k");
ITensor T(i,j,k);
CHECK(index(T,1) == inds(T)(1));
CHECK(index(T,2) == inds(T)(2));
CHECK(index(T,3) == inds(T)(3));
}
SECTION("RealImagPart")
{
auto f1 = 2.124;
auto f2 = 1.113;
auto ZiX = f1*Z + f2*1_i*X;
auto R = realPart(ZiX);
auto I = imagPart(ZiX);
R -= f1*Z;
I -= f2*X;
CHECK_DIFF(norm(R),0,1E-5);
CHECK_DIFF(norm(I),0,1E-5);
//Test hc:
ZiX.dag();
R = realPart(ZiX);
I = imagPart(ZiX);
R -= f1*Z;
I += f2*X;
CHECK_DIFF(norm(R),0,1E-5);
CHECK_DIFF(norm(I),0,1E-5);
}
SECTION("NormTest")
{
A = randomITensor(s1,prime(s1));
CHECK_CLOSE(norm(A),sqrt(elt(A*A)));
B = randomITensor(s1,prime(s1));
auto C = A+1_i*B;
CHECK_CLOSE(norm(C),sqrt(elt(realPart(dag(C)*C))));
}
SECTION("Scalar Storage")
{
auto S1 = ITensor(1.);
CHECK_CLOSE(elt(S1),1.);
auto S2 = ITensor(1.)*2.;
CHECK_CLOSE(elt(S2),2.);
auto ZA = ITensor(1._i);
CHECK_CLOSE(eltC(ZA),1._i);
auto ZB = ITensor(-1.+2._i);
CHECK_CLOSE(eltC(ZB),-1+2._i);
SECTION("Set")
{
S1.set(4.5);
CHECK_CLOSE(elt(S1),4.5);
S1.set(4);
CHECK_CLOSE(elt(S1),4);
S1.set(1.+3._i);
CHECK(isComplex(S1));
CHECK_CLOSE(eltC(S1),1.+3._i);
ZA.set(2.-3._i);
CHECK_CLOSE(eltC(ZA),2.-3._i);
ZA.set(3.0);
CHECK(isReal(ZA));
CHECK_CLOSE(elt(ZA),3.);
}
SECTION("Norm")
{
CHECK_CLOSE(norm(S1),1.);
CHECK_CLOSE(norm(S2),2.);
auto Sn2 = ITensor(-2.);
CHECK_CLOSE(norm(Sn2),2.);
CHECK_CLOSE(norm(ZA),std::norm(eltC(ZA)));
}
auto i = Index(3,"i");
auto j = Index(4,"j");
auto T = randomITensor(i,j);
auto TC = randomITensorC(i,j);
SECTION("Multiply on right")
{
auto R = T*S1;
CHECK(norm(R-T) < 1E-12);
R = T*S2;
CHECK(norm(R-2*T) < 1E-12);
R = TC*S2;
CHECK(norm(R-2*TC) < 1E-12);
R = T*ZA;
CHECK(isComplex(R));
CHECK(norm(R-eltC(ZA)*T) < 1E-12);
R = TC*ZA;
CHECK(norm(R-eltC(ZA)*TC) < 1E-12);
}
SECTION("Multiply on left")
{
auto R = S1*T;
CHECK(norm(R-T) < 1E-12);
R = S2*T;
CHECK(norm(R-2*T) < 1E-12);
R = S2*TC;
CHECK(norm(R-2*TC) < 1E-12);
R = ZA*T;
CHECK(isComplex(R));
CHECK(norm(R-eltC(ZA)*T) < 1E-12);
R = ZA*TC;
CHECK(norm(R-eltC(ZA)*TC) < 1E-12);
}
SECTION("Add & Subtract")
{
auto R = S1 + S2;
CHECK_CLOSE(elt(R),3.);
R = ZA+ZB;
CHECK_CLOSE(eltC(R),eltC(ZA)+eltC(ZB));
R = S1 - S2;
CHECK_CLOSE(elt(R),-1.);
R = ZA-ZB;
CHECK_CLOSE(eltC(R),eltC(ZA)-eltC(ZB));
}
}
SECTION("ITensor Negation")
{
auto i = Index(2,"i");
auto j = Index(2,"j");
auto k = Index(2,"k");
auto T = randomITensor(i,j,k);
//Print(elt(T,i(1),j(1),k(1)));
auto oT = T;
auto N = -T;
//Print(elt(oT,i(1),j(1),k(1)));
//Print(elt(T,i(1),j(1),k(1)));
//Print(elt(N,i(1),j(1),k(1)));
for(auto ii : range1(i))
for(auto ij : range1(j))
for(auto ik : range1(k))
{
CHECK_CLOSE(elt(oT,i(ii),j(ij),k(ik)),elt(T,i(ii),j(ij),k(ik)));
CHECK_CLOSE(-elt(oT,i(ii),j(ij),k(ik)),elt(N,i(ii),j(ij),k(ik)));
}
}
SECTION("ITensor partial direct sum")
{
SECTION("No QNs")
{
auto a = Index(2,"a"),
b = Index(2,"b"),
i = Index(2,"i"),
j = Index(2,"j");
auto A = randomITensor(a,b,i);
auto B = randomITensor(a,b,j);
// Version accepting an index on A and an index on B to be direct summed
// Here we create a new ITensor C with indices {a,b,i+j}
// Indices that are not specified must be shared by A and B
auto [C,ij] = directSum(A,B,i,j,{"Tags=","i+j"});
CHECK_CLOSE(C.elt(a=1,b=1,ij=1),A.elt(a=1,b=1,i=1));
CHECK_CLOSE(C.elt(a=1,b=1,ij=dim(i)+1),B.elt(a=1,b=1,j=1));
}
SECTION("QNs")
{
auto a = Index(QN(-1),2,
QN(0),2,
QN(+1),2,"a");
auto b = Index(QN(-1),2,
QN(0),2,
QN(+1),2,"b");
auto i = Index(QN(-1),2,
QN(0),2,
QN(+1),2,"i");
auto j = Index(QN(-1),2,
QN(0),2,
QN(+1),2,"j");
auto A = randomITensor(QN(0),a,b,dag(i));
auto B = randomITensor(QN(0),a,b,dag(j));
// Version accepting an index on A and an index on B to be direct summed
// Here we create a new ITensor C with indices {a,b,i+j}
// Indices that are not specified must be shared by A and B
auto [C,ij] = directSum(A,B,i,j,{"Tags=","i+j"});
CHECK_CLOSE(C.elt(a=1,b=1,ij=1),A.elt(a=1,b=1,i=1));
CHECK_CLOSE(C.elt(a=1,b=1,ij=dim(i)+1),B.elt(a=1,b=1,j=1));
}
}
} //TEST_CASE("ITensor")