https://github.com/ITensor/ITensor
Raw File
Tip revision: 6b54fa39438c296f80049dc937ca966746eded68 authored by Miles Stoudenmire on 11 April 2016, 18:02:29 UTC
Updated localop.h diag method to correctly use delta function to tie indices. Fixes #96 - thanks to Xiongjie Yu for reporting it.
Tip revision: 6b54fa3
qn.cc
#include "itensor/qn.h"

namespace itensor {

QN::
QN(qn_t q0)
    {
    qn_[0] = QNVal(q0);
    }

QN::
QN(qn_t q0,
   qn_t q1)
    {
    qn_[0] = QNVal(q0);
    qn_[1] = QNVal(q1);
    }

QN::
QN(qn_t q0,
   qn_t q1,
   qn_t q2)
    {
    qn_[0] = QNVal(q0);
    qn_[1] = QNVal(q1);
    qn_[2] = QNVal(q2);
    }

QN::
QN(qn_t q0,
   qn_t q1,
   qn_t q2,
   qn_t q3)
    {
    qn_[0] = QNVal(q0);
    qn_[1] = QNVal(q1);
    qn_[2] = QNVal(q2);
    qn_[3] = QNVal(q3);
    }

QN::
QN(Args const& args)
    {
    auto hasSz = args.defined("Sz");
    auto start = hasSz ? 1 : 0;

    if(hasSz) qn_[0] = args.getInt("Sz");

    if(args.defined("Nb"))
        {
        qn_[start] = QNVal(args.getInt("Nb"),+1);
        }
    else if(args.defined("Nf"))
        {
        qn_[start] = QNVal(args.getInt("Nf"),-1);
        }
    else if(args.defined("Pf"))
        {
        qn_[start] = QNVal(args.getInt("Pf"),-2);
        }
    }

void QN::
modAssign(QN const& qo)
    {
    for(size_t n = 0; n < QNSize(); ++n)
        {
        qn_[n] = QNVal(qn_[n].val(),qo.qn_[n].mod());
        }
    }

void QNVal::
set(qn_t v)
    { 
    auto m = std::abs(mod_);
    if(m > 1) 
        {
        // Here v is the value we want to compute mod m.
        // If v >= 0 then it's enough to compute v%m.
        // If v < 0 we don't want -(|v|%m) which is what
        // C++'s v%m operation gives. Instead we want
        // to map, say, -1 to m-1 and -m-1 to m-1 etc.
        // Observe that m*|v| > v (since m > 1).
        // So m*|v|+v for negative v will always be > 0
        // and mod'ing this will give the desired behavior.
        val_ = (m*std::abs(v)+v)%m;
        }
    else                   
        {
        val_ = v;
        }
    }


void
operator+=(QNVal& qva, QNVal const& qvb) 
    { 
#ifdef DEBUG
    if(qva.mod() != qvb.mod())
        {
        printfln("qva.mod()=%d, qvb.mod()=%d",qva.mod(),qvb.mod());
        Error("Mismatched mod factors");
        }
#endif
    qva.set(qva.val()+qvb.val());
    }

void
operator-=(QNVal& qva, QNVal const& qvb) 
    { 
    assert(qva.mod() == qvb.mod());
    qva.set(qva.val()-qvb.val());
    }

void
operator*=(QNVal& qva, Arrow dir)
    { 
    qva.set(qva.val() * static_cast<int>(dir));
    }

bool
operator==(QNVal const& qva, QNVal const& qvb)
    {
    assert(qva.mod() == qvb.mod());
    return qva.val() == qvb.val();
    }

bool
operator!=(QNVal const& qva, QNVal const& qvb)
    {
    assert(qva.mod() == qvb.mod());
    return qva.val() != qvb.val();
    }

void
read(std::istream & s, QNVal & q)
    {
    QNVal::qn_t v = 0,
                m = 0;
    itensor::read(s,v);
    itensor::read(s,m);
    q = QNVal(v,m);
    }

void
write(std::ostream & s, QNVal const& q)
    {
    itensor::write(s,q.val());
    itensor::write(s,q.mod());
    }

void
printFull(QN const& q)
    {
    print("QN(");
    for(auto n : range1(QNSize()))
        {
        if(!isActive(q,n)) break;
        if(n > 1) print(",");
        print("{",q(n),",",q.mod(n),"}");
        }
    println(")");
    }

bool
operator==(QN const& qa, QN const& qb)
    {
    for(size_t n = 0; n < QNSize(); ++n)
        {
        if(qa.val0(n).val() != qb.val0(n).val()) return false;
        }
    return true;
    }

bool
operator<(QN const& qa, QN const& qb)
    {
    for(size_t n = 0; n < QNSize(); ++n)
        {
        if(qa.val0(n).val() == qb.val0(n).val()) continue;
        return qa.val0(n).val() < qb.val0(n).val();
        }
    return false;
    }

QN
operator-(QN q)
    {
    for(size_t n = 0; n < QNSize(); ++n)
        {
        q.val0(n) = -q.val0(n);
        }
    return q;
    }

void
operator+=(QN & qa, QN const& qb) 
    { 
    if(!qa) qa.modAssign(qb);
    if(!qb) return;
    for(size_t n = 0; n < QNSize() && isActive(qa.val0(n)); ++n)
        {
        qa.val0(n) += qb.val0(n);
        }
    }

void
operator-=(QN & qa, QN const& qb) 
    { 
    if(!qa) qa.modAssign(qb);
    if(!qb) return;
    for(size_t n = 0; n < QNSize() && isActive(qa.val0(n)); ++n)
        {
        qa.val0(n) -= qb.val0(n);
        }
    }

void
operator*=(QN & qa, Arrow dir)
    { 
    for(size_t n = 0; n < QNSize() && isActive(qa.val0(n)); ++n)
        {
        qa.val0(n) *= dir;
        }
    }

std::ostream& 
operator<<(std::ostream & s, QN const& q)
    {
    if(q.mod(1) == 1 && !isActive(q,2))
        {
        //spin or spinless boson
        s << "QN(" << q(1) << ")";
        }
    else
    if(q.mod(1) == -1 && !isActive(q,2))
        {
        //spinless fermion
        s << "(Nf=" << q(1) << ")";
        }
    else
    if(q.mod(1) == -2 && !isActive(q,2))
        {
        //parity-only spinless fermion
        s << "(Pf=" << q(1) << ")";
        }
    else
    if(q.mod(1) == 1 && q.mod(2) == -1 && !isActive(q,3))
        {
        //electron
        s << "(Sz=" << q(1) << ",Nf=" << q(2) << ")";
        }
    else
    if(q.mod(1) == 1 && q.mod(2) == -2 && !isActive(q,3))
        {
        //"superconducting" electron (parity conservation only)
        s << "(Sz=" << q(1) << ",Pf=" << q(2) << ")";
        }
    else
        {
        //catch-all behavior
        s << "QN(";
        for(auto n : range1(QNSize()))
            {
            if(!isActive(q,n)) break;
            if(n > 1) s << ",";
            if(q.mod(n) != 1)
                {
                s << "{" << q(n) << "," << q.mod(n) << "}";
                }
            else
                {
                s << q(n);
                }
            }
        s << ")";
        }
    return s;
    }

int
paritySign(QN const& q)
    {
    int p = 1;
    for(size_t n = 0; n < QNSize() && isActive(q.val0(n)); ++n)
        {
        if(isFermionic(q.val0(n)) && std::abs(q[n])%2==1)
            {
            p *= -1;
            }
        }
    return p;
    }

bool
isFermionic(QN const& q)
    {
    for(size_t n = 0; n < QNSize() && isActive(q.val0(n)); ++n)
        {
        if(isFermionic(q.val0(n))) return true;
        }
    return false;
    }

void
read(std::istream & s, QN & q)
    {
    for(auto& el : q.store())
        itensor::read(s,el);
    }

void
write(std::ostream & s, QN const& q)
    {
    for(auto& el : q.store())
        itensor::write(s,el);
    }
} //namespace itensor
back to top