ABACUS/src/SCAN/Descendents.cc

1189 lines
52 KiB
C++

/**********************************************************
This software is part of J.-S. Caux's ABACUS library.
Copyright (c) J.-S. Caux.
-----------------------------------------------------------
File: Descendents.cc
Purpose: New implementation of state scanning:
functions to descend down hierarchy of states.
***********************************************************/
#include "ABACUS.h"
using namespace std;
using namespace ABACUS;
namespace ABACUS {
Vect<string> Descendent_States_with_iK_Stepped_Up
(string ScanIx2_label, const Vect<Vect<int> >& OriginIx2, const Vect<Vect<int> >& BaseScanIx2,
const Vect<int>& Ix2_min, const Vect<int>& Ix2_max, bool disperse_only_current_exc, bool preserve_nexc)
{
// Given an OriginIx2 and a BaseScanIx2 (by which we mean a set of Ix2 providing a basis for scanning),
// this function returns a vector of the labels of the states obtained by each allowable
// one-step increase of the quantum numbers.
// Rules for moving quantum numbers:
// - quantum numbers preserve their ordering (an Umklapp is thus made of many one-step movements)
// - if a quantum number has moved as compared to BaseScanIx2, then it can only move further in the same direction
// The ordering rule for allowable increases is that we start from the topmost, rightmost quantum number.
// The increases can thus be applied to quantum numbers below the bottom-most, left-most right-displaced quantum nr.
// The preserve_nexc boolean flags whether we maintain or increase the nr of ph pairs.
// This is only checked if disperse_only_current_exc == false (otherwise it's irrelevant).
Vect<Vect<int> > ScanIx2 = Return_Ix2_from_Label (ScanIx2_label, OriginIx2);
// Determine the level and index of the bottom-most left-most right-moving quantum number sits:
int exclevel = -1;
int excindex = 0;
bool excfound = false;
do {
exclevel++;
if (exclevel == ScanIx2.size()) { // there isn't a single right-moving quantum number in ScanIx2
break;
}
for (int alpha = 0; alpha < ScanIx2[exclevel].size(); ++alpha)
if (ScanIx2[exclevel][alpha] > BaseScanIx2[exclevel][alpha]) {
excindex = alpha;
excfound = true;
break;
}
} while (!excfound);
// If we haven't found an excitation, then exclevel == ScanIx2.size() and excindex = 0;
// The quantum numbers which we can move right are thus those
// with (j < exclevel) and (j == exclelev and alpha <= excindex)
int ndesc_possible = 1;
if (!disperse_only_current_exc) {
ndesc_possible = 0;
for (int j = 0; j <= ABACUS::min(exclevel, ScanIx2.size() -1); ++j) ndesc_possible += ScanIx2[j].size();
}
// Now construct the actual descendents:
Vect<string> desclabelfound (ndesc_possible);
int ndesc_found = 0;
if (!disperse_only_current_exc && !preserve_nexc)
// List descendents with a new excitation at a lower level:
// this can only create an additional ph pair
for (int j = 0; j < exclevel; ++j)
for (int alpha = 0; alpha < ScanIx2[j].size(); ++alpha) {
if (ScanIx2[j][alpha] >= BaseScanIx2[j][alpha] // candidate either undisplaced or right-moving
&& !ScanIx2[j].includes(ScanIx2[j][alpha] + 2) // there is a hole to its right
&& ScanIx2[j][alpha] + 2 <= Ix2_max[j]) { // this new quantum number fits within the limits
// We've found a descendent
ScanIx2[j][alpha] += 2;
desclabelfound[ndesc_found] = Return_State_Label (ScanIx2, OriginIx2);
ScanIx2[j][alpha] -= 2;
ndesc_found++;
}
}
// List descendents with a new excitation at exclevel:
if (exclevel < ScanIx2.size()) { // excfound == true, excindex is now guaranteed < ScanIx2[exclevel].size()
int alphamin = (disperse_only_current_exc ? excindex : 0);
int alphamax = (disperse_only_current_exc ? excindex : excindex - 1);
//for (int alpha = 0; alpha <= excindex; ++alpha) {
for (int alpha = alphamin; alpha <= alphamax; ++alpha) {
if (ScanIx2[exclevel][alpha] >= BaseScanIx2[exclevel][alpha]
&& !ScanIx2[exclevel].includes(ScanIx2[exclevel][alpha] + 2)
&& ScanIx2[exclevel][alpha] + 2 <= Ix2_max[exclevel]) {
// We've found a descendent
ScanIx2[exclevel][alpha] += 2;
desclabelfound[ndesc_found] = Return_State_Label (ScanIx2, OriginIx2);
ScanIx2[exclevel][alpha] -= 2;
// If we're dispersing a subleading Ix2, check whether we match the preserve_nexc condition:
// The descendent is acceptable if disperse_only_current_exc == true,
// or if preserve_nexc == true and nexc labels match,
// or if preserve_nexc == false and nexc labels don't match:
if (disperse_only_current_exc
//|| (preserve_nexc == BaseScanIx2[exclevel].includes(ScanIx2[exclevel][alpha] + 2)))
|| (preserve_nexc == (Extract_nexc_Label(desclabelfound[ndesc_found]
).compare(Extract_nexc_Label(ScanIx2_label)) == 0)))
ndesc_found++;
}
}
} //if (exclevel < ScanIx2.size())
// Resize desc:
Vect<string> desclabelfound_resized(ndesc_found);
for (int idesc = 0; idesc < ndesc_found; ++idesc)
desclabelfound_resized[idesc] = desclabelfound[idesc];
return(desclabelfound_resized);
}
Vect<string> Descendent_States_with_iK_Stepped_Down
(string ScanIx2_label, const Vect<Vect<int> >& OriginIx2, const Vect<Vect<int> >& BaseScanIx2,
const Vect<int>& Ix2_min, const Vect<int>& Ix2_max, bool disperse_only_current_exc, bool preserve_nexc)
{
// Given an OriginIx2 and a BaseScanIx2 (by which we mean a set of Ix2 providing a basis for scanning),
// this function returns a vector of the labels of the states obtained by each allowable
// one-step decrease of the quantum numbers.
// Rules for moving quantum numbers:
// - quantum numbers preserve their ordering (an Umklapp is thus made of many one-step movements)
// - if a quantum number has moved as compared to BaseScanIx2, then it can only move further in the same direction
// The ordering rule for allowable decreases is that we start from the topmost, leftmost quantum number.
// The decreases can thus be applied to quantum numbers below the bottom-most, right-most left-displaced quantum nr.
// The preserve_nexc boolean flags whether we maintain or increase the nr of ph pairs.
// This is only checked if disperse_only_current_exc == false (otherwise it's irrelevant).
Vect<Vect<int> > ScanIx2 = Return_Ix2_from_Label (ScanIx2_label, OriginIx2);
// Determine the level and index of the bottom-most right-most left-moving quantum number sits:
int exclevel = -1;
int excindex = 0;
bool excfound = false;
do {
exclevel++;
if (exclevel == ScanIx2.size()) { // there isn't a single left-moving quantum number in ScanIx2
break;
}
for (int alpha = ScanIx2[exclevel].size() - 1; alpha >= 0; --alpha) {
if (ScanIx2[exclevel][alpha] < BaseScanIx2[exclevel][alpha]) {
excindex = alpha;
excfound = true;
break;
}
}
} while (!excfound);
// If we haven't found an excitation, then exclevel == ScanIx2.size() and excindex = 0;
// The quantum numbers which we can move left are thus those
// with (j < exclevel) and (j == exclelev and alpha >= excindex)
int ndesc_possible = 1;
if (!disperse_only_current_exc) {
ndesc_possible = 0;
for (int j = 0; j <= ABACUS::min(exclevel, ScanIx2.size() - 1); ++j) ndesc_possible += ScanIx2[j].size();
}
// Now construct the actual descendents:
Vect<string> desclabelfound (ndesc_possible);
int ndesc_found = 0;
if (!disperse_only_current_exc && !preserve_nexc)
// List descendents with a new excitation at a lower level:
for (int j = 0; j < exclevel; ++j)
for (int alpha = 0; alpha < ScanIx2[j].size(); ++alpha) {
if (ScanIx2[j][alpha] <= BaseScanIx2[j][alpha] // candidate either undisplaced or left-moving
&& !ScanIx2[j].includes(ScanIx2[j][alpha] - 2) // there is a hole to its left
&& ScanIx2[j][alpha] - 2 >= Ix2_min[j]) { // this new quantum number fits within the limits
// We've found a descendent
ScanIx2[j][alpha] -= 2;
desclabelfound[ndesc_found] = Return_State_Label (ScanIx2, OriginIx2);
ScanIx2[j][alpha] += 2;
ndesc_found++;
}
}
// List descendents with a new excitation at exclevel:
if (exclevel < ScanIx2.size()) { // excfound == true, excindex is now guaranteed < ScanIx2[exclevel].size()
int alphamin = (disperse_only_current_exc ? excindex : excindex + 1);
int alphamax = (disperse_only_current_exc ? excindex : ScanIx2[exclevel].size() - 1);
for (int alpha = alphamax; alpha >= alphamin; --alpha) {
if (ScanIx2[exclevel][alpha] <= BaseScanIx2[exclevel][alpha]
&& !ScanIx2[exclevel].includes(ScanIx2[exclevel][alpha] - 2)
&& ScanIx2[exclevel][alpha] - 2 >= Ix2_min[exclevel]) {
ScanIx2[exclevel][alpha] -= 2;
desclabelfound[ndesc_found] = Return_State_Label (ScanIx2, OriginIx2);
ScanIx2[exclevel][alpha] += 2;
if (disperse_only_current_exc
|| (preserve_nexc == (Extract_nexc_Label(desclabelfound[ndesc_found]
).compare(Extract_nexc_Label(ScanIx2_label)) == 0)))
ndesc_found++;
}
}
} // if (exclevel < ScanIx2.size())
// Resize desc:
Vect<string> desclabelfound_resized(ndesc_found);
for (int idesc = 0; idesc < ndesc_found; ++idesc)
desclabelfound_resized[idesc] = desclabelfound[idesc];
return(desclabelfound_resized);
}
Vect<string> Descendent_States_with_iK_Preserved
(string ScanIx2_label, const Vect<Vect<int> >& OriginIx2, const Vect<Vect<int> >& BaseScanIx2,
const Vect<int>& Ix2_min, const Vect<int>& Ix2_max,
bool disperse_only_current_exc_up, bool preserve_nexc_up,
bool disperse_only_current_exc_down, bool preserve_nexc_down)
{
// Returns the labels of all states which are obtained from ScanIx2 by stepping p one step, and down one step.
Vect<string> labels_up = Descendent_States_with_iK_Stepped_Up
(ScanIx2_label, OriginIx2, BaseScanIx2, Ix2_min, Ix2_max, disperse_only_current_exc_up, preserve_nexc_up);
Vect<string> labels_found(0);
for (int i = 0; i < labels_up.size(); ++i) {
labels_found.Append (Descendent_States_with_iK_Stepped_Down
(labels_up[i], OriginIx2, BaseScanIx2, Ix2_min, Ix2_max,
disperse_only_current_exc_down, preserve_nexc_down));
}
return(labels_found);
}
// For symmetric state descending:
Vect<string> Descendent_States_with_iK_Stepped_Up_rightIx2only
(string ScanIx2_label, const Vect<Vect<int> >& OriginIx2, const Vect<Vect<int> >& BaseScanIx2,
const Vect<int>& Ix2_min, const Vect<int>& Ix2_max, bool disperse_only_current_exc, bool preserve_nexc)
{
// This function raises an Ix2 in the right half of ScanIx2, and does the symmetric lowering in the lower half.
// ASSUMPTIONS: OriginIx2 is a symmetric state.
Vect<Vect<int> > ScanIx2 = Return_Ix2_from_Label (ScanIx2_label, OriginIx2);
// Determine the level and index of the bottom-most left-most right-moving quantum number sits:
int exclevel = -1;
int excindex = 0;
bool excfound = false;
do {
exclevel++;
if (exclevel == ScanIx2.size()) { // there isn't a single right-moving quantum number in ScanIx2
break;
}
for (int alpha = (ScanIx2[exclevel].size() + 1)/2; alpha < ScanIx2[exclevel].size(); ++alpha)
if (ScanIx2[exclevel][alpha] > BaseScanIx2[exclevel][alpha]) {
excindex = alpha;
excfound = true;
break;
}
} while (!excfound);
// If we haven't found an excitation, then exclevel == ScanIx2.size() and excindex = 0;
// The quantum numbers which we can move right are thus those
// with (j < exclevel) and (j == exclelev and alpha <= excindex)
int ndesc_possible = 1;
if (!disperse_only_current_exc) {
ndesc_possible = 0;
for (int j = 0; j <= ABACUS::min(exclevel, ScanIx2.size() -1); ++j) ndesc_possible += ScanIx2[j].size();
}
// Now construct the actual descendents:
Vect<string> desclabelfound (ndesc_possible);
int ndesc_found = 0;
if (!disperse_only_current_exc && !preserve_nexc)
// List descendents with a new excitation at a lower level:
// this can only create an additional ph pair
for (int j = 0; j < exclevel; ++j)
for (int alpha = (ScanIx2[j].size() + 1)/2; alpha < ScanIx2[j].size(); ++alpha) {
if (ScanIx2[j][alpha] >= BaseScanIx2[j][alpha] // candidate either undisplaced or right-moving
&& !ScanIx2[j].includes(ScanIx2[j][alpha] + 2) // there is a hole to its right
&& ScanIx2[j][alpha] + 2 <= Ix2_max[j]) { // this new quantum number fits within the limits
// We've found a descendent
ScanIx2[j][alpha] += 2;
ScanIx2[j][ScanIx2[j].size() - 1 - alpha] -= 2;
desclabelfound[ndesc_found] = Return_State_Label (ScanIx2, OriginIx2);
ScanIx2[j][alpha] -= 2;
ScanIx2[j][ScanIx2[j].size() - 1 - alpha] += 2;
ndesc_found++;
}
}
// List descendents with a new excitation at exclevel:
if (exclevel < ScanIx2.size()) { // excfound == true, excindex is now guaranteed < ScanIx2[exclevel].size()
int alphamin = (disperse_only_current_exc ? excindex : 0);
alphamin = ABACUS::max((ScanIx2[exclevel].size() + 1)/2, alphamin);
int alphamax = (disperse_only_current_exc ? excindex : excindex - 1);
for (int alpha = alphamin; alpha <= alphamax; ++alpha) {
if (ScanIx2[exclevel][alpha] >= BaseScanIx2[exclevel][alpha]
&& !ScanIx2[exclevel].includes(ScanIx2[exclevel][alpha] + 2)
&& ScanIx2[exclevel][alpha] + 2 <= Ix2_max[exclevel]) {
// We've found a descendent
ScanIx2[exclevel][alpha] += 2;
ScanIx2[exclevel][ScanIx2[exclevel].size() - 1 - alpha] -= 2;
desclabelfound[ndesc_found] = Return_State_Label (ScanIx2, OriginIx2);
ScanIx2[exclevel][alpha] -= 2;
ScanIx2[exclevel][ScanIx2[exclevel].size() - 1 - alpha] += 2;
// If we're dispersing a subleading Ix2, check whether we match the preserve_nexc condition:
// The descendent is acceptable if disperse_only_current_exc == true,
// or if preserve_nexc == true and nexc labels match,
// or if preserve_nexc == false and nexc labels don't match:
if (disperse_only_current_exc
|| (preserve_nexc == (Extract_nexc_Label(desclabelfound[ndesc_found]
).compare(Extract_nexc_Label(ScanIx2_label)) == 0)))
ndesc_found++;
}
}
} //if (exclevel < ScanIx2.size())
// Resize desc:
Vect<string> desclabelfound_resized(ndesc_found);
for (int idesc = 0; idesc < ndesc_found; ++idesc)
desclabelfound_resized[idesc] = desclabelfound[idesc];
return(desclabelfound_resized);
}
Vect<string> Descendent_States_with_iK_Stepped_Down_rightIx2only
(string ScanIx2_label, const Vect<Vect<int> >& OriginIx2, const Vect<Vect<int> >& BaseScanIx2,
const Vect<int>& Ix2_min, const Vect<int>& Ix2_max, bool disperse_only_current_exc, bool preserve_nexc)
{
Vect<Vect<int> > ScanIx2 = Return_Ix2_from_Label (ScanIx2_label, OriginIx2);
// Determine the level and index of the bottom-most right-most left-moving quantum number sits:
int exclevel = -1;
int excindex = 0;
bool excfound = false;
do {
exclevel++;
if (exclevel == ScanIx2.size()) { // there isn't a single left-moving quantum number in ScanIx2
break;
}
for (int alpha = ScanIx2[exclevel].size() - 1; alpha >= (ScanIx2[exclevel].size() + 1)/2 ; --alpha) {
if (ScanIx2[exclevel][alpha] < BaseScanIx2[exclevel][alpha]) {
excindex = alpha;
excfound = true;
break;
}
}
} while (!excfound);
// If we haven't found an excitation, then exclevel == ScanIx2.size() and excindex = 0;
// The quantum numbers which we can move left are thus those
// with (j < exclevel) and (j == exclevel and alpha >= excindex)
int ndesc_possible = 1;
if (!disperse_only_current_exc) {
ndesc_possible = 0;
for (int j = 0; j <= ABACUS::min(exclevel, ScanIx2.size() - 1); ++j) ndesc_possible += ScanIx2[j].size();
}
// Now construct the actual descendents:
Vect<string> desclabelfound (ndesc_possible);
int ndesc_found = 0;
if (!disperse_only_current_exc && !preserve_nexc)
// List descendents with a new excitation at a lower level:
for (int j = 0; j < exclevel; ++j)
for (int alpha = (ScanIx2[j].size() + 1)/2; alpha < ScanIx2[j].size(); ++alpha) {
if (ScanIx2[j][alpha] <= BaseScanIx2[j][alpha] // candidate either undisplaced or left-moving
&& !ScanIx2[j].includes(ScanIx2[j][alpha] - 2) // there is a hole to its left
&& ScanIx2[j][alpha] - 2 >= Ix2_min[j]) { // this new quantum number fits within the limits
// We've found a descendent
ScanIx2[j][alpha] -= 2;
ScanIx2[j][ScanIx2[j].size() - 1 - alpha] += 2;
desclabelfound[ndesc_found] = Return_State_Label (ScanIx2, OriginIx2);
ScanIx2[j][alpha] += 2;
ScanIx2[j][ScanIx2[j].size() - 1 - alpha] -= 2;
ndesc_found++;
}
}
// List descendents with a new excitation at exclevel:
if (exclevel < ScanIx2.size()) { // excfound == true, excindex is now guaranteed < ScanIx2[exclevel].size()
int alphamin = (disperse_only_current_exc ? excindex : excindex + 1);
alphamin = ABACUS::max((ScanIx2[exclevel].size() + 1)/2, alphamin);
int alphamax = (disperse_only_current_exc ? excindex : ScanIx2[exclevel].size() - 1);
for (int alpha = alphamax; alpha >= alphamin; --alpha) {
if (ScanIx2[exclevel][alpha] <= BaseScanIx2[exclevel][alpha]
&& !ScanIx2[exclevel].includes(ScanIx2[exclevel][alpha] - 2)
&& ScanIx2[exclevel][alpha] - 2 >= Ix2_min[exclevel]) {
ScanIx2[exclevel][alpha] -= 2;
ScanIx2[exclevel][ScanIx2[exclevel].size() - 1 - alpha] += 2;
desclabelfound[ndesc_found] = Return_State_Label (ScanIx2, OriginIx2);
ScanIx2[exclevel][alpha] += 2;
ScanIx2[exclevel][ScanIx2[exclevel].size() - 1 - alpha] -= 2;
if (disperse_only_current_exc
|| (preserve_nexc == (Extract_nexc_Label(desclabelfound[ndesc_found]
).compare(Extract_nexc_Label(ScanIx2_label)) == 0)))
ndesc_found++;
}
}
} // if (exclevel < ScanIx2.size())
// Resize desc:
Vect<string> desclabelfound_resized(ndesc_found);
for (int idesc = 0; idesc < ndesc_found; ++idesc)
desclabelfound_resized[idesc] = desclabelfound[idesc];
return(desclabelfound_resized);
}
// Specialization for Lieb-Liniger case:
Vect<string> Descendent_States_with_iK_Stepped_Up (string ScanIx2_label, const LiebLin_Bethe_State& OriginState,
bool disperse_only_current_exc, bool preserve_nexc)
{
Vect<Vect<int> > OriginIx2here(1);
OriginIx2here[0] = OriginState.Ix2;
Vect<Vect<int> > BaseScanIx2here(1);
BaseScanIx2here[0] = OriginState.Ix2;
Vect<int> Ix2_min(1);
Ix2_min[0] = LIEBLIN_Ix2_MIN;
Vect<int> Ix2_max(1);
Ix2_max[0] = LIEBLIN_Ix2_MAX;
return (Descendent_States_with_iK_Stepped_Up (ScanIx2_label, OriginIx2here, BaseScanIx2here, Ix2_min, Ix2_max,
disperse_only_current_exc, preserve_nexc));
}
// Specialization for Lieb-Liniger case:
Vect<string> Descendent_States_with_iK_Stepped_Down (string ScanIx2_label, const LiebLin_Bethe_State& OriginState,
bool disperse_only_current_exc, bool preserve_nexc)
{
Vect<Vect<int> > OriginIx2here(1);
OriginIx2here[0] = OriginState.Ix2;
Vect<Vect<int> > BaseScanIx2here(1);
BaseScanIx2here[0] = OriginState.Ix2;
Vect<int> Ix2_min(1);
Ix2_min[0] = LIEBLIN_Ix2_MIN;
Vect<int> Ix2_max(1);
Ix2_max[0] = LIEBLIN_Ix2_MAX;
return (Descendent_States_with_iK_Stepped_Down (ScanIx2_label, OriginIx2here, BaseScanIx2here, Ix2_min, Ix2_max,
disperse_only_current_exc, preserve_nexc));
}
// Specialization for Lieb-Liniger case:
Vect<string> Descendent_States_with_iK_Preserved (string ScanIx2_label, const LiebLin_Bethe_State& OriginState,
bool disperse_only_current_exc_up, bool preserve_nexc_up,
bool disperse_only_current_exc_down, bool preserve_nexc_down)
{
Vect<Vect<int> > OriginIx2here(1);
OriginIx2here[0] = OriginState.Ix2;
Vect<Vect<int> > BaseScanIx2here(1);
BaseScanIx2here[0] = OriginState.Ix2;
Vect<int> Ix2_min(1);
Ix2_min[0] = LIEBLIN_Ix2_MIN;
Vect<int> Ix2_max(1);
Ix2_max[0] = LIEBLIN_Ix2_MAX;
return (Descendent_States_with_iK_Preserved (ScanIx2_label, OriginIx2here, BaseScanIx2here, Ix2_min, Ix2_max,
disperse_only_current_exc_up, preserve_nexc_up,
disperse_only_current_exc_down, preserve_nexc_down));
}
// Specialization for Lieb-Liniger case:
Vect<string> Descendent_States_with_iK_Stepped_Up_rightIx2only
(string ScanIx2_label, const LiebLin_Bethe_State& OriginState, bool disperse_only_current_exc, bool preserve_nexc)
{
Vect<Vect<int> > OriginIx2here(1);
OriginIx2here[0] = OriginState.Ix2;
Vect<Vect<int> > BaseScanIx2here(1);
BaseScanIx2here[0] = OriginState.Ix2;
Vect<int> Ix2_min(1);
Ix2_min[0] = LIEBLIN_Ix2_MIN;
Vect<int> Ix2_max(1);
Ix2_max[0] = LIEBLIN_Ix2_MAX;
return(Descendent_States_with_iK_Stepped_Up_rightIx2only (ScanIx2_label, OriginIx2here, BaseScanIx2here,
Ix2_min, Ix2_max, disperse_only_current_exc, preserve_nexc));
}
Vect<string> Descendent_States_with_iK_Stepped_Down_rightIx2only
(string ScanIx2_label, const LiebLin_Bethe_State& OriginState, bool disperse_only_current_exc, bool preserve_nexc)
{
Vect<Vect<int> > OriginIx2here(1);
OriginIx2here[0] = OriginState.Ix2;
Vect<Vect<int> > BaseScanIx2here(1);
BaseScanIx2here[0] = OriginState.Ix2;
Vect<int> Ix2_min(1);
Ix2_min[0] = LIEBLIN_Ix2_MIN;
Vect<int> Ix2_max(1);
Ix2_max[0] = LIEBLIN_Ix2_MAX;
return(Descendent_States_with_iK_Stepped_Down_rightIx2only (ScanIx2_label, OriginIx2here, BaseScanIx2here,
Ix2_min, Ix2_max, disperse_only_current_exc, preserve_nexc));
}
// Specializations for Heis states:
Vect<string> Descendent_States_with_iK_Stepped_Up
(string ScanIx2_label, const Heis_Bethe_State& OriginState, bool disperse_only_current_exc, bool preserve_nexc)
{
return(Descendent_States_with_iK_Stepped_Up (ScanIx2_label, OriginState.Ix2, OriginState.Ix2, OriginState.base.Ix2_min,
OriginState.base.Ix2_max, disperse_only_current_exc, preserve_nexc));
}
Vect<string> Descendent_States_with_iK_Stepped_Down
(string ScanIx2_label, const Heis_Bethe_State& OriginState, bool disperse_only_current_exc, bool preserve_nexc)
{
return(Descendent_States_with_iK_Stepped_Down (ScanIx2_label, OriginState.Ix2, OriginState.Ix2, OriginState.base.Ix2_min,
OriginState.base.Ix2_max, disperse_only_current_exc, preserve_nexc));
}
Vect<string> Descendent_States_with_iK_Preserved
(string ScanIx2_label, const Heis_Bethe_State& OriginState, bool disperse_only_current_exc_up, bool preserve_nexc_up,
bool disperse_only_current_exc_down, bool preserve_nexc_down)
{
return(Descendent_States_with_iK_Preserved
(ScanIx2_label, OriginState.Ix2, OriginState.Ix2,
OriginState.base.Ix2_min, OriginState.base.Ix2_max, disperse_only_current_exc_up, preserve_nexc_up,
disperse_only_current_exc_down, preserve_nexc_down));
}
Vect<string> Descendent_States_with_iK_Stepped_Up_rightIx2only
(string ScanIx2_label, const Heis_Bethe_State& OriginState, bool disperse_only_current_exc, bool preserve_nexc)
{
return(Descendent_States_with_iK_Stepped_Up_rightIx2only
(ScanIx2_label, OriginState.Ix2, OriginState.Ix2, OriginState.base.Ix2_min, OriginState.base.Ix2_max,
disperse_only_current_exc, preserve_nexc));
}
Vect<string> Descendent_States_with_iK_Stepped_Down_rightIx2only
(string ScanIx2_label, const Heis_Bethe_State& OriginState, bool disperse_only_current_exc, bool preserve_nexc)
{
return(Descendent_States_with_iK_Stepped_Down_rightIx2only
(ScanIx2_label, OriginState.Ix2, OriginState.Ix2, OriginState.base.Ix2_min, OriginState.base.Ix2_max,
disperse_only_current_exc, preserve_nexc));
}
Vect<bool> Is_Good_New_Hole_Position (const Vect<Vect<int> >& OriginIx2, State_Label_Data currentdata, int exclevel_newph)
{
// Given a state, returns the acceptable new hole positions.
// Define the objects for the newstatedata:
Vect<int> type_new = currentdata.type;
Vect<int> M_new = currentdata.M;
Vect<int> nexc_new = currentdata.nexc;
nexc_new[exclevel_newph] += 1; // we drill one more particle-hole pair at this level
int index_new = (currentdata.nexc[exclevel_newph] + 1)/2; // we put the new p-h pair at index index_new.
int ntypespresent = currentdata.type.size();
Vect<Vect<int> > Ix2old_new(ntypespresent);
Vect<Vect<int> > Ix2exc_new(ntypespresent);
for (int it = 0; it < ntypespresent; ++it) Ix2old_new[it] = Vect<int>(ABACUS::max(nexc_new[it],1));
for (int it = 0; it < ntypespresent; ++it) Ix2exc_new[it] = Vect<int>(ABACUS::max(nexc_new[it],1));
// Copy earlier data in:
for (int it = 0; it < ntypespresent; ++it) {
for (int i = 0; i < currentdata.nexc[it]; ++i) {
Ix2old_new[it][i + (it == exclevel_newph && i >= index_new)] = currentdata.Ix2old[it][i];
Ix2exc_new[it][i + (it == exclevel_newph && i >= index_new)] = currentdata.Ix2exc[it][i];
}
}
State_Label_Data descdatanewph (type_new, M_new, nexc_new, Ix2old_new, Ix2exc_new);
// We now look for all possible hole positions,
// the allowable ones being either at the edge of a block, or next to an existing hole excitation,
// under the condition of obeying the `towards the block center' rule.
Vect<bool> isgoodnewholepos(false, OriginIx2[descdatanewph.type[exclevel_newph] ].size());
for (int ih = 0; ih < OriginIx2[descdatanewph.type[exclevel_newph] ].size(); ++ih) {
int candidateIx2old = OriginIx2[descdatanewph.type[exclevel_newph] ][ih];
// candidateIx2old is an acceptable position for the new hole provided the following conditions are fulfilled:
// A- it is in OriginIx2
// B- it follows the ordering rule, i.e. it sits in the middle of previous particle excitations,
// namely between Ix2old[index_new - 1] (if this exists) and Ix2old[index_new] (if this exists)
// C- it is next to an OriginIx2 vacancy or immediately right of Ix2old[index_new - 1] (if this exists)
// or immediately left of Ix2old[index_new] (if this exists)
// D- it does not break the `towards the center' rule
// (it will break the rule at this point if it is created away from an OriginIx2 boundary
// (and thus next to a preexisting excitation),
// and if this excitation and it are not in the same sideblock
// (in other words: if there is a sideblock boundary between them)
// A
if (!OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2old)) {
// is not contained in OriginIx2
continue;
}
// B1
if (currentdata.nexc[exclevel_newph] > 0
&& candidateIx2old <= currentdata.Ix2old[exclevel_newph][index_new - 1]) {
// there is at least one hole exc to the left, and the candidate position isn't right of Ix2old[index_new - 1]
continue;
}
// B2
if (currentdata.nexc[exclevel_newph] > 1
&& candidateIx2old >= currentdata.Ix2old[exclevel_newph][index_new]) {
// there is at least one hole exc to the right, and the candidate position isn't left of Ix2old[index_new]
continue;
}
// C- it is next to an OriginIx2 vacancy or immediately right of Ix2old[index_new - 1] (if this exists)
// or immediately left of Ix2old[index_new] (if this exists)
if (!(!OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2old + 2)
|| !OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2old - 2))
// doesn't sit next to an OriginIx2 vacancy
&& (currentdata.nexc[exclevel_newph] == 0
|| candidateIx2old != currentdata.Ix2old[exclevel_newph][index_new - 1] + 2)
// doesn't sit immediately right of first hole excitation to the left
&& (currentdata.nexc[exclevel_newph] <= 1
|| candidateIx2old != currentdata.Ix2old[exclevel_newph][index_new] - 2)
// doesn't sit immediately left of first hole excitation to the right
) {
continue;
}
// D- it does not break the `towards the center' rule
// In other words, if created away from a block boundary but next to a preexisting hole,
// must be in same sideblock as this particle:
// Determine the size of the block of OriginIx2 in which this hole sits:
int nroccupiedtoleft = 0;
while (OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2old -2*(nroccupiedtoleft + 1)))
nroccupiedtoleft++;
int nroccupiedtoright = 0;
while (OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2old +2*(nroccupiedtoright + 1)))
nroccupiedtoright++;
// We can determine whether the new hole would be left- or right-moving
bool hole_candidate_is_left_moving = nroccupiedtoleft >= nroccupiedtoright;
bool hole_candidate_is_right_moving = nroccupiedtoleft < nroccupiedtoright;
if (hole_candidate_is_left_moving
&& (currentdata.nexc[exclevel_newph] > 0 && candidateIx2old == currentdata.Ix2old[exclevel_newph][index_new - 1] + 2)
// it is created to the right of a preexisting hole excitation
&& OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2old + 2)
// and is not sitting at the boundary
&& (currentdata.nexc[exclevel_newph] <= 1 || candidateIx2old != currentdata.Ix2old[exclevel_newph][index_new] - 2)
// and is not sitting just left of another preexisting hole excitation which is also left moving
)
{
continue;
}
if (hole_candidate_is_right_moving
&& (currentdata.nexc[exclevel_newph] > 1 && candidateIx2old == currentdata.Ix2old[exclevel_newph][index_new] - 2)
// it is created to the left of a preexisting hole excitation
&& OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2old - 2)
// and is not sitting at the boundary
&& (currentdata.nexc[exclevel_newph] == 0
|| candidateIx2old != currentdata.Ix2old[exclevel_newph][index_new - 1] + 2)
// and is not sitting just right of another preexisting hole excitation which is also right moving
)
{
continue;
}
// If we have reached this point, candidateIx2old is acceptable.
isgoodnewholepos[ih] = true;
} // for (int ih
return(isgoodnewholepos);
} // Vect<bool> Is_Good_New_Hole_Position
Vect<string> Descendents (string ScanStateLabel, const Vect<Vect<int> >& ScanIx2, const Vect<Vect<int> >& OriginIx2,
const Vect<int>& Ix2_min, const Vect<int>& Ix2_max, int type_required)
{
// This generates descendents for a fixed base.
// As compared to the OriginState, ScanState thus has only (in-level) particle-hole excitations
// ASSUMPTIONS:
// ScanStateLabel is consistent with ScanIx2 and OriginIx2.
// type_required == 0: inner (right)most hole moved
// type_required == 1: inner (right)most particle moved
// type_required == 2: new particle-hole pair added, keeping only closest p < h and p > h cases
// type_required == 3: at level 0, move leftmost particle one step left, rightmost one step right
// (fixed iK logic using skeletons).
// type_required == 4: generalized Umklapp: increase distance between latest-added p-h pair,
// staying on boundary of blocks
bool cinbreaks = false;
// Number of descendents:
int ndesc_possible = 1;
if (type_required == 1 || type_required == 2) {
for (int i = 0; i < ScanIx2.size(); ++i)
ndesc_possible = ABACUS::max (ndesc_possible, 2* ScanIx2[i].size() * 2 * ScanIx2[i].size());
// inexact, should be refined
}
Vect<string> desclabelfound (ndesc_possible);
Vect<int> desctypefound (ndesc_possible);
int ndesc_found = 0;
// First read the current state data:
State_Label_Data currentdata = Read_State_Label (ScanStateLabel, OriginIx2);
// Determine the level at which the highest current excitation sits
int exclevel = currentdata.type.size() - 1;
while (exclevel > 0 && currentdata.nexc[exclevel] == 0) exclevel--;
if (type_required == 0) {
// We move the inner(right)most hole of the highest excited level one more step towards
// the center of the block of Ix2 vacancies in which it sits.
// Is there already an excitation at level 0? If so, move inner(right)most particle one step further.
if (currentdata.nexc[0] > 0) {
// Produce a new state_label_data:
State_Label_Data descdata = Read_State_Label (ScanStateLabel, OriginIx2);
// Identify the inner(right)most excitation:
int innerindex = currentdata.nexc[exclevel]/2;
int newholepos = currentdata.Ix2old[exclevel][innerindex];
// Determine the size of the block of OriginState.Ix2 in which this hole sits:
int nroccupiedtoleft = 0;
while (OriginIx2[descdata.type[exclevel] ].includes (currentdata.Ix2old[exclevel][innerindex]
-2*(nroccupiedtoleft + 1)))
nroccupiedtoleft++;
int nroccupiedtoright = 0;
while (OriginIx2[descdata.type[exclevel] ].includes (currentdata.Ix2old[exclevel][innerindex]
+2*(nroccupiedtoright + 1)))
nroccupiedtoright++;
if (nroccupiedtoleft - nroccupiedtoright + 2 < 0) newholepos += 2;
else if (nroccupiedtoleft - nroccupiedtoright - 2 >= 0) newholepos -= 2;
if (newholepos != currentdata.Ix2old[exclevel][innerindex] // we have successfully moved the hole
&& !currentdata.Ix2old[exclevel].includes(newholepos) // new hole position is not already taken
)
{ // we have found a descendent
descdata.Ix2old[exclevel][innerindex] = newholepos;
desclabelfound[ndesc_found] = Return_State_Label (descdata, OriginIx2);
desctypefound[ndesc_found] = 0;
ndesc_found++;
if (cinbreaks) { char a; cin >> a;}
}
} // if (currentdata.nexc[exclevel] > 0)
} // if (type_required == 0)
if (type_required == 1) {
// We move the inner(right)most particle of the highest excited level one more step towards
// the center of the block of Ix2 vacancies in which it sits.
// Is there already an excitation at level 0? If so, move inner(right)most particle one step further.
if (currentdata.nexc[exclevel] > 0) {
// Produce a new state_label_data:
State_Label_Data descdata = Read_State_Label (ScanStateLabel, OriginIx2);
// Identify the inner(right)most excitation:
int innerindex = currentdata.nexc[exclevel]/2;
int partpos = currentdata.Ix2exc[exclevel][innerindex];
// Determine the size of the block of OriginState.Ix2 vacancies in which this particle sits:
bool partpos_is_left_of_all_OriginIx2 = (partpos <= OriginIx2[descdata.type[exclevel] ].min());
bool partpos_is_right_of_all_OriginIx2 = (partpos >= OriginIx2[descdata.type[exclevel] ].max());
int nremptytoleft = 0;
if (partpos_is_left_of_all_OriginIx2) nremptytoleft = (partpos - Ix2_min[descdata.type[exclevel] ])/2;
else while (!OriginIx2[descdata.type[exclevel] ].includes (partpos -2*(nremptytoleft + 1)))
nremptytoleft++;
int nremptytoright = 0;
if (partpos_is_right_of_all_OriginIx2) nremptytoright = (Ix2_max[descdata.type[exclevel] ] - partpos)/2;
else while (!OriginIx2[descdata.type[exclevel] ].includes (partpos +2*(nremptytoright + 1)))
nremptytoright++;
if (!partpos_is_left_of_all_OriginIx2 && (partpos_is_right_of_all_OriginIx2
|| nremptytoleft - nremptytoright + 2 < 0))
partpos += 2;
else if (!partpos_is_right_of_all_OriginIx2 && (partpos_is_left_of_all_OriginIx2
|| nremptytoleft - nremptytoright - 2 >= 0))
partpos -= 2;
if (partpos != currentdata.Ix2exc[exclevel][innerindex] // we have successfully moved the particle
&& !OriginIx2[descdata.type[exclevel] ].includes(partpos) // it's actually a new particle position
&& !currentdata.Ix2exc[exclevel].includes(partpos) // new particle position is not already taken
&& partpos >= Ix2_min[descdata.type[exclevel] ]
&& partpos <= Ix2_max[descdata.type[exclevel] ]
)
{ // we have found a descendent
descdata.Ix2exc[exclevel][innerindex] = partpos;
desclabelfound[ndesc_found] = Return_State_Label (descdata, OriginIx2);
desctypefound[ndesc_found] = 1;
ndesc_found++;
if (cinbreaks) { char a; cin >> a;}
}
} // if (currentdata.nexc[exclevel] > 0)
} // if (type_required == 1)
if (type_required == 2) {
// Now add a new p-h pair at the inner(right)most position, at each level from exclevel upwards,
// putting the particle and hole to each available positions at the edge of vacancy/occupancy blocks.
for (int exclevel_newph = exclevel; exclevel_newph < currentdata.nexc.size(); ++exclevel_newph) {
if (ScanIx2[currentdata.type[exclevel_newph] ].size() <= currentdata.nexc[exclevel_newph])
continue; // no space for another p-h
// Define the objects for the newstatedata:
Vect<int> type_new = currentdata.type;
Vect<int> M_new = currentdata.M;
Vect<int> nexc_new = currentdata.nexc;
nexc_new[exclevel_newph] += 1; // we drill one more particle-hole pair at this level
int index_new = (currentdata.nexc[exclevel_newph] + 1)/2; // we put the new p-h pair at index index_new.
//int ntypespresent = ScanIx2.size();
int ntypespresent = currentdata.type.size();
Vect<Vect<int> > Ix2old_new(ntypespresent);
Vect<Vect<int> > Ix2exc_new(ntypespresent);
for (int it = 0; it < ntypespresent; ++it) Ix2old_new[it] = Vect<int>(ABACUS::max(nexc_new[it],1));
for (int it = 0; it < ntypespresent; ++it) Ix2exc_new[it] = Vect<int>(ABACUS::max(nexc_new[it],1));
// Copy earlier data in:
for (int it = 0; it < ntypespresent; ++it) {
for (int i = 0; i < currentdata.nexc[it]; ++i) {
Ix2old_new[it][i + (it == exclevel_newph && i >= index_new)] = currentdata.Ix2old[it][i];
Ix2exc_new[it][i + (it == exclevel_newph && i >= index_new)] = currentdata.Ix2exc[it][i];
}
}
State_Label_Data descdatanewph (type_new, M_new, nexc_new, Ix2old_new, Ix2exc_new);
// We now look for all possible hole positions,
// the allowable ones being either at the edge of a block, or next to an existing hole excitation,
// under the condition of obeying the `towards the block center' rule.
Vect<bool> isgoodnewholepos = Is_Good_New_Hole_Position (OriginIx2, currentdata, exclevel_newph);
// We now look for all possible particle positions,
// the allowable ones being either at the edge of a block, or next to an existing particle excitation,
// under the condition of obeying the `towards the block center' rule.
// Determine range of possible Ix2exc:
int Ix2excmin = ScanIx2[descdatanewph.type[exclevel_newph] ].min() - 2;
if (currentdata.nexc[exclevel_newph] > 0)
Ix2excmin = ABACUS::min (Ix2excmin, currentdata.Ix2exc[exclevel_newph][index_new - 1] + 2);
Ix2excmin = ABACUS::max (Ix2excmin, Ix2_min[descdatanewph.type[exclevel_newph] ]);
int Ix2excmax = ScanIx2[descdatanewph.type[exclevel_newph] ].max() + 2;
if (currentdata.nexc[exclevel_newph] > 1)
Ix2excmax = ABACUS::max (Ix2excmax, currentdata.Ix2exc[exclevel_newph][index_new] - 2);
Ix2excmax = ABACUS::min (Ix2excmax, Ix2_max[descdatanewph.type[exclevel_newph] ]);
Vect<bool> isgoodnewpartpos(false, (Ix2excmax - Ix2excmin)/2 + 1);
for (int candidateIx2exc = Ix2excmin; candidateIx2exc <= Ix2excmax; candidateIx2exc += 2) {
// candidateIx2exc is an acceptable position for the new particle provided the following conditions are fulfilled:
// A- it is not in OriginIx2
// B- it follows the ordering rule, i.e. it sits in the middle of previous particle excitations,
// namely between Ix2exc[index_new - 1] (if this exists) and Ix2exc[index_new] (if this exists)
// C- it is next to an OriginIx2 or immediately right of Ix2exc[index_new - 1] (if this exists)
// or immediately left of Ix2exc[index_new] (if this exists)
// D- it does not break the `towards the center' rule
// (it will break the rule at this point if it is created away from an OriginIx2 boundary
// (and thus next to a preexisting excitation),
// and if this excitation and it are not in the same sideblock
// (in other words: if there is a sideblock boundary between them)
// A
if (OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2exc)) {
// is contained in OriginIx2
continue;
}
// B1
if (currentdata.nexc[exclevel_newph] > 0
&& candidateIx2exc <= currentdata.Ix2exc[exclevel_newph][index_new - 1]) {
// there is at least one particle exc to the left, and the candidate position isn't right of Ix2exc[index_new - 1]
continue;
}
// B2
if (currentdata.nexc[exclevel_newph] > 1
&& candidateIx2exc >= currentdata.Ix2exc[exclevel_newph][index_new]) {
// there is at least one particle exc to the right, and the candidate position isn't left of Ix2exc[index_new]
continue;
}
// C- it is next to an OriginIx2 or immediately right of Ix2exc[index_new - 1] (if this exists)
// or immediately left of Ix2exc[index_new] (if this exists)
if (!(OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2exc + 2)
|| OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2exc - 2))
// doesn't sit next to an OriginIx2
&& (currentdata.nexc[exclevel_newph] == 0
|| candidateIx2exc != currentdata.Ix2exc[exclevel_newph][index_new - 1] + 2)
// doesn't sit immediately right of first particle excitation to the left
&& (currentdata.nexc[exclevel_newph] <= 1
|| candidateIx2exc != currentdata.Ix2exc[exclevel_newph][index_new] - 2)
// doesn't sit immediately left of first particle excitation to the right
) {
continue;
}
// D- it does not break the `towards the center' rule
// In other words, if created away from a block boundary but next to a preexisting particle,
// must be in same sideblock as this particle:
// Determine the size of the block of OriginIx2 vacancies in which this particle sits:
bool candidate_is_left_of_all_OriginIx2 =
(candidateIx2exc < OriginIx2[descdatanewph.type[exclevel_newph] ].min()); // this makes it left-moving
bool candidate_is_right_of_all_OriginIx2 =
(candidateIx2exc > OriginIx2[descdatanewph.type[exclevel_newph] ].max()); // this makes it right-moving
int nremptytoleft = 0;
if (candidate_is_left_of_all_OriginIx2)
nremptytoleft = (candidateIx2exc - Ix2_min[descdatanewph.type[exclevel_newph] ])/2;
else while (!OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2exc -2*(nremptytoleft + 1)))
nremptytoleft++;
int nremptytoright = 0;
if (candidate_is_right_of_all_OriginIx2)
nremptytoright = (Ix2_max[descdatanewph.type[exclevel_newph] ] - candidateIx2exc)/2;
else while (!OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2exc +2*(nremptytoright + 1)))
nremptytoright++;
// We can determine whether the new particle would be left- or right-moving
bool candidate_is_left_moving = candidate_is_left_of_all_OriginIx2
|| (!candidate_is_right_of_all_OriginIx2 && nremptytoleft >= nremptytoright);
bool candidate_is_right_moving = candidate_is_right_of_all_OriginIx2
|| (!candidate_is_left_of_all_OriginIx2 && nremptytoleft < nremptytoright);
// Consistency checks:
if (candidate_is_left_moving && candidate_is_right_moving)
ABACUSerror("New particle moving left and right at same time");
if (!candidate_is_left_moving && !candidate_is_right_moving)
ABACUSerror("New particle not moving either left or right");
if (candidate_is_left_moving
&& (currentdata.nexc[exclevel_newph] > 0
&& candidateIx2exc == currentdata.Ix2exc[exclevel_newph][index_new - 1] + 2)
// it is created to the right of a preexisting particle excitation
&& !OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2exc + 2)
// and is not sitting at the boundary
&& (currentdata.nexc[exclevel_newph] <= 1
|| candidateIx2exc != currentdata.Ix2exc[exclevel_newph][index_new] - 2)
// and is not sitting just left of another preexisting particle excitation which is also left moving
)
{
continue;
}
if (candidate_is_right_moving
&& (currentdata.nexc[exclevel_newph] > 1
&& candidateIx2exc == currentdata.Ix2exc[exclevel_newph][index_new] - 2)
// it is created to the left of a preexisting particle excitation
&& !OriginIx2[descdatanewph.type[exclevel_newph] ].includes (candidateIx2exc - 2)
// and is not sitting at the boundary
&& (currentdata.nexc[exclevel_newph] == 0
|| candidateIx2exc != currentdata.Ix2exc[exclevel_newph][index_new - 1] + 2)
// and is not sitting just right of another preexisting particle excitation which is also right moving
)
{
continue;
}
// If we have reached this point, candidateIx2exc is acceptable.
// Immediately construct all descendents with this part position:
// We now select the hole position closest to left or right:
int ihclosestleft = -1;
int ihclosestright = -1;
for (int ih = 0; ih < OriginIx2[descdatanewph.type[exclevel_newph] ].size(); ++ih)
if (isgoodnewholepos[ih])
{
if (OriginIx2[descdatanewph.type[exclevel_newph] ][ih] - candidateIx2exc < 0)
// new hole is left of new particle
if (ihclosestleft == -1 // we hadn't found a hole previously
|| ihclosestleft >= 0 // we had aleady found a new hole to the left
&& OriginIx2[descdatanewph.type[exclevel_newph] ][ih] >
OriginIx2[descdatanewph.type[exclevel_newph] ][ihclosestleft])
ihclosestleft = ih;
if (OriginIx2[descdatanewph.type[exclevel_newph] ][ih] - candidateIx2exc > 0)
// new hole is right of new particle
if (ihclosestright == -1 // we hadn't found a hole previously
|| ihclosestright >= 0 // we had aleady found a new hole to the right
&& OriginIx2[descdatanewph.type[exclevel_newph] ][ih] <
OriginIx2[descdatanewph.type[exclevel_newph] ][ihclosestright])
ihclosestright = ih;
} // if (isgoodnewholepos[ih])
// for ih
if (ihclosestleft >= 0) { // Found a descendent with new hole to left of new particle
descdatanewph.Ix2old[exclevel_newph][index_new] = OriginIx2[descdatanewph.type[exclevel_newph] ][ihclosestleft];
descdatanewph.Ix2exc[exclevel_newph][index_new] = candidateIx2exc;
desclabelfound[ndesc_found] = Return_State_Label (descdatanewph, OriginIx2);
desctypefound[ndesc_found] = 2;
ndesc_found++;
}
if (ihclosestright >= 0) { // Found a descendent with new hole to right of new particle
descdatanewph.Ix2old[exclevel_newph][index_new] = OriginIx2[descdatanewph.type[exclevel_newph] ][ihclosestright];
descdatanewph.Ix2exc[exclevel_newph][index_new] = candidateIx2exc;
desclabelfound[ndesc_found] = Return_State_Label (descdatanewph, OriginIx2);
desctypefound[ndesc_found] = 2;
ndesc_found++;
}
} // for (int candidateIx2exc)
} // for (int exclevel_newph)
} // if (type_required == 2)
if (type_required == 3) {
// We here only move the leftmost Ix2[0] left, and rightmost Ix2[0] right (this preserves iK)
if (ScanIx2[0][0] > Ix2_min[0] && ScanIx2[0][ScanIx2[0].size() - 1] < Ix2_max[0]) {
Vect<Vect<int> > descIx2 = ScanIx2;
descIx2[0][0] -= 2;
descIx2[0][descIx2[0].size() - 1] += 2;
desclabelfound[ndesc_found] = Return_State_Label (descIx2, OriginIx2);
desctypefound[ndesc_found] = 3;
ndesc_found++;
}
} // if (type_required == 3)
if (type_required == 4) {
// We take the latest particle-hole pair, and move the hole to a further generalized Umklapp position
State_Label_Data descdata = currentdata;
// Start by finding the possible hole positions of the state without the innermost p-h pair:
Vect<int> nexc_new = currentdata.nexc;
if (currentdata.nexc[exclevel] < 1)
ABACUSerror("Should not call type 3 descendent if there are no ph exc at exclevel");
nexc_new[exclevel] -= 1; // we remove the innermost ph pair
int innerindex = currentdata.nexc[exclevel]/2; // index of ph pair we remove
int ntypespresent = currentdata.type.size();
Vect<Vect<int> > Ix2old_new(ntypespresent);
Vect<Vect<int> > Ix2exc_new(ntypespresent);
for (int it = 0; it < ntypespresent; ++it) Ix2old_new[it] = Vect<int>(ABACUS::max(nexc_new[it],1));
for (int it = 0; it < ntypespresent; ++it) Ix2exc_new[it] = Vect<int>(ABACUS::max(nexc_new[it],1));
// Copy earlier data in:
for (int it = 0; it < ntypespresent; ++it) {
for (int i = 0; i < nexc_new[it]; ++i) {
Ix2old_new[it][i] = currentdata.Ix2old[it][i + (it == exclevel && i >= innerindex)];
Ix2exc_new[it][i] = currentdata.Ix2exc[it][i + (it == exclevel && i >= innerindex)];
}
}
State_Label_Data data_latest_ph_removed (currentdata.type, currentdata.M, nexc_new, Ix2old_new, Ix2exc_new);
Vect<bool> isgoodnewholepos = Is_Good_New_Hole_Position (OriginIx2, data_latest_ph_removed, exclevel);
// Move hole further away from its corresponding particle, preserving the direction
bool holemovingleft = currentdata.Ix2old[exclevel][innerindex] < currentdata.Ix2exc[exclevel][innerindex];
int inewhole;
if (holemovingleft) {
inewhole = 0;
while (OriginIx2[currentdata.type[exclevel] ][inewhole] != currentdata.Ix2old[exclevel][innerindex]) inewhole++;
do {
inewhole--;
} while (inewhole >= 0 && !isgoodnewholepos[inewhole]);
}
if (!holemovingleft) {
inewhole = OriginIx2[currentdata.type[exclevel] ].size() - 1;
while (OriginIx2[currentdata.type[exclevel] ][inewhole] != currentdata.Ix2old[exclevel][innerindex]) inewhole--;
do {
inewhole++;
} while (inewhole <= OriginIx2[currentdata.type[exclevel] ].size() - 1 && !isgoodnewholepos[inewhole]);
}
if (inewhole >= 0 && inewhole <= OriginIx2[currentdata.type[exclevel] ].size() - 1) { // Found a descendent
descdata.Ix2old[exclevel][innerindex] = OriginIx2[currentdata.type[exclevel] ][inewhole];
desclabelfound[ndesc_found] = Return_State_Label (descdata, OriginIx2);
desctypefound[ndesc_found] = 4;
ndesc_found++;
}
} // if (type_required == 4)
Vect<string> desclabelfoundresized (ndesc_found);
for (int i = 0; i < ndesc_found; ++i) {
desclabelfoundresized[i] = desclabelfound[i];
}
if (cinbreaks) { char a; cin >> a;}
return(desclabelfoundresized);
} // Vect<string> Descendents
// Specialization for LiebLin gas:
Vect<string> Descendents (const LiebLin_Bethe_State& ScanState, const LiebLin_Bethe_State& OriginState, int type_required)
{
Vect<Vect<int> > ScanIx2here(1);
ScanIx2here[0] = ScanState.Ix2;
Vect<Vect<int> > OriginIx2here(1);
OriginIx2here[0] = OriginState.Ix2;
Vect<int> Ix2_min(1);
Ix2_min[0] = LIEBLIN_Ix2_MIN;
Vect<int> Ix2_max(1);
Ix2_max[0] = LIEBLIN_Ix2_MAX;
Vect<string> desc_found;
// If the state is an outer skeleton, we use a slightly modified OriginIx2 (in which the outermost
// rapidities at level zero are put to the outer skeleton position convention) for computing the descendents.
if (Is_Outer_Skeleton(ScanState)) {
// Construct and descend a state with 2 less particles:
if (ScanState.N < 3) ABACUSerror("Skeleton descendent logic at fixed iK not implemented for N < 3.");
LiebLin_Bethe_State ReducedScanState (ScanState.c_int, ScanState.L, ScanState.N - 2);
LiebLin_Bethe_State ReducedOriginState (ScanState.c_int, ScanState.L, ScanState.N - 2);
for (int i = 0; i < ScanState.N - 2; ++i) {
ReducedScanState.Ix2[i] = ScanState.Ix2[i+1];
ReducedOriginState.Ix2[i] = OriginState.Ix2[i+1];
}
ReducedScanState.Set_Label_from_Ix2 (ReducedOriginState.Ix2);
Vect<string> desc_mod = Descendents (ReducedScanState, ReducedOriginState, type_required);
// Now translate results back to ScanState: we return outer skeleton states
LiebLin_Bethe_State LabellingState = ScanState;
for (int idesc = 0; idesc < desc_mod.size(); ++idesc) {
ReducedScanState.Set_to_Label (desc_mod[idesc], ReducedOriginState.Ix2);
// Now set all quantum numbers of LabellingState:
LabellingState.Ix2[0] = LIEBLIN_Ix2_MIN + (ScanState.N % 2) + 1;
for (int i = 0; i < ScanState.N - 2; ++i) LabellingState.Ix2[i+1] = ReducedScanState.Ix2[i];
LabellingState.Ix2[ScanState.N - 1] = LIEBLIN_Ix2_MAX - (ScanState.N % 2) - 1;
LabellingState.Set_Label_from_Ix2 (OriginState.Ix2); // Now reset label on OriginIx2 from the correctly set Ix2
desc_mod[idesc] = LabellingState.label;
}
desc_found = desc_mod;
}
// If not outer skeleton, just return straight descendents
else desc_found = Descendents (ScanState.label, ScanIx2here, OriginIx2here, Ix2_min, Ix2_max, type_required);
return(desc_found);
}
// Specialization for Heisenberg:
Vect<string> Descendents (const Heis_Bethe_State& ScanState, const Heis_Bethe_State& OriginState, int type_required)
{
return(Descendents (ScanState.label, ScanState.Ix2, OriginState.Ix2,
ScanState.base.Ix2_min, ScanState.base.Ix2_max, type_required));
}
} // namespace ABACUS