Program Listing for File ED_basis.cpp

Return to documentation for file (src_ed/ED_basis.cpp)

#include <iostream>
#include <iomanip>
#include <unistd.h>
#include <set>
#include <algorithm>

#include "ED_basis.hpp"
#include "symmetry_group.hpp"
#include "fraction.hpp"

//------------------------------------------------------------------------------
// external variables or declarations

using namespace std;

//------------------------------------------------------------------------------
// variables local to this file

map<pair<int, int>, shared_ptr<ED_halfbasis>> halfbasis;

//------------------------------------------------------------------------------
// declarations local to this file

bool ED_basis::verb = false;

ED_basis::ED_basis(const sector &_sec, int _L): sec(_sec) , L(_L), dim(0)
{
    if(verb) cout << "construction of basis in sector " << sec.name() << endl;
    name = sec.name();
}




tuple<uint32_t, int, int, bool>  Destroy(const int a, const uint32_t label, const ED_mixed_basis &Bx, const ED_mixed_basis &By)
{
    tuple<uint32_t, int, int, bool> T(0,0,0,false);
    uint64_t mask = (a >= Bx.group->N) ? 1UL << (a - Bx.group->N + 32) : 1UL << a; // the literal '1UL' is crucial (not '1')
    binary_state ss = Bx.binlist[label];
    if(!(ss.b&mask)) return T;
    auto X = Bx.group->Representative(ss.b^mask, By.sec.irrep);
    if(X.length==0) return T;
    uint32_t labelp = By.index(X.b);
    if(labelp == By.dim) return T; // replace by exception raise
    if(bitcount64(ss.b & (mask-1)) & 1) X.phase += Bx.group->g;
    get<3>(T) = true;
    get<0>(T) = labelp;
    get<1>(T) = X.phase;
    get<2>(T) = X.length;
    // cout << a << '\t' << label << '\t' << labelp << endl; // tempo
    return T;
}

tuple<uint32_t, int, int, bool>  Destroy(const int a, const uint32_t label, const ED_factorized_basis &Bx, const ED_factorized_basis &By)
{
    tuple<uint32_t, int, int, bool> T(0,0,0,false);
    uint32_t label_up = label%Bx.up->dim;
    uint32_t label_down = label/Bx.up->dim;
    uint32_t ss_up = Bx.up->bin[label_up];
    uint32_t ss_down = Bx.down->bin[label_down];

    // tuple<uint32_t, uint32_t, uint32_t, uint32_t> C = Bx.components(label);

    uint32_t ssp, labelp;
    if(a >= Bx.L){ // down orbital
        uint32_t mask = 1U << (a - Bx.L);
        if(mask&ss_down) ssp = ss_down^mask;
        else return T;
        get<1>(T) = (bitcount32(ss_down&(mask-1)) + bitcount32(ss_up))%2;
        labelp = By.down->index(ssp);
        get<0>(T) = labelp*By.up->dim + label_up;
    }
    else{
        uint32_t mask = 1U << a;
        if(mask&ss_up) ssp = ss_up^mask;
        else return T;
        get<1>(T) = (bitcount32(ss_up&(mask-1)))%2;
        labelp = By.up->index(ssp);
        get<0>(T) = label_down*By.up->dim + labelp;
    }
    get<2>(T) = 1;
    get<3>(T) = true;
    // cout << a << '\t' << label << '\t' << get<0>(T) << endl; // tempo
    return T;
}

//==============================================================================
// class ED_halfbasis

ED_halfbasis::ED_halfbasis(int _L, int _N): L(_L), N(_N)
{
    size_t max_dim = 1<<L; // = 2^L
    bin.reserve(1024);

    for(uint32_t b=0; b < max_dim; ++b){
        if(bitcount32(b) != N) continue;
        bin.push_back(b);
    }
    dim = bin.size();
}

uint32_t ED_halfbasis::index(const uint32_t &b) const
{
    uint32_t I = lower_bound(bin.begin(), bin.end(), b) - bin.begin();
    if(I < dim and bin[I]==b) return I;
    else return dim;
}



//==============================================================================
// class ED_factorized_basis

ED_factorized_basis::ED_factorized_basis(const sector &_sec, int _L)
: ED_basis(_sec, _L)
{
    int Nup = sec.Nup();
    int Ndw = sec.Ndw();
    if(Nup > 32 or Ndw > 32) qcm_ED_throw("construction of factorized basis impossible : wrong mixing or N too large");

    if(halfbasis.find({L,Nup}) == halfbasis.end()) halfbasis[{L,Nup}] = make_shared<ED_halfbasis>(L, Nup);
    if(halfbasis.find({L,Ndw}) == halfbasis.end()) halfbasis[{L,Ndw}] = make_shared<ED_halfbasis>(L, Ndw);

    up = halfbasis[{L,Nup}];
    down = halfbasis[{L,Ndw}];
    dim = up->dim*down->dim;
}

