https://github.com/ITensor/ITensor
Raw File
Tip revision: 6928c721813cde1204e8bf29dfb51a2f44dd9c9e authored by Miles Stoudenmire on 13 November 2015, 17:24:13 UTC
Removed outdated IQTensor constructor declarations
Tip revision: 6928c72
itensor_test.cc
#include "test.h"
#include "itensor/itensor.h"
#include "itensor/util/cplx_literal.h"
#include "itensor/util/count.h"
#include "itensor/util/set_scoped.h"

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 
          };
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; }
        };
    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 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("s1",2,Site);
Index s2("s2",2,Site);
Index s3("s3",2,Site);
Index s4("s4",2,Site);
//Index s1P(prime(s1));
//Index s2P(prime(s2));
//Index s3P(prime(s3));
//Index s4P(prime(s4));
Index l1("l1",2);
Index l2("l2",2);
Index l3("l3",2);
Index l4("l4",2);
Index l5("l5",2);
Index l6("l6",2);
Index l7("l7",2);
Index l8("l8",2);
Index a1("a1");
Index a2("a2");
Index a3("a3");
Index a4("a4");
Index b2("b2",2);
Index b3("b3",3);
Index b4("b4",4);
Index b5("b5",5);
Index b6("b6",6);
Index b7("b7",7);
Index b8("b8",8);

