https://github.com/ITensor/ITensor
Raw File
Tip revision: 4140f057ba18c7a1b9b59b5992c5091a4e4d24d5 authored by Matthew Fishman on 02 January 2019, 23:05:02 UTC
.real() and .cplx() can take vector<IndexVal> and vector<int>
Tip revision: 4140f05
qn.h
//
// Distributed under the ITensor Library License, Version 1.2
//    (See accompanying LICENSE file.)
//
#ifndef __ITENSOR_QN_H
#define __ITENSOR_QN_H

#include "itensor/global.h"
#include "itensor/arrow.h"

namespace itensor {

//
// QN
//
// Quantum number label for IQIndexes.
//

class QN;

//
// QN convenience accessor functions
// 

//Get the Sz value
//Appropriate for QNs constructed via:
//spin, spinboson, electron, elparity
int
Sz(QN const& q);

//Get the Nb (boson number) value
//Appropriate for QNs constructed via:
//boson, spinboson
int
Nb(QN const& q);

//Get the Nf (fermion number) value
//Appropriate for QNs constructed via:
//electron
int
Nf(QN const& q);

//Get the fermion parity value.
//Either 0 for even parity or 1 for odd parity.
//Appropriate for QNs constructed via:
//electron, elparity
int
Pf(QN const& q);
//Nfp is an alias for Pf
int
Nfp(QN const& q);


size_t inline constexpr
QNSize() { return 4ul; }

//QNVal: storage element type for QN
//Represents a number with a Z (integer)
//or Z_M (integer mod M) addition rule
//
// Meaning of mod field:
// mod == 1  => Z addition
// mod >  1  => Z_M addition
// mod <  0  => same as above, fermionic
// mod == 0  => inactive/not used
struct QNVal
    {
    using qn_t = int;
    private:
    qn_t val_ = 0,
         mod_ = 0;
    public:

    QNVal() { }

    explicit QNVal(qn_t v) : val_(v), mod_(1) { }

    QNVal(qn_t v, qn_t m) : mod_(m) { set(v); }

    QNVal(std::initializer_list<qn_t> qv)
        {
        if(qv.size() != 2) Error("initializer_list arg to QNVal must have two elements");
        mod_ = *(qv.begin()+1);
        set(*(qv.begin()));
        }

    qn_t
    mod() const { return mod_; }

    qn_t
    val() const { return val_; }

    void
    set(qn_t v);

    QNVal
    operator-() const { return QNVal(-val_, mod_); }
    };

//
// QN - quantum number label for IQIndex sectors
//

class QN
    {
    public:
    using qn_t = QNVal::qn_t;
    using storage_type = std::array<QNVal,QNSize()>;
    using iterator = storage_type::iterator;
    using const_iterator = storage_type::const_iterator;
    private:
    storage_type qn_{};
    public:

    QN() { }

    // Takes named Args:
    // QN({"Sz=",-1,"Nf=",2})
    explicit
    QN(Args const& args);

    explicit
    QN(qn_t q0);

    QN(qn_t q0,
       qn_t q1);

    QN(qn_t q0,
       qn_t q1,
       qn_t q2);

    QN(qn_t q0,
       qn_t q1,
       qn_t q2,
       qn_t q3);

    template <typename T, typename... Rest>
    QN(const char* name1,
       T const& t1, 
       Rest const&... rest)
      : QN(Args(name1,t1,rest...))
        { }

    // Takes QNVal arguments,
    // specifying both a qn value in each
    // sector and a mod factor
    // Can call as as QN({0,2},{1,2})
    explicit
    QN(QNVal v0,
       QNVal v1 = QNVal{},
       QNVal v2 = QNVal{},
       QNVal v3 = QNVal{}) 
     : qn_{{v0,v1,v2,v3}} 
       { }

    explicit
    QN(std::initializer_list<qn_t> qv)
        {
        qn_[0] = qv;
        }

    explicit operator bool() const { return qn_.front().mod() != 0; }

    qn_t
    operator[](size_t n) const
        { 
#ifdef DEBUG
        return qn_.at(n).val(); 
#else
        return qn_[n].val(); 
#endif
        }

    //1-indexed
    qn_t
    operator()(size_t n) const { return operator[](n-1); }

    //1-indexed
    qn_t
    mod(size_t n) const { return qn_.at(n-1).mod(); }

    size_t
    size() const { return qn_.size(); }

    //0-indexed
    QNVal &
    val0(size_t n)
        { 
#ifdef DEBUG
        return qn_.at(n); 
#else
        return qn_[n]; 
#endif
        }

    //0-indexed
    QNVal const&
    val0(size_t n) const 
        { 
#ifdef DEBUG
        return qn_.at(n); 
#else
        return qn_[n]; 
#endif
        }

    void
    modAssign(QN const& qo);

    storage_type &
    store() { return qn_; }

    storage_type const&
    store() const { return qn_; }
    };


//
// QNVal functions
// 

bool inline
isFermionic(QNVal const& qv) { return qv.mod() < 0; }

bool inline
isActive(QNVal const& qv) { return qv.mod() != 0; }

void
operator+=(QNVal& qva, QNVal const& qvb);

void
operator-=(QNVal& qva, QNVal const& qvb);

void
operator*=(QNVal& qva, Arrow dir);

bool
operator==(QNVal const& qva, QNVal const& qvb);

bool
operator!=(QNVal const& qva, QNVal const& qvb);

void
read(std::istream & s, QNVal & q);

void
write(std::ostream & s, QNVal const& q);


//
// QN functions
// 

//1-indexed
bool inline
isActive(QN const& q, size_t n) { return isActive(q.val0(n-1)); }

bool inline
isFermionic(QN const& q, size_t n) { return q.mod(n) < 0; }

bool
operator==(QN const& qa, QN const& qb);

bool inline
operator!=(QN const& qa, QN const& qb) { return !operator==(qa,qb); }

bool
operator<(QN const& qa, QN const& qb);

QN
operator-(QN q);

void
operator+=(QN & qa, QN const& qb);

void
operator-=(QN & qa, QN const& qb);

void
operator*=(QN & qa, Arrow dir);

QN inline
operator+(QN qa, QN const& qb) { qa += qb; return qa; }

QN inline
operator-(QN qa, QN const& qb) { qa -= qb; return qa; }

QN inline
operator*(QN q, Arrow dir) { q *= dir; return q; }

QN inline
operator*(Arrow dir, QN q) { q *= dir; return q; }

std::ostream& 
operator<<(std::ostream & s, QN const& q);

//returns -1 if any sector of the QN is fermionic and odd-parity
//otherwise returns +1
int
paritySign(QN const& q);

//returns true if any sector of the QN is fermionic
bool
isFermionic(QN const& q);

void
read(std::istream & s, QN & q);

void
write(std::ostream & s, QN const& q);

void
printFull(QN const& q);


int inline
Sz(QN const& q) { return q[0]; }

int inline
Nb(QN const& q) { return isActive(q,2) ? q(2) : q(1); }

int inline
Nf(QN const& q) { return isActive(q,2) ? q(2) : q(1); }

int inline
Pf(QN const& q) { return std::abs(Nf(q))%2; }

int inline
Nfp(QN const& q) { return Pf(q); }

} //namespace itensor

#endif
back to top