binary_state ED_factorized_basis::bin(uint32_t I) const
{
    return binary_state(up->bin[I%up->dim], down->bin[I/up->dim]);
}

uint32_t ED_factorized_basis::index(const binary_state &b) const
{
    return up->index(b.left()) + up->dim*down->index(b.right());
}

void ED_factorized_basis::print_state(std::ostream &flux, uint32_t i) const
{
    PrintBinaryDouble(flux, bin(i).b, L);
}

tuple<uint32_t, uint32_t, uint32_t, uint32_t> ED_factorized_basis::components(uint32_t label) const
{
    uint32_t label_up = label%(up->dim);
    uint32_t label_down = label/up->dim;
    uint32_t ss_up = up->bin[label_up];
    uint32_t ss_down = down->bin[label_down];
    return tuple<uint32_t, uint32_t, uint32_t, uint32_t>(label_up, label_down, ss_up, ss_down);
}


//==============================================================================
// class ED_mixed_basis

ED_mixed_basis::ED_mixed_basis(const sector &_sec, shared_ptr<symmetry_group> _group):
ED_basis(_sec, _group->N), group(_group)
{
    size_t n_orb = group->N;

    if(n_orb > MAX_ORBITAL){
        qcm_ED_throw("Number of orbitals (sites) exceeds limit of " + to_string(MAX_ORBITAL));
    }
    binlist.reserve(4096);


    //..............................................................................
    // Builds the basis in the completely mixed case

    if(sec.N == sector::even and sec.S == sector::even){
        size_t max_dimup = 1<<n_orb; // = 2^n
        binlist.reserve(4096);
        dim=0;
        // Putting together
        int phase;
        int length;
        for(uint32_t i=0; i<max_dimup; ++i){
            for(uint32_t j=0; j<max_dimup; ++j){
                binary_state b(i,j);
                if(b.count()%2) continue; // reject if odd number of particles
                binary_state b0=b;
                auto R = group->Representative(b, sec.irrep);
                if(R.length and  R.b == b0) binlist.push_back(R.b);
            }
        }
    }
    if(sec.N == sector::odd and sec.S == sector::odd){
        size_t max_dimup = 1<<n_orb; // = 2^n
        binlist.reserve(4096);
        dim=0;
        // Putting together
        int phase;
        int length;
        for(uint32_t i=0; i<max_dimup; ++i){
            for(uint32_t j=0; j<max_dimup; ++j){
                binary_state b(i,j);
                if(b.count()%2 == 0) continue; // reject if even number of particles
                binary_state b0=b;
                auto R = group->Representative(b, sec.irrep);
                if(R.length and  R.b == b0) binlist.push_back(R.b);
            }
        }
    }

    //..............................................................................
    // Builds the basis in the anomalous case (no spin flip)

    else if(sec.N >= sector::odd and sec.S < sector::odd){
        size_t max_dimup = 1<<n_orb; // = 2^n
        dim=0;
        for(size_t Nup=0; Nup <= n_orb; Nup++){
            size_t Ndw = Nup - sec.S;
            if(Ndw > n_orb) continue;
            vector<uint32_t> bin_up; // list of binary up states with Nup electrons
            vector<uint32_t> bin_dw; // list of binary up states with Ndw electrons
            bin_up.reserve(1024);
            bin_dw.reserve(1024);
            // construction of bin_up
            for(uint32_t bup=0; bup < max_dimup; ++bup){
                if(bitcount32(bup) != Nup) continue;
                bin_up.push_back(bup);
            }
            size_t nbup = bin_up.size();
            // construction of bin_dw
            for(uint32_t bdw=0; bdw < max_dimup; ++bdw){
                if(bitcount32(bdw) != Ndw) continue;
                bin_dw.push_back(bdw);
            }
            size_t nbdw = bin_dw.size();

            // Putting together
            int phase;
            int length;
            for(size_t i=0; i<nbup; ++i){
                for(size_t j=0; j<nbdw; ++j){
                    binary_state b(bin_dw[j],bin_up[i]);
                    binary_state b0=b;
                    auto R = group->Representative(b, sec.irrep);
                    if(R.length and  R.b == b0) binlist.push_back(R.b);
                }
            }
        }
    }

    //..............................................................................
    // Builds the basis in the spin flip case (no anomalous terms)

    else if(sec.N < sector::odd and sec.S >= sector::odd){
        uint32_t max_dimup = 1<<n_orb; // = 2^n
        dim=0;
        for(size_t Nup=0; Nup <= n_orb; Nup++){
            size_t Ndw = -Nup + sec.N;
            if(Ndw > n_orb) continue;
            vector<uint32_t> bin_up; // list of binary up states with Nup electrons
            vector<uint32_t> bin_dw; // list of binary up states with Ndw electrons
            binlist.reserve(4096);
            bin_up.reserve(1024);
            bin_dw.reserve(1024);
            // construction of bin_up
            for(uint32_t bup=0; bup < max_dimup; ++bup){
                if(bitcount32(bup) != Nup) continue;
                bin_up.push_back(bup);
            }
            size_t nbup = bin_up.size();
            // construction of bin_dw
            for(uint32_t bdw=0; bdw < max_dimup; ++bdw){
                if(bitcount32(bdw) != Ndw) continue;
                bin_dw.push_back(bdw);
            }
            size_t nbdw = bin_dw.size();

            // Putting together
            int phase;
            int length;
            for(size_t i=0; i<nbup; ++i){
                for(size_t j=0; j<nbdw; ++j){
                    binary_state b(bin_dw[j],bin_up[i]);
                    binary_state b0=b;
                    auto R = group->Representative(b, sec.irrep);
                    if(R.length and  R.b == b0) binlist.push_back(R.b);
                }
            }
        }
    }

    //..............................................................................
    // Builds the basis in the unmixed case

    else {
        size_t max_dimup = 1<<n_orb; // = 2^n
        size_t Nup = (sec.N + sec.S)/2; // number of up electrons
        size_t Ndw = (sec.N - sec.S)/2; // number of down electrons
        vector<uint32_t> bin_up; // list of binary up states with Nup electrons
        vector<uint32_t> bin_dw; // list of binary up states with Ndw electrons
        bin_up.reserve(1024);
        bin_dw.reserve(1024);

        // construction of bin_up
        for(uint32_t bup=0; bup < max_dimup; ++bup){
            if(bitcount32(bup) != Nup) continue;
            bin_up.push_back(bup);
        }
        size_t nbup = bin_up.size();

        // construction of bin_dw
        for(uint32_t bdw=0; bdw < max_dimup; ++bdw){
            if(bitcount32(bdw) != Ndw) continue;
            bin_dw.push_back(bdw);
        }
        size_t nbdw = bin_dw.size();

        dim=0;
        // Putting together
        int phase;
        int length;
        for(size_t i=0; i<nbup; ++i){
            for(size_t j=0; j<nbdw; ++j){
                binary_state b(bin_dw[j],bin_up[i]);
                binary_state b0=b;
                auto R = group->Representative(b, sec.irrep);
                if(R.length and  R.b == b0) binlist.push_back(R.b);
            }
        }
    }

  //..............................................................................
  // sorting

  dim = binlist.size();
  sort(binlist.begin(), binlist.end());
  if(verb) cout << "dimension = " << dim << endl;
}