Index J("J",10),
      K("K",10),
      L("L",10);

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(t7.real(l1(1),l2(1)),a,1E-5);
    CHECK_DIFF(t7.real(l1(1),l2(2)),a,1E-5);
    CHECK_DIFF(t7.real(l1(2),l2(1)),a,1E-5);
    CHECK_DIFF(t7.real(l1(2),l2(2)),a,1E-5);
    t7.set(l1(2),l2(2),1.5);
    CHECK_DIFF(t7.real(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("linkind",10);
    auto data = randomData(linkind.m());
    auto t10 = diagTensor(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("i1",10),
          i2("i2",10);
    auto data = randomData(i1.m());
    auto T = diagTensor(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("IndexValConstructors")
{
SECTION("Rank 1")
    {
    ITensor t1(l1(2));
    CHECK_EQUAL(t1.r(),1);
    CHECK(hasindex(t1,l1));
    CHECK_DIFF(t1.real(l1(1)),0,1E-10);
    CHECK_DIFF(t1.real(l1(2)),1,1E-10);
    CHECK_DIFF(sumels(t1),1,1E-10);
    CHECK_DIFF(norm(t1),1,1E-10);
    }

SECTION("Rank 2")
    {
    ITensor t2(l1(2),l2(1));

    CHECK_EQUAL(t2.r(),2);
    CHECK(hasindex(t2,l1));
    CHECK(hasindex(t2,l2));
    CHECK_DIFF(t2.real(l1(1),l2(1)),0,1E-10);
    CHECK_DIFF(t2.real(l1(1),l2(2)),0,1E-10);
    CHECK_DIFF(t2.real(l1(2),l2(1)),1,1E-10);
    CHECK_DIFF(t2.real(l1(2),l2(2)),0,1E-10);
    CHECK_DIFF(sumels(t2),1,1E-10);
    CHECK_DIFF(norm(t2),1,1E-10);

    ITensor u2a(a1(1),l2(2));

    CHECK_EQUAL(u2a.r(),2);
    CHECK(hasindex(u2a,a1));
    CHECK(hasindex(u2a,l2));
    CHECK_DIFF(u2a.real(a1(1),l2(1)),0,1E-10);
    CHECK_DIFF(u2a.real(a1(1),l2(2)),1,1E-10);
    CHECK_DIFF(sumels(u2a),1,1E-10);
    CHECK_DIFF(norm(u2a),1,1E-10);

    ITensor u2b(l1(2),a2(1));

    CHECK_EQUAL(u2b.r(),2);
    CHECK(hasindex(u2b,l1));
    CHECK(hasindex(u2b,a2));
    CHECK_DIFF(u2b.real(l1(1),a2(1)),0,1E-10);
    CHECK_DIFF(u2b.real(l1(2),a2(1)),1,1E-10);
    CHECK_DIFF(sumels(u2b),1,1E-10);
    CHECK_DIFF(norm(u2b),1,1E-10);
    }

SECTION("Rank 3")
    {
    ITensor t3(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.real(l1(1),l3(1),l2(1)),0,1E-10);
    CHECK_DIFF(t3.real(l1(2),l3(1),l2(1)),1,1E-10);
    CHECK_DIFF(t3.real(l1(1),l3(2),l2(1)),0,1E-10);
    CHECK_DIFF(t3.real(l1(2),l3(2),l2(2)),0,1E-10);
    CHECK_DIFF(t3.real(l1(1),l3(1),l2(2)),0,1E-10);
    CHECK_DIFF(t3.real(l1(2),l3(1),l2(2)),0,1E-10);
    CHECK_DIFF(t3.real(l1(1),l3(2),l2(2)),0,1E-10);
    CHECK_DIFF(t3.real(l1(2),l3(2),l2(2)),0,1E-10);
    CHECK_DIFF(sumels(t3),1,1E-10);
    CHECK_DIFF(norm(t3),1,1E-10);

    ITensor t4(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.real(l3(1),l2(1),a1(1)),0,1E-10);
    CHECK_DIFF(t4.real(l3(1),l2(2),a1(1)),0,1E-10);
    CHECK_DIFF(t4.real(l3(2),l2(1),a1(1)),1,1E-10);
    CHECK_DIFF(t4.real(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")
    {
    ITensor r4(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.real(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")
    {
    ITensor t8(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.real(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 = randomTensor(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(A.real(s1(1),s1P(1)),-11);
    CHECK_EQUAL(A.real(s1(1),s1P(2)),-12);
    CHECK_EQUAL(A.real(s1(2),s1P(1)),-21);
    CHECK_EQUAL(A.real(s1(2),s1P(2)),-22);

    Real f = Global::random();
    A *= -f;
    CHECK_DIFF(A.real(s1(1),s1P(1)),11*f,1E-10);
    CHECK_DIFF(A.real(s1(1),s1P(2)),12*f,1E-10);
    CHECK_DIFF(A.real(s1(2),s1P(1)),21*f,1E-10);
    CHECK_DIFF(A.real(s1(2),s1P(2)),22*f,1E-10);

    B /= f;
    CHECK_DIFF(B.real(s1(1),s2(1)),110/f,1E-10);
    CHECK_DIFF(B.real(s1(1),s2(2)),120/f,1E-10);
    CHECK_DIFF(B.real(s1(2),s2(1)),210/f,1E-10);
    CHECK_DIFF(B.real(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(A.cplx(s1(1),s1P(1)),11_i);
    CHECK_EQUAL(A.cplx(s1(1),s1P(2)),12_i);
    CHECK_EQUAL(A.cplx(s1(2),s1P(1)),21_i);
    CHECK_EQUAL(A.cplx(s1(2),s1P(2)),22_i);

    auto T = random(A);
    CHECK(typeOf(T) == Type::DenseReal);
    CHECK(typeOf(A) == Type::DenseCplx);

    randomize(T,"Complex");
    CHECK(typeOf(T) == Type::DenseCplx);

    auto z = 2.2-3.1_i;
    auto cT = T;
    T *= z;
    CHECK_CLOSE(T.cplx(s1(1),s1P(1)),z * cT.cplx(s1(1),s1P(1)));
    CHECK_CLOSE(T.cplx(s1(1),s1P(2)),z * cT.cplx(s1(1),s1P(2)));
    CHECK_CLOSE(T.cplx(s1(2),s1P(1)),z * cT.cplx(s1(2),s1P(1)));
    CHECK_CLOSE(T.cplx(s1(2),s1P(2)),z * cT.cplx(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.m(); ++n1)
    for(int n2 = 1; n2 <= s1P.m(); ++n2)
        {
        CHECK_DIFF( f( A.real(s1(n1),s1P(n2)) ), A1.real(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 = randomTensor(b4,l2);
    T.apply(rfunc);
    }

SECTION("Visit Real")
    {
    //use visitor function that only accepts Real argument to real ITensor
    auto T = randomTensor(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 b4i : b4) for(auto l2i : l2)
        {
        prod_check *= T.real(b4i,l2i);
        }
    CHECK_CLOSE(prod,prod_check);
    }

}

SECTION("SumDifference")
{
auto v = randomTensor(mixed_inds), 
     w = randomTensor(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(r.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)),
                 f1*v.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))
               + w.real(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(d.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)),
                v.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))-w.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)));
    }

f1 = 1; f2 = 1;
auto yy = randomTensor(mixed_inds), 
     zz = randomTensor(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(r.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)),
                f1*yy.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))
               +f2*zz.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)));
    }

IndexSet reordered(l2,l1,b3,a4,a2,l4);
w = randomTensor(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(r.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1)),
                 f1*v.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))
               + w.real(l1(j1),l2(j2),b3(k3),l4(j4),a2(1),a4(1))/f2);
    }

SECTION("Reordered Case 2")
    {
    auto T1 = randomTensor(b6,s1,b5,s2),
         T2 = randomTensor(s1,s2,b6,b5);
    auto R = T1+T2;
    for(int j6 = 1; j6 <= b6.m(); ++j6)
    for(int j5 = 1; j5 <= b5.m(); ++j5)
    for(int k1 = 1; k1 <= s1.m(); ++k1)
    for(int k2 = 1; k2 <= s2.m(); ++k2)
        {
        auto val = T1.real(b6(j6),s1(k1),b5(j5),s2(k2))+T2.real(b6(j6),s1(k1),b5(j5),s2(k2));
        CHECK_CLOSE(R.real(b6(j6),s1(k1),b5(j5),s2(k2)),val);
        }
    }

SECTION("Add diag")
    {
    auto data1 = randomData(std::min(l6.m(),b4.m())),
         data2 = randomData(std::min(l6.m(),b4.m()));
    auto v1 = diagTensor(data1,l6,b4),
         v2 = diagTensor(data2,b4,l6);
    auto r = v1+v2;
    for(int j1 = 1; j1 <= 2; ++j1)
    for(int j2 = 1; j2 <= 4; ++j2)
        {
        //printfln("r.real(l6(%d),b4(%d)) = %.10f",j1,j2,r.real(l6(j1),b4(j2)));
        CHECK_CLOSE(r.real(l6(j1),b4(j2)),v1.real(l6(j1),b4(j2))+v2.real(l6(j1),b4(j2)));
        }
    }

}

SECTION("Complex SumDifference")
{

SECTION("Complex+-Complex")
    {
    SECTION("Case 1 - Same Order")
        {
        auto T1 = randomTensorC(l2,b4,b2);
        auto T2 = randomTensorC(l2,b4,b2);

        auto R = T1 + T2;

        for(auto i2 : count1(l2.m()))
        for(auto j2 : count1(b2.m()))
        for(auto j4 : count1(b4.m()))
            {
            CHECK_CLOSE(R.cplx(l2(i2),b2(j2),b4(j4)), T1.cplx(l2(i2),b2(j2),b4(j4))+T2.cplx(l2(i2),b2(j2),b4(j4)));
            }
        }

    SECTION("Case 2 - Different Order")
        {
        auto T1 = randomTensorC(l2,b4,b2);
        auto T2 = randomTensorC(b4,l2,b2);

        auto R = T1 + T2;

        for(auto i2 : count1(l2.m()))
        for(auto j2 : count1(b2.m()))
        for(auto j4 : count1(b4.m()))
            {
            CHECK_CLOSE(R.cplx(l2(i2),b2(j2),b4(j4)), T1.cplx(l2(i2),b2(j2),b4(j4))+T2.cplx(l2(i2),b2(j2),b4(j4)));
            }
        }

    SECTION("Case 3 - Subtract Different Order")
        {
        auto f1 = Global::random(),
             f2 = Global::random();
        auto T1 = randomTensorC(l2,b4,b2);
        auto T2 = randomTensorC(b4,l2,b2);

        auto R = f1*T1 - f2*T2;

        for(auto i2 : count1(l2.m()))
        for(auto j2 : count1(b2.m()))
        for(auto j4 : count1(b4.m()))
            {
            CHECK_CLOSE(R.cplx(l2(i2),b2(j2),b4(j4)), f1*T1.cplx(l2(i2),b2(j2),b4(j4))-f2*T2.cplx(l2(i2),b2(j2),b4(j4)));
            }
        }
    }

SECTION("Real+-Complex")
    {
    auto f1 = Global::random(),
         f2 = Global::random();
    auto T1 = randomTensor(l2,b4,b2);

    SECTION("Case 1: Real+Cplx, No Permute")
        {
        auto T2 = randomTensorC(l2,b4,b2);
        //println("Case 1");
        auto R = f1*T1 + f2*T2;

        for(auto i2 : count1(l2.m()))
        for(auto j2 : count1(b2.m()))
        for(auto j4 : count1(b4.m()))
            {
            CHECK_CLOSE(R.cplx(l2(i2),b2(j2),b4(j4)), f1*T1.cplx(l2(i2),b2(j2),b4(j4))+f2*T2.cplx(l2(i2),b2(j2),b4(j4)));
            }
        }

    SECTION("Case 2: Real+Cplx, Permute")
        {
        auto T2 = randomTensorC(b4,l2,b2);
        //println("Case 2");
        auto R = f1*T1 + f2*T2;

        for(auto i2 : count1(l2.m()))
        for(auto j2 : count1(b2.m()))
        for(auto j4 : count1(b4.m()))
            {
            CHECK_CLOSE(R.cplx(l2(i2),b2(j2),b4(j4)), f1*T1.cplx(l2(i2),b2(j2),b4(j4))+f2*T2.cplx(l2(i2),b2(j2),b4(j4)));
            }
        }

    SECTION("Case 3: Cplx+Real, No Permute")
        {
        auto T2 = randomTensorC(l2,b4,b2);
        //println("Case 3");
        auto R = f2*T2 + f1*T1;

        for(auto i2 : count1(l2.m()))
        for(auto j2 : count1(b2.m()))
        for(auto j4 : count1(b4.m()))
            {
            CHECK_CLOSE(R.cplx(l2(i2),b2(j2),b4(j4)), f1*T1.cplx(l2(i2),b2(j2),b4(j4))+f2*T2.cplx(l2(i2),b2(j2),b4(j4)));
            }
        }

    SECTION("Case 4: Cplx+Real, Permute")
        {
        auto T2 = randomTensorC(b4,l2,b2);
        //println("Case 4");
        auto R = f2*T2 + f1*T1;

        for(auto i2 : count1(l2.m()))
        for(auto j2 : count1(b2.m()))
        for(auto j4 : count1(b4.m()))
            {
            CHECK_CLOSE(R.cplx(l2(i2),b2(j2),b4(j4)), f1*T1.cplx(l2(i2),b2(j2),b4(j4))+f2*T2.cplx(l2(i2),b2(j2),b4(j4)));
            }
        }

    SECTION("Case 5: Cplx+Real, Permute")
        {
        auto T2 = randomTensorC(b2,l2,b4);
        //println("Case 5");
        auto R = f2*T2 + f1*T1;

        for(auto i2 : count1(l2.m()))
        for(auto j2 : count1(b2.m()))
        for(auto j4 : count1(b4.m()))
            {
            CHECK_CLOSE(R.cplx(l2(i2),b2(j2),b4(j4)), f1*T1.cplx(l2(i2),b2(j2),b4(j4))+f2*T2.cplx(l2(i2),b2(j2),b4(j4)));
            }
        }
    }

}

SECTION("ContractingProduct")
{

//Check for rank 0 ITensors
SECTION("Rank 0")
    {
    Real f = Global::random();
    auto rZ = ITensor(f); 
    auto T = randomTensor(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 * T.real(b2(j2),a1(1),b4(j4));
        CHECK_CLOSE(res.real(b2(j2),a1(1),b4(j4)),val);
        }
    }

auto L = randomTensor(b4,a1,b3,a2,b2), 
     R = randomTensor(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.m(); ++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 += L.real(a2(1),b2(j2),a1(1),b3(j3),b4(j4))*fL * R.real(b5(j5),a1(1),b3(j3),b2(j2),b4(j4))*fR;
            }
        CHECK_DIFF(res1.real(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.m(); ++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 += L.real(a2(1),b2(j2),a1(1),b3(j3),b4(j4)) * R.real(b5(j5),a1(1),b3(j3),b2(j2),b4(j4));
            }
        CHECK_DIFF(res2.real(a2(1),b5(j5)),val,1E-10);
        }
    }

ITensor Q = randomTensor(a1,b4,a2,b2), 
        P = randomTensor(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.m(); ++j2)
    for(int j4 = 1; j4 <= b4.m(); ++j4)
        {
        auto val = Q.real(a1(1),b4(j4),a2(1),b2(j2))*fQ * P.real(a2(1),a3(1),a1(1))*fP;
        CHECK_DIFF(res3.real(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 = Q.real(a1(1),b4(j4),a2(1),b2(j2))*fQ * P.real(a2(1),a3(1),a1(1))*fP;
        CHECK_DIFF(res4.real(a3(1),b4(j4),b2(j2)),val,1E-10);
        }
    }


SECTION("Case 5")
    {
    auto psi = randomTensor(a1,a2,a3), 
         mpoh = randomTensor(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 = randomTensor(b3,b5,l6,a1,s3),
         T2 = randomTensor(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 += T1.real(a1(1),b3(j3),b5(j5),l6(k6),s3(i3)) * T2.real(a1(1),l6(k6),s4(i4),b3(j3));
            }
        CHECK_DIFF(R.real(b5(j5),s3(i3),s4(i4)),val,1E-10);
        }
    }

SECTION("Scalar Result")
    {
    auto T1 = randomTensor(a1,b3,b4),
         T2 = randomTensor(b4,a1,b3);
    auto f = -0.2342;
    T1 *= f;
    auto R = T1*T2;

    Real val = 0;
    for(long j3 = 1; j3 <= b3.m(); ++j3)
    for(long j4 = 1; j4 <= b4.m(); ++j4)
        {
        val += T1.real(a1(1),b3(j3),b4(j4))*T2.real(a1(1),b3(j3),b4(j4));
        }
    CHECK_CLOSE(val,R.real());
    }
}

SECTION("Non-contracting Product")
{
auto i = Index("i",8),
     j = Index("j",3),
     k = Index("k",7),
     l = Index("l",10);
SECTION("Case 1")
    {
    auto A = randomTensor(i,l,j);
    auto B = randomTensor(k,j,l);
    auto C = A/B;
    auto diff = 0.;
    for(auto ii : count1(i.m()))
    for(auto jj : count1(j.m()))
    for(auto kk : count1(k.m()))
    for(auto ll : count1(l.m()))
        {
        diff += C.real(i(ii),l(ll),j(jj),k(kk)) - A.real(l(ll),i(ii),j(jj))*B.real(j(jj),k(kk),l(ll));
        }
    CHECK(diff < 1E-13);
    }
SECTION("Case 2")
    {
    auto A = randomTensor(i,l,j);
    auto B = randomTensor(l,j,k);
    auto C = A/B;
    auto diff = 0.;
    for(auto ii : count1(i.m()))
    for(auto jj : count1(j.m()))
    for(auto kk : count1(k.m()))
    for(auto ll : count1(l.m()))
        {
        diff += C.real(i(ii),l(ll),j(jj),k(kk)) - A.real(l(ll),i(ii),j(jj))*B.real(j(jj),k(kk),l(ll));
        }
    CHECK(diff < 1E-13);
    }
SECTION("Case 3")
    {
    auto A = randomTensor(i,l,j);
    auto B = randomTensor(l,j,k);
    auto C = B/A;
    auto diff = 0.;
    for(auto ii : count1(i.m()))
    for(auto jj : count1(j.m()))
    for(auto kk : count1(k.m()))
    for(auto ll : count1(l.m()))
        {
        diff += C.real(i(ii),l(ll),j(jj),k(kk)) - A.real(l(ll),i(ii),j(jj))*B.real(j(jj),k(kk),l(ll));
        }
    CHECK(diff < 1E-13);
    }
SECTION("Case 4")
    {
    auto A = randomTensor(i);
    auto B = randomTensor(j);
    auto C = B/A;
    auto diff = 0.;
    for(auto ii : count1(i.m()))
    for(auto jj : count1(j.m()))
        {
        diff += C.real(i(ii),j(jj)) - A.real(i(ii))*B.real(j(jj));
        }
    CHECK(diff < 1E-13);
    }
SECTION("Case 5")
    {
    auto A = randomTensor(i);
    auto B = randomTensor(j,k);
    auto C = B/A;
    auto diff = 0.;
    for(auto ii : count1(i.m()))
    for(auto jj : count1(j.m()))
    for(auto kk : count1(k.m()))
        {
        diff += C.real(k(kk),i(ii),j(jj)) - A.real(i(ii))*B.real(k(kk),j(jj));
        }
    CHECK(diff < 1E-13);
    }
}

SECTION("Complex Contracting Product")
{
SECTION("Complex-Complex")
    {
    auto T1 = randomTensorC(b3,b5,l6,a1,s3),
         T2 = randomTensorC(l6,s4,b3,a1);
    auto R = T1*T2;

    for(auto b5i : b5)
    for(auto s3i : s3)
    for(auto s4i : s4)
        {
        Cplx val = 0;
        for(auto b3i : b3)
        for(auto l6i : l6)
            {
            val += T1.cplx(a1(1),b3i,b5i,l6i,s3i) * T2.cplx(a1(1),l6i,s4i,b3i);
            }
        CHECK_CLOSE(R.cplx(b5i,s3i,s4i),val);
        }
    }

SECTION("Real-Complex")
    {
    auto T1 = randomTensor(b3,b5,l6,a1,s3),
         T2 = randomTensorC(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 += T1.cplx(a1(1),b3(j3),b5(j5),l6(k6),s3(i3)) * T2.cplx(a1(1),l6(k6),s4(i4),b3(j3));
            }
        CHECK_CLOSE(R.cplx(b5(j5),s3(i3),s4(i4)),val);
        }
    }

SECTION("Real Times Scalar Complex")
    {
    auto T1 = randomTensor(b3,b5,a1),
         T2 = randomTensorC(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 = T1.cplx(a1(1),b3(j3),b5(j5)) * T2.cplx(a1(1),a2(1));
        CHECK_CLOSE(R1.cplx(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 = T1.cplx(a1(1),b3(j3),b5(j5)) * T2.cplx(a1(1),a2(1));
        CHECK_CLOSE(R2.cplx(a2(1),b5(j5),b3(j3)),val);
        } 
    }

SECTION("Complex Times Scalar Real")
    {
    auto T1 = randomTensorC(b3,b5,a1),
         T2 = randomTensor(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 = T1.cplx(b3(j3),b5(j5),a1(1)) * T2.cplx(a1(1),a2(1));
        CHECK_CLOSE(R1.cplx(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 = T1.cplx(b3(j3),b5(j5),a1(1)) * T2.cplx(a1(1),a2(1));
        CHECK_CLOSE(R2.cplx(a2(1),b5(j5),b3(j3)),val);
        }
    }

SECTION("Complex Times Scalar Complex")
    {
    auto T1 = randomTensorC(b3,b5,a1),
         T2 = randomTensorC(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 = T1.cplx(b3(j3),b5(j5),a1(1)) * T2.cplx(a1(1),a2(1));
        CHECK_CLOSE(R1.cplx(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 = T1.cplx(b3(j3),b5(j5),a1(1)) * T2.cplx(a1(1),a2(1));
        CHECK_CLOSE(R2.cplx(b5(j5),b3(j3),a2(1)),val);
        }
    }
}


SECTION("Prime Level Functions")
{

SECTION("Prime")
    {
    Index x("x",2,Xtype),
          z("z",2,Ztype),
          v("v",2,Vtype);
    ITensor T(x,z,v,prime(x));
    T = prime(T);
    CHECK(T.inds()[0] == prime(x));
    CHECK(T.inds()[1] == prime(z));
    CHECK(T.inds()[2] == prime(v));
    CHECK(T.inds()[3] == prime(x,2));
    }

SECTION("SwapPrimeTest")
    {
    CHECK_EQUAL(A.real(s1(1),prime(s1)(1)),11);
    CHECK_EQUAL(A.real(s1(2),prime(s1)(1)),21);
    CHECK_EQUAL(A.real(s1(1),prime(s1)(2)),12);
    CHECK_EQUAL(A.real(s1(2),prime(s1)(2)),22);

    A = swapPrime(A,0,1);

    CHECK_EQUAL(A.real(prime(s1)(1),s1(1)),11);
    CHECK_EQUAL(A.real(prime(s1)(2),s1(1)),21);
    CHECK_EQUAL(A.real(prime(s1)(1),s1(2)),12);
    CHECK_EQUAL(A.real(prime(s1)(2),s1(2)),22);
    }

SECTION("NoprimeTest")
    {
    SECTION("Case 1")
        {
        ITensor T(s1,s2);
        T.prime();
        CHECK(T.inds()[0] == prime(s1));
        CHECK(T.inds()[1] == prime(s2));
        T.noprime();
        CHECK(T.inds()[0] == s1);
        CHECK(T.inds()[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 IndexTypes")
    {
    Index x("x",2,Xtype),
          z("z",2,Ztype),
          v("v",2,Vtype);
    ITensor T(x,z,v);
    T = prime(T,Ztype,Vtype);
    CHECK(T.inds()[0] == x);
    CHECK(T.inds()[1] == prime(z));
    CHECK(T.inds()[2] == prime(v));
    }
}

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);
}

SECTION("Diag ITensor Contraction")
{
SECTION("Diag All Same")
    {
    auto op = diagTensor(1.,s1,a1); //all diag elements same
    CHECK(typeOf(op) == Type::DiagRealAllSame);

    auto r1 = randomTensor(s1,prime(s1,2));
    auto res1 = op*r1;
    CHECK(hasindex(res1,a1));
    CHECK(hasindex(res1,prime(s1,2)));
    for(int j1 = 1; j1 <= s1.m(); ++j1)
        {
        CHECK_CLOSE(res1.real(prime(s1,2)(j1),a1(1)), r1.real(prime(s1,2)(j1),s1(1)));
        }
    }

SECTION("Diag")
    {
    std::vector<Real> v = {{1.23234, -0.9237}};
    auto op = diagTensor(v,s1,b2);
    CHECK(typeOf(op) == Type::DiagReal);

    auto r2 = randomTensor(s1,s2);
    auto res2 = op*r2;
    CHECK(hasindex(res2,s2));
    CHECK(hasindex(res2,b2));
    auto diagm = std::min(s1.m(),b2.m());
    for(int j2 = 1; j2 <= s2.m(); ++j2)
    for(int d = 1; d <= diagm; ++d)
        {
        CHECK_CLOSE(res2.real(s2(j2),b2(d)), v.at(d-1) * r2.real(s2(j2),s1(d)));
        }
    }

SECTION("Trace")
    {
    auto T = randomTensor(s1,s2,s3);
    auto d = diagTensor(1,s1,s2);
    auto R = d*T;
    for(int i3 = 1; i3 <= s3.m(); ++i3)
        {
        Real val = 0;
        for(int i12 = 1; i12 <= s1.m(); ++i12)
            {
            val += T.real(s1(i12),s2(i12),s3(i3));
            }
        CHECK_CLOSE(val,R.real(s3(i3)));
        }
    }

SECTION("Tie Indices with Diag Tensor")
    {
    auto T = randomTensor(s1,s2,s3,s4);

    auto tied1 = Index("tied1",s1.m());
    auto tt1 = diagTensor(1,s1,s2,s3,tied1);
    auto R1 = T*tt1;
    for(int t = 1; t <= tied1.m(); ++t)
    for(int j4 = 1; j4 <= s4.m(); ++j4)
        {
        CHECK_CLOSE(T.real(s1(t),s2(t),s3(t),s4(j4)), R1.real(tied1(t),s4(j4)));
        }

    auto tied2 = Index("tied2",s1.m());
    auto tt2 = diagTensor(1,s1,s3,tied2);
    auto R2 = T*tt2;
    for(int t = 1; t <= tied1.m(); ++t)
    for(int j2 = 1; j2 <= s2.m(); ++j2)
    for(int j4 = 1; j4 <= s4.m(); ++j4)
        {
        CHECK_CLOSE(T.real(s1(t),s2(j2),s3(t),s4(j4)), R2.real(tied2(t),s2(j2),s4(j4)));
        }
    }

SECTION("Contract All Dense Inds; Diag Scalar result")
    {
    auto T = randomTensor(J,K);

    auto d1 = diagTensor(1,J,K);
    auto R = d1*T;
    CHECK(typeOf(R) == Type::DiagRealAllSame);
    Real val = 0;
    auto minjk = std::min(J.m(),K.m());
    for(long j = 1; j <= minjk; ++j)
        val += T.real(J(j),K(j));
    CHECK_CLOSE(R.real(),val);

    auto data = randomData(minjk);
    auto d2 = diagTensor(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)*T.real(J(j),K(j));
    CHECK_CLOSE(R.real(),val);
    }

SECTION("Contract All Dense Inds; Diag result")
    {
    auto T = randomTensor(J,K);
    
    auto d = diagTensor(1,J,K,L);
    auto R = d*T;
    CHECK(typeOf(R) == Type::DiagReal);
    CHECK(hasindex(R,L));
    auto minjkl = std::min(std::min(J.m(),K.m()),L.m());
    for(long j = 1; j <= minjkl; ++j)
        CHECK_CLOSE(R.real(L(j)), T.real(J(j),K(j)));
    }
}

SECTION("Kronecker Delta Tensor")
    {
    auto d = deltaTensor(s1,s2);
    CHECK(typeOf(d) == Type::Combiner);

    auto T1 = randomTensor(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.m(); ++i3)
    for(int i12 = 1; i12 <= s1.m(); ++i12)
        {
        CHECK_CLOSE(T1.real(s1(i12),s3(i3)), R1a.real(s2(i12),s3(i3)));
        CHECK_CLOSE(T1.real(s1(i12),s3(i3)), R1b.real(s2(i12),s3(i3)));
        }

    auto T2 = randomTensor(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.m(); ++i3)
    for(int i12 = 1; i12 <= s1.m(); ++i12)
        {
        CHECK_CLOSE(T2.real(s2(i12),s3(i3)), R2a.real(s1(i12),s3(i3)));
        CHECK_CLOSE(T2.real(s2(i12),s3(i3)), R2b.real(s1(i12),s3(i3)));
        }

    auto T3 = randomTensor(b8,s1,b6,a1);
    auto R3a = d*T3;
    auto R3b = T3*d;
    CHECK(hasindex(R3a,s2));
    CHECK(hasindex(R3b,s2));

    auto T4 = randomTensor(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 = combiner(s1,s2);
        CHECK(typeOf(C) == Type::Combiner);

        auto T1 = randomTensor(s1,s2,s3);
        auto R1 = C*T1;
        auto ci = commonIndex(C,R1);
        CHECK(ci);
        CHECK(ci.m() == s1.m()*s2.m());

        for(int i1 = 1; i1 <= s1.m(); ++i1)
        for(int i2 = 1; i2 <= s2.m(); ++i2)
        for(int i3 = 1; i3 <= s3.m(); ++i3)
            {
            auto j = i1+(i2-1)*s2.m();
            CHECK_CLOSE(T1.real(s1(i1),s2(i2),s3(i3)), R1.real(ci(j),s3(i3)));
            }

        auto T2 = randomTensor(s1,s3,s2);
        auto R2 = C*T2;
        CHECK(R2.r() == 2);
        ci = commonIndex(C,R2);
        CHECK(ci);
        CHECK(ci.m() == s1.m()*s2.m());
        for(int i1 = 1; i1 <= s1.m(); ++i1)
        for(int i2 = 1; i2 <= s2.m(); ++i2)
        for(int i3 = 1; i3 <= s3.m(); ++i3)
            {
            auto j = i1+(i2-1)*s2.m();
            CHECK_CLOSE(T2.real(s1(i1),s2(i2),s3(i3)), R2.real(ci(j),s3(i3)));
            }
        }

    SECTION("One Index")
        {
        auto T1 = randomTensor(s4,b5,s1,l2);

        auto cs4 = combiner(s4);
        auto Rs4a = T1*cs4;
        CHECK(!hasindex(Rs4a,s4));
        CHECK(commonIndex(cs4,Rs4a));
        auto Rs4b = cs4*T1;
        CHECK(!hasindex(Rs4b,s4));
        CHECK(commonIndex(cs4,Rs4b));

        auto cl2 = combiner(l2);
        auto Rl2a = T1*cl2;
        CHECK(!hasindex(Rl2a,l2));
        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("a",1),
              b("b",1),
              c("c",1);

        auto T = randomTensor(a,b,c);
        auto C = combiner(a,c);
        auto R = T*C;
        auto ci = commonIndex(C,R);

        CHECK(hasindex(R,ci));
        CHECK(hasindex(R,b));
        CHECK_CLOSE(T.real(a(1),b(1),c(1)),R.real(ci(1),b(1)));
        }

    SECTION("Three Index")
        {
        Index i("i",4),
              j("j",2),
              k("k",3);

        auto T = randomTensor(i,j,k);

        SECTION("Combine 1st,2nd")
            {
            auto C = combiner(i,j);
            auto R = C * T;
            auto ci = commonIndex(C,R);

            CHECK_CLOSE(norm(R),norm(T));

            for(auto i_ : count1(i.m()))
            for(auto j_ : count1(j.m()))
            for(auto k_ : count1(k.m()))
                {
                auto ci_ = i_ + i.m()*(j_-1);
                CHECK_CLOSE(R.real(ci(ci_),k(k_)), T.real(i(i_),j(j_),k(k_)));
                }
            }

        SECTION("Combine 1st,3rd")
            {
            auto C = combiner(i,k);
            auto R = C * T;
            auto ci = commonIndex(C,R);

            CHECK_CLOSE(norm(R),norm(T));

            for(auto i_ : count1(i.m()))
            for(auto j_ : count1(j.m()))
            for(auto k_ : count1(k.m()))
                {
                auto ci_ = i_ + i.m()*(k_-1);
                CHECK_CLOSE(R.real(ci(ci_),j(j_)), T.real(i(i_),j(j_),k(k_)));
                }
            }

        SECTION("Combine 2nd,3rd")
            {
            auto C = combiner(k,j);
            auto R = T * C;
            auto ci = commonIndex(C,R);

            CHECK_CLOSE(norm(R),norm(T));

            for(auto i_ : count1(i.m()))
            for(auto j_ : count1(j.m()))
            for(auto k_ : count1(k.m()))
                {
                auto ci_ = k_ + k.m()*(j_-1);
                CHECK_CLOSE(R.real(ci(ci_),i(i_)), T.real(i(i_),j(j_),k(k_)));
                }
            }


        //Uncombine back:
        //auto TT = C * R;

        //for(auto ii : count1(i.m()))
        //for(auto ij : count1(j.m()))
        //for(auto ik : count1(k.m()))
        //    {
        //    CHECK_CLOSE(TT.real(i(ii),j(ij),k(ik)), T.real(i(ii),j(ij),k(ik)));
        //    }
        }

    SECTION("Five Index")
        {
        Index i("i",2),
              j("j",3),
              k("k",4),
              l("l",5),
              m("m",6);

        auto T = randomTensor(i,j,k,l,m);

        SECTION("Combine 1,3,5")
            {
            auto C = combiner(i,k,m);
            auto R = C * T;
            auto ci = commonIndex(R,C);

            CHECK_CLOSE(norm(R),norm(T));
            
            for(auto i_ : count1(i.m()))
            for(auto j_ : count1(j.m()))
            for(auto k_ : count1(k.m()))
            for(auto l_ : count1(l.m()))
            for(auto m_ : count1(m.m()))
                {
                auto ci_ = i_+i.m()*((k_-1)+k.m()*(m_-1));
                CHECK_CLOSE(R.real(ci(ci_),j(j_),l(l_)), T.real(i(i_),j(j_),k(k_),l(l_),m(m_)));
                }
            }

        SECTION("Combine 2,3,4")
            {
            auto C = combiner(k,j,l);
            auto R = C * T;
            auto ci = commonIndex(R,C);

            CHECK_CLOSE(norm(R),norm(T));
            
            for(auto i_ : count1(i.m()))
            for(auto j_ : count1(j.m()))
            for(auto k_ : count1(k.m()))
            for(auto l_ : count1(l.m()))
            for(auto m_ : count1(m.m()))
                {
                auto ci_ = k_+k.m()*((j_-1)+j.m()*(l_-1));
                CHECK_CLOSE(R.real(ci(ci_),i(i_),m(m_)), T.real(i(i_),j(j_),k(k_),l(l_),m(m_)));
                }
            }

        //Uncombine back:
        //auto TT = C * R;

        //for(auto ii : count1(i.m()))
        //for(auto ij : count1(j.m()))
        //for(auto ik : count1(k.m()))
        //for(auto il : count1(l.m()))
        //for(auto im : count1(m.m()))
        //    {
        //    CHECK_CLOSE(TT.real(i(ii),j(ij),k(ik),l(il),m(im)), T.real(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 = randomTensor(b2,b7,b8);
T.visit(calcnrm);
CHECK_CLOSE(std::sqrt(nrm),norm(T));

nrm = 0;
T = randomTensorC(b2,b7,b8);
CHECK(typeOf(T) == Type::DenseCplx);
T.visit(calcnrm);
CHECK_CLOSE(std::sqrt(nrm),norm(T));
}

SECTION("Conj")
{
auto T1 = randomTensorC(b2,b7);
CHECK(isComplex(T1));
auto T2 = conj(T1);
for(auto j2 = 1; j2 <= b2.m(); ++j2) 
for(auto j7 = 1; j7 <= b7.m(); ++j7) 
    {
    //printfln("T1 val = %f, conj = %f, T2 val = %f",
    //         T1.cplx(b2(j2),b7(j7)),std::conj(T1.cplx(b2(j2),b7(j7))), 
    //         T2.cplx(b2(j2),b7(j7)));
    CHECK_CLOSE(std::conj(T1.cplx(b2(j2),b7(j7))), T2.cplx(b2(j2),b7(j7)));
    }
}

SECTION("SumEls")
{
auto T = randomTensor(b2,b7);
Real r = 0;
for(auto j2 = 1; j2 <= b2.m(); ++j2) 
for(auto j7 = 1; j7 <= b7.m(); ++j7) 
    {
    r += T.real(b2(j2),b7(j7));
    }
CHECK_CLOSE(sumels(T),r);

T = randomTensorC(b2,b7);
Complex z = 0;
for(auto j2 = 1; j2 <= b2.m(); ++j2) 
for(auto j7 = 1; j7 <= b7.m(); ++j7) 
    {
    z += T.cplx(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 = matrixTensor(move(M),l1,l2);
CHECK_CLOSE(T.real(l1(1),l2(1)),11);
CHECK_CLOSE(T.real(l1(1),l2(2)),12);
CHECK_CLOSE(T.real(l1(2),l2(1)),21);
CHECK_CLOSE(T.real(l1(2),l2(2)),22);
}

//SECTION("TieIndices")
//    {
//
//    Index t("tied",2);
//
//    ITensor dX(X);
//    dX.tieIndices(s1,s2,t);
//
//    CHECK_DIFF(norm(dX),0,1E-5);
//    CHECK_EQUAL(dX.r(),1);
//    CHECK(hasindex(dX,t));
//
//    ITensor dZ(Z);
//    dZ.tieIndices(s1,s2,t);
//    CHECK_DIFF(dZ(t(1)),+1,1E-5);
//    CHECK_DIFF(dZ(t(2)),-1,1E-5);
//
//    {
//    ITensor T(l1,l2,a1,s2,s1);
//    T.randomize();
//
//    ITensor TT(T);
//    TT.tieIndices(l2,l1,s1,l2);
//
//    CHECK_EQUAL(TT.r(),3);
//
//    for(int j = 1; j <= 2; ++j)
//    for(int k = 1; k <= 2; ++k)
//        {
//        CHECK_DIFF(T(l1(j),l2(j),a1(1),s2(k),s1(j)),TT(l2(j),s2(k),a1(1)),1E-5);
//        }
//    }
//
//    //Try tying m==1 inds
//    {
//    ITensor T(l1,a2,a1,s2,a3);
//    T.randomize();
//
//    ITensor TT(T);
//    TT.tieIndices(a1,a3,a2,a1);
//
//    CHECK_EQUAL(TT.r(),3);
//
//    for(int j = 1; j <= 2; ++j)
//    for(int k = 1; k <= 2; ++k)
//        {
//        CHECK_DIFF(T(l1(j),s2(k)),TT(l1(j),s2(k)),1E-5);
//        }
//    }
//
//
//
//    } //TieIndices
//
//SECTION("ComplexTieIndices")
//    {
//    ITensor Tr(l1,l2,a1,s2,s1),
//            Ti(l1,l2,a1,s2,s1);
//    Tr.randomize();
//    Ti.randomize();
//
//    ITensor T = Tr + Complex_i*Ti;
//
//    ITensor TT(T);
//    TT.tieIndices(l2,l1,s1,l2);
//
//    CHECK_EQUAL(TT.r(),3);
//
//    ITensor TTr(realPart(TT)),
//            TTi(imagPart(TT));
//
//    for(int j = 1; j <= 2; ++j)
//    for(int k = 1; k <= 2; ++k)
//        {
//        CHECK_DIFF(Tr(l1(j),l2(j),a1(1),s2(k),s1(j)),TTr(l2(j),s2(k),a1(1)),1E-5);
//        CHECK_DIFF(Ti(l1(j),l2(j),a1(1),s2(k),s1(j)),TTi(l2(j),s2(k),a1(1)),1E-5);
//        }
//    }
//
//SECTION("Trace")
//    {
//
//    ITensor A(b2,a1,b3,b5,prime(b3));
//    A.randomize();
//    Real f = -Global::random();
//    A *= f;
//
//    ITensor At = trace(A,b3,prime(b3));
//
//    for(int j2 = 1; j2 <= b2.m(); ++j2)
//    for(int j5 = 1; j5 <= b5.m(); ++j5)
//        {
//        Real val = 0;
//        for(int j3 = 1; j3 <= b3.m(); ++j3)
//            {
//            val += A(b2(j2),a1(1),b3(j3),b5(j5),prime(b3)(j3));
//            }
//        CHECK_DIFF(val,At(b2(j2),a1(1),b5(j5)),1E-10);
//        }
//
//    ITensor MM(b5,prime(b5));
//    MM.randomize();
//    MM *= -2.34;
//
//    Real tr = trace(MM);
//
//    Real check_tr = 0;
//    for(int j5 = 1; j5 <= b5.m(); ++j5)
//        {
//        check_tr += MM(b5(j5),prime(b5)(j5));
//        }
//    CHECK_DIFF(tr,check_tr,1E-10);
//
//    }
//
//SECTION("fromMatrix11")
//    {
//    Matrix M22(s1.m(),s2.m());
//
//    M22(1,1) = -0.3; M22(1,2) = 110;
//    M22(2,1) = -1.7; M22(1,2) = 5;
//
//    ITensor T(s1,s2);
//    //T should be overwritten so check
//    //that scalar mult has no effect
//    T *= -5; 
//
//    T.fromMatrix11(s1,s2,M22);
//
//    CHECK_DIFF(T(s1(1),s2(1)),M22(1,1),1E-10);
//    CHECK_DIFF(T(s1(1),s2(2)),M22(1,2),1E-10);
//    CHECK_DIFF(T(s1(2),s2(1)),M22(2,1),1E-10);
//    CHECK_DIFF(T(s1(2),s2(2)),M22(2,2),1E-10);
//
//    ITensor U(T);
//
//    U.fromMatrix11(s2,s1,M22);
//
//    CHECK_DIFF(T(s1(1),s2(1)),M22(1,1),1E-10);
//    CHECK_DIFF(T(s1(1),s2(2)),M22(1,2),1E-10);
//    CHECK_DIFF(T(s1(2),s2(1)),M22(2,1),1E-10);
//    CHECK_DIFF(T(s1(2),s2(2)),M22(2,2),1E-10);
//
//    CHECK_DIFF(U(s2(1),s1(1)),M22(1,1),1E-10);
//    CHECK_DIFF(U(s2(1),s1(2)),M22(1,2),1E-10);
//    CHECK_DIFF(U(s2(2),s1(1)),M22(2,1),1E-10);
//    CHECK_DIFF(U(s2(2),s1(2)),M22(2,2),1E-10);
//
//    Matrix M12(a1.m(),s2.m());
//    M12(1,1) = 37; M12(1,2) = -2;
//
//    ITensor P(a1,s2);
//    P *= -4;
//
//    P.fromMatrix11(a1,s2,M12);
//
//    CHECK_DIFF(P(a1(1),s2(1)),M12(1,1),1E-10);
//    CHECK_DIFF(P(a1(1),s2(2)),M12(1,2),1E-10);
//
//    P.fromMatrix11(s2,a1,M12.t());
//
//    CHECK_DIFF(P(s2(1),a1(1)),M12(1,1),1E-10);
//    CHECK_DIFF(P(s2(2),a1(1)),M12(1,2),1E-10);
//    }
//
//SECTION("ToFromMatrix11")
//    {
//    Matrix M(s1.m(),s2.m());    
//
//    Real f = -Global::random();
//
//    A *= f;
//
//    A.toMatrix11(s2,s1,M);
//
//    CHECK_DIFF(M(1,1),11*f,1E-10);
//    CHECK_DIFF(M(2,1),12*f,1E-10);
//    CHECK_DIFF(M(1,2),21*f,1E-10);
//    CHECK_DIFF(M(2,2),22*f,1E-10);
//
//    A.toMatrix11(s1,s2,M);
//
//    CHECK_DIFF(M(1,1),11*f,1E-10);
//    CHECK_DIFF(M(1,2),12*f,1E-10);
//    CHECK_DIFF(M(2,1),21*f,1E-10);
//    CHECK_DIFF(M(2,2),22*f,1E-10);
//
//    A.toMatrix11NoScale(s2,s1,M);
//
//    CHECK_DIFF(M(1,1),11,1E-10);
//    CHECK_DIFF(M(2,1),12,1E-10);
//    CHECK_DIFF(M(1,2),21,1E-10);
//    CHECK_DIFF(M(2,2),22,1E-10);
//
//    A *= -40;
//    A.fromMatrix11(s2,s1,M);
//
//    CHECK_DIFF(A(s1(1),s2(1)),11,1E-10);
//    CHECK_DIFF(A(s1(1),s2(2)),12,1E-10);
//    CHECK_DIFF(A(s1(2),s2(1)),21,1E-10);
//    CHECK_DIFF(A(s1(2),s2(2)),22,1E-10);
//
//    A.fromMatrix11(s1,s2,M);
//
//    CHECK_DIFF(A(s1(1),s2(1)),11,1E-10);
//    CHECK_DIFF(A(s1(1),s2(2)),21,1E-10);
//    CHECK_DIFF(A(s1(2),s2(1)),12,1E-10);
//    CHECK_DIFF(A(s1(2),s2(2)),22,1E-10);
//
//
//    Vector V(4);
//    V(1) = 3.14; V(2) = 2.718; V(3) = -1; V(4) = 0;
//    Index link("link",4);
//
//    ITensor T(link,a1);
//    T(link(1),a1(1)) = V(1);
//    T(link(2),a1(1)) = V(2);
//    T(link(3),a1(1)) = V(3);
//    T(link(4),a1(1)) = V(4);
//
//    Matrix M41(4,1), M14(1,4);
//    
//    T.toMatrix11(link,a1,M41);
//
//    CHECK_DIFF(M41(1,1),V(1),1E-10);
//    CHECK_DIFF(M41(2,1),V(2),1E-10);
//    CHECK_DIFF(M41(3,1),V(3),1E-10);
//    CHECK_DIFF(M41(4,1),V(4),1E-10);
//     
//    T.toMatrix11(a1,link,M14);
//
//    CHECK_DIFF(M14(1,1),V(1),1E-10);
//    CHECK_DIFF(M14(1,2),V(2),1E-10);
//    CHECK_DIFF(M14(1,3),V(3),1E-10);
//    CHECK_DIFF(M14(1,4),V(4),1E-10);
//
//    }
//
//SECTION("ToFromMatrix22")
//    {
//    Index i1("i1",3),
//          i2("i2",4),
//          i3("i3",2),
//          i4("i4",4);
//
//    ITensor T(i1,i2,i3,i4);
//    T.randomize();
//    T *= -1.23235;
//
//    Matrix M;
//    T.toMatrix22(i2,i1,i4,i3,M);
//    ITensor V;
//    V.fromMatrix22(i2,i1,i4,i3,M);
//
//    CHECK(norm(T-V) < 1E-12);
//    }
//
//SECTION("CommaAssignment")
//    {
//    ITensor VV(s1);
//    VV.randomize();
//    VV *= -1;
//    commaInit(VV,s1) << 1, 2;
//    CHECK_EQUAL(VV(s1(1)),1);
//    CHECK_EQUAL(VV(s1(2)),2);
//
//    ITensor ZZ(s1,s2);
//    commaInit(ZZ,s1,s2) << 1, 0, 
//                           0, -1;
//    CHECK_EQUAL(ZZ(s1(1),s2(1)),1);
//    CHECK_EQUAL(ZZ(s1(2),s2(1)),0);
//    CHECK_EQUAL(ZZ(s1(1),s2(2)),0);
//    CHECK_EQUAL(ZZ(s1(2),s2(2)),-1);
//
//    ITensor XX(s1,s2);
//    XX(s1(2),s2(1)) = 5;
//    XX *= 3;
//    commaInit(XX,s1,s2) << 0, 1, 
//                           1, 0;
//    CHECK_EQUAL(XX(s1(1),s2(1)),0);
//    CHECK_EQUAL(XX(s1(2),s2(1)),1);
//    CHECK_EQUAL(XX(s1(1),s2(2)),1);
//    CHECK_EQUAL(XX(s1(2),s2(2)),0);
//
//    ITensor AA(s1,s2);
//    AA.randomize();
//    AA *= -Global::random();
//    commaInit(AA,s1,s2) << 11, 12, 
//                           21, 22;
//    CHECK_EQUAL(AA(s1(1),s2(1)),11);
//    CHECK_EQUAL(AA(s1(1),s2(2)),12);
//    CHECK_EQUAL(AA(s1(2),s2(1)),21);
//    CHECK_EQUAL(AA(s1(2),s2(2)),22);
//
//    ITensor T(s1,s2,s3);
//    T.randomize();
//    T *= -Global::random();
//    commaInit(T,s1,s2,s3) << 111, 112, 
//                             121, 122,
//                             211, 212,
//                             221, 222;
//    CHECK_EQUAL(T(s1(1),s2(1),s3(1)),111);
//    CHECK_EQUAL(T(s1(1),s2(1),s3(2)),112);
//    CHECK_EQUAL(T(s1(1),s2(2),s3(1)),121);
//    CHECK_EQUAL(T(s1(1),s2(2),s3(2)),122);
//    CHECK_EQUAL(T(s1(2),s2(1),s3(1)),211);
//    CHECK_EQUAL(T(s1(2),s2(1),s3(2)),212);
//    CHECK_EQUAL(T(s1(2),s2(2),s3(1)),221);
//    CHECK_EQUAL(T(s1(2),s2(2),s3(2)),222);
//    }
//
//SECTION("RealImagPart")
//    {
//    const Real f1 = 2.124,
//               f2 = 1.113;
//    ITensor ZiX = f1*Complex_1*Z + f2*Complex_i*X;
//    ITensor 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);
//
//    //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 = randomTensor(s1,prime(s1));
//    CHECK_DIFF(norm(A),sqrt((A*A).real()),1E-5);
//
//    ITensor C = Complex_1*A+Complex_i*B;
//
//    CHECK_DIFF(norm(C),sqrt(realPart(dag(C)*C).toReal()),1E-5);
//    }

//SECTION("CR_ComplexAddition")
//    {
//    const Real f1 = 1.234,
//               f2 = 2.456;
//    ITensor iZX = f1*Complex_i*Z + f2*Complex_1*X;
//    ITensor R(realPart(iZX)),
//            I(imagPart(iZX));
//    R -= f2*X;
//    I -= f1*Z;
//    CHECK_DIFF(norm(R),0,1E-5);
//    CHECK_DIFF(norm(I),0,1E-5);
//    }
//
//SECTION("CC_ComplexAddition")
//    {
//    const Real f1 = 1.234,
//               f2 = 2.456;
//    ITensor iZiX = f1*Complex_i*Z + f2*Complex_i*X;
//    ITensor R(realPart(iZiX)),
//            I(imagPart(iZiX));
//    I -= f1*Z+f2*X;
//    CHECK_DIFF(norm(R),0,1E-5);
//    CHECK_DIFF(norm(I),0,1E-5);
//    }
//
//SECTION("ComplexScalar")
//    {
//    ITensor A(b4,s1),
//            B(b4,s1);
//    A.randomize();
//    B.randomize();
//    
//    const Real f1 = 2.1324,
//               f2 = -5.2235;
//
//    ITensor T1 = Complex(f1,0)*A;
//
//    CHECK(norm(realPart(T1)-(f1*A)) < 1E-12);
//    CHECK(norm(imagPart(T1)) < 1E-12);
//
//    ITensor T2 = Complex(0,f2)*A;
//
//    CHECK(norm(realPart(T2)) < 1E-12);
//    CHECK(norm(imagPart(T2)-f2*A) < 1E-12);
//
//    ITensor T3 = Complex(f1,f2)*A;
//    CHECK(norm(realPart(T3)-f1*A)) < 1E-12);
//    CHECK(norm(imagPart(T3)-f2*A)) < 1E-12);
//
//    ITensor T4 = Complex(f2,f1)*A;
//    CHECK(norm(realPart(T4)-f2*A)) < 1E-12);
//    CHECK(norm(imagPart(T4)-f1*A)) < 1E-12);
//
//    ITensor T5 = A+Complex_i*B;
//    T5 *= Complex(f1,f2);
//    CHECK(norm(realPart(T5)-(f1*A-f2*B))) < 1E-12);
//    CHECK(norm(imagPart(T5)-(f2*A+f1*B))) < 1E-12);
//
//    ITensor T6 = A+Complex_i*B;
//    T6 *= Complex(f2,f1);
//    CHECK(norm(realPart(T6)-(f2*A-f1*B))) < 1E-12);
//    CHECK(norm(imagPart(T6)-(f1*A+f2*B))) < 1E-12);
//    }


//SECTION("Complex Diag ITensor")
//    {
//    Vector v(3);
//    v(1) = -0.8;
//    v(2) = 1.7;
//    v(3) = 4.9;
//
//    Vector vb(2);
//    vb(1) = 1;
//    vb(2) = -1;
//
//    const Real f1 = Global::random(),
//               f2 = Global::random();
//
//    ITensor op1(s1,prime(s1),f1),
//            op2(s1,prime(s1),f2),
//            opa(s1,a1,3.1),
//            psi(s1,l1,-1),
//            opb(s1,b2,vb);
//
//    auto r1 = randomTensor(s1,prime(s1,2)),
//         r2 = randomTensor(s1,prime(s1,2));
//
//    auto op3 = op1 + Complex_i*op2;
//
//    auto res1 = op1*r1;
//    res1.mapprime(1,0);
//    ITensor diff1 = res1-f1*r1;
//    CHECK(norm(diff1) < 1E-10);
//
//    auto res2 = r1*op1;
//    res2.mapprime(1,0);
//    ITensor diff2 = res2-f1*r1;
//    CHECK(norm(diff2) < 1E-10);
//
//    auto rc = r1+Complex_i*r2;
//
//    ITensor res3 = rc*op1;
//    res3.mapprime(1,0);
//    CHECK(isComplex(res3));
//    ITensor diff3 = res3-f1*rc;
//    CHECK(norm(diff3) < 1E-10);
//
//    ITensor res4 = op1*rc;
//    res4.mapprime(1,0);
//    CHECK(isComplex(res4));
//    ITensor diff4 = res4-f1*rc;
//    CHECK(norm(diff4) < 1E-10);
//
//    ITensor res5 = rc*op3;
//    CHECK(isComplex(res5));
//    ITensor rres5(realPart(res5)),
//            ires5(imagPart(res5));
//    ITensor rdiff5 = rres5-(r1*op1-r2*op2),
//            idiff5 = ires5-(r1*op2+r2*op1);
//    CHECK(norm(rdiff5) < 1E-10);
//    CHECK(norm(idiff5) < 1E-10);
//    }

//SECTION("DiagMethod")
//    {
//    ITensor t1(b3,b4);
//    t1.randomize();
//    t1 *= -8.232244;
//    Vector d1 = t1.diag();
//    for(int i = 1; i <= minM(t1.indices()); ++i)
//        {
//        CHECK(fabs(d1(i)-t1(b3(i),b4(i))) < 1E-12);
//        }
//
//    Vector v(4);
//    v(1) = -2.2442;
//    v(2) = 1.34834;
//    v(3) = 0.0;
//    v(4) = 8.38457;
//    ITensor t2(prime(b4),b4,v);
//    CHECK(t2.type() == ITensor::Diag);
//    CHECK(Norm(v-t2.diag()) < 1E-12);
//    }




} //TEST_CASE("ITensor")


back to top