ED_mixed_basis::~ED_mixed_basis()
{
    binlist.clear();
}


inline binary_state ED_mixed_basis::bin(uint32_t I) const
{
    return binlist[I];
}

uint32_t ED_mixed_basis::index(const binary_state &b) const
{
  uint32_t I = lower_bound(binlist.begin(), binlist.end(), b) - binlist.begin();
  if(I < dim and binlist[I]==b) return I;
  else return dim;
}


void ED_mixed_basis::print_state(std::ostream &flux, uint32_t i) const
{
    int phase;
    auto R = group->Representative(binlist[i], sec.irrep);
    if(R.length == 0) return;
    if(group->g > 1) flux << '[' << R.length << "]\t";
    PrintBinaryDouble(flux, binlist[i].b, group->N);
    set<binary_state> s;
    for(size_t j=1; j<group->g; ++j){
        s.insert(binlist[i]);
        auto Y = group->apply(j, sec.irrep, binlist[i]);
        if(s.count(Y.first)==0){
            s.insert(Y.first);
            if(Y.second==0) flux << " + ";
            else if(Y.second==group->g) flux << " - ";
            else{
                fraction f((int)Y.second,(int)group->g); f.simplify();
                flux << " + exp(i pi " << f << ") ";
            }
            PrintBinaryDouble(flux, Y.first.b, group->N);
        }
    }
}




std::ostream & operator<<(std::ostream &flux, const ED_basis &B)
{
    size_t n_orb = B.L;

    flux << "---------------------------------------------------------------------------------\n";
    flux << "Basis " << B.name << "\t(" << B.dim << " states)\n";
    if(B.dim > 1024) return flux;
    flux << "List of basis states\n";
    for(size_t i=0; i<B.dim; ++i){
        flux << i+1 << '\t';
        B.print_state(flux, i);
        flux << '\n';
    }
    return flux;
}