/********************************************************** This software is part of J.-S. Caux's ABACUS library. Copyright (c) J.-S. Caux. ----------------------------------------------------------- File: src/UTILS/State_Label.cc Purpose: universal implementation of state labels for ABACUS ***********************************************************/ #include "ABACUS.h" using namespace std; using namespace ABACUS; namespace ABACUS { // The label of a state is built as follows: // M0[|type1:M1|type2:M2...]_nexc0[|nexc1|nexc2...]_type0Ix2old@type0Ix2new[:...][|type1Ix2old@type1Ix2new...] // A label is always relative to another label reference state, in practice // the seed state used in the scanning for correlations (or otherwise by default: the ground state). // The first part of the label (before the first _ ) labels the particle content (the "base"). // The second part (between the two _ ) specifies the number of quantum numbers // excited to a position different from the configuration of the label reference state. // The third part gives, for each excitation, the moved quantum number, and // (after the @) the quantum number it has been moved to. // The second part is redundant (it could be read off the third part), but is kept since it is human-readable. // Example: // 300|2:23|5:4_3|2|1_-21@-43:11@-21:299@341|0@-24:4@12|5@35 // labels a state with // 300 particles of type 0, 23 of type 2 and 4 of type 5 // 3 type 0 particles displaced (Ix2 = -21 displaced to Ix2 = -43, 11 to -21 and 299 at 341) // 2 type 2 particles displaced (Ix2 = 0 to -24 and 4 to 12) // 1 type 5 particle displaced (Ix2 = 5 displaced to Ix2 = 35). string Extract_Base_Label (string label) { string::size_type i1 = label.find(LABELSEP); string baselabel = label.substr(0, i1); return(baselabel); } string Extract_nexc_Label (string label) { string::size_type i1 = label.find(LABELSEP); string::size_type i2 = label.rfind(LABELSEP); return(label.substr(i1+1, i2-i1-1)); } // For compressed labels: conversions between integers and char/strings. // This is done according to the following data (in ABACUS_Scan.h): look for ABACUScoding. string Convert_POSINT_to_STR (int int_to_convert) { // Converts a positive integer into a string according to the coding defined by global constant array ABACUScoding. if (int_to_convert < 0) ABACUSerror("Trying to convert a negative integer to a string."); int remainder = int_to_convert; stringstream result_strstrm; do { result_strstrm << ABACUScoding[remainder - ABACUScodingsize * (remainder/ABACUScodingsize)]; remainder /= ABACUScodingsize; } while (remainder > 0); return(result_strstrm.str()); } int Convert_CHAR_to_POSINT (char char_to_convert) { // Converts a char into an int according to the coding defined by global constant array ABACUScoding. for (int i = 0; i < ABACUScodingsize; ++i) if (char_to_convert == ABACUScoding[i]) return(i); cout << "char to convert: " << char_to_convert << endl; ABACUSerror("Failed to convert char to posint: char not in ABACUScoding set."); return(-1); } int Convert_STR_to_POSINT (string str_to_convert) { // Converts a string into a positive integer according to the coding defined by global constant array ABACUScoding. int result = 0; for (unsigned int i = 0; i < str_to_convert.size(); ++i) { result = ABACUScodingsize * result + Convert_CHAR_to_POSINT(str_to_convert[str_to_convert.size() - 1 - i]); } return(result); } // For reading only the base part of a label: State_Label_Data Read_Base_Label (string label) { // Converts a given label into the appropriate State_Label_Data // Split label into base, nexc and q#exc parts: // these are divided by the two LABELSEP characters in the label. string::size_type i1 = label.find(LABELSEP); string::size_type i2 = label.rfind(LABELSEP); string baselabel = label.substr(0, i1); string nexclabel = label.substr(i1+1, i2-i1-1); string Ix2exclabel = label.substr(i2+1); // Read off the base label: count the number of TYPESEP in baselabel int nbar = 0; for (unsigned int i = 0; i < baselabel.length(); ++i) if (baselabel[i] == TYPESEP) nbar++; // There are now nbar + 1 base label data: int ntypes = nbar + 1; Vect type(ntypes); // integer type labels of the types present type[0] = 0; // always the case by convention Vect M(ntypes); // how many particles of each type if (ntypes == 1) { // Only one type to read off istringstream M0buffer(baselabel); M0buffer >> M[0]; } else { // ntypes > 1 // Read off M[0]: string::size_type i1 = baselabel.find(TYPESEP); // M0 is always present, without type specifier string M0 = baselabel.substr(0, i1); istringstream M0buffer(M0); M0buffer >> M[0]; // Read off M[1 ... ntypes - 2] string baselabelremaining = baselabel; for (int itype = 1; itype < ntypes - 1; ++itype) { // Remove everything up to leftmost TYPESEP in baselabelremaining string::size_type i1 = baselabelremaining.find(TYPESEP); // M0 is always present, without type specifier baselabelremaining = baselabelremaining.substr(i1+1); string::size_type i2 = baselabelremaining.find(EXCSEP); string::size_type i3 = baselabelremaining.find(TYPESEP); string typeread = baselabelremaining.substr(0, i2); string Mread = baselabelremaining.substr(i2+1,i3-i2-1); istringstream typereadbuffer (typeread); typereadbuffer >> type[itype]; istringstream Mreadbuffer (Mread); Mreadbuffer >> M[itype]; } // Read off M[ntypes - 1] { string::size_type i1 = baselabelremaining.find(TYPESEP); // M0 is always present, without type specifier baselabelremaining = baselabelremaining.substr(i1+1); string::size_type i2 = baselabelremaining.find(EXCSEP); string typeread = baselabelremaining.substr(0, i2); string Mread = baselabelremaining.substr(i2+1); istringstream typereadbuffer (typeread); typereadbuffer >> type[ntypes - 1]; istringstream Mreadbuffer (Mread); Mreadbuffer >> M[ntypes - 1]; } } // else if ntypes > 1 // baselabel is now completely read // Define some dud nex, Ix2old, Ix2exc: Vect nexc(ntypes); // how many excitations as compared to the OriginState Vect > Ix2old(ntypes); // which Ix2 will be excited Vect > Ix2exc(ntypes); // which Ix2 the excitation has shifted to State_Label_Data labeldata (type, M, nexc, Ix2old, Ix2exc); return(labeldata); } State_Label_Data Read_State_Label (string label, const Vect >& OriginIx2) { // Converts a given label into the appropriate State_Label_Data // Split label into base, nexc and q#exc parts: // these are divided by the two LABELSEP characters in the label. string::size_type i1 = label.find(LABELSEP); string::size_type i2 = label.rfind(LABELSEP); string baselabel = label.substr(0, i1); string nexclabel = label.substr(i1+1, i2-i1-1); string Ix2exclabel = label.substr(i2+1); // Read off the base label: count the number of TYPESEP in baselabel int nbar = 0; for (unsigned int i = 0; i < baselabel.length(); ++i) if (baselabel[i] == TYPESEP) nbar++; // There are now nbar + 1 base label data: int ntypes = nbar + 1; Vect type(ntypes); // integer type labels of the types present type[0] = 0; // always the case by convention Vect M(ntypes); // how many particles of each type if (ntypes == 1) { // Only one type to read off istringstream M0buffer(baselabel); M0buffer >> M[0]; } else { // ntypes > 1 // Read off M[0]: string::size_type i1 = baselabel.find(TYPESEP); // M0 is always present, without type specifier string M0 = baselabel.substr(0, i1); istringstream M0buffer(M0); M0buffer >> M[0]; // Read off M[1 ... ntypes - 2] string baselabelremaining = baselabel; for (int itype = 1; itype < ntypes - 1; ++itype) { // Remove everything up to leftmost TYPESEP in baselabelremaining string::size_type i1 = baselabelremaining.find(TYPESEP); // M0 is always present, without type specifier baselabelremaining = baselabelremaining.substr(i1+1); string::size_type i2 = baselabelremaining.find(EXCSEP); string::size_type i3 = baselabelremaining.find(TYPESEP); string typeread = baselabelremaining.substr(0, i2); string Mread = baselabelremaining.substr(i2+1,i3-i2-1); istringstream typereadbuffer (typeread); typereadbuffer >> type[itype]; istringstream Mreadbuffer (Mread); Mreadbuffer >> M[itype]; } // Read off M[ntypes - 1] { string::size_type i1 = baselabelremaining.find(TYPESEP); // M0 is always present, without type specifier baselabelremaining = baselabelremaining.substr(i1+1); string::size_type i2 = baselabelremaining.find(EXCSEP); string typeread = baselabelremaining.substr(0, i2); string Mread = baselabelremaining.substr(i2+1); istringstream typereadbuffer (typeread); typereadbuffer >> type[ntypes - 1]; istringstream Mreadbuffer (Mread); Mreadbuffer >> M[ntypes - 1]; } } // else if ntypes > 1 // baselabel is now completely read // Read off the nexc vector: Vect nexc(ntypes); // how many excitations as compared to the OriginState if (ntypes == 1) { // Only one type to read off istringstream exc0buffer(nexclabel); exc0buffer >> nexc[0]; } else { // ntypes > 1 // Read off nexc[0]: string::size_type i1 = nexclabel.find(TYPESEP); string nexc0 = nexclabel.substr(0, i1); istringstream nexc0buffer(nexc0); nexc0buffer >> nexc[0]; // Read off nexc[1 ... ntypes - 2] string nexclabelremaining = nexclabel; for (int itype = 1; itype < ntypes - 1; ++itype) { // Remove everything up to leftmost TYPESEP in nexclabelremaining string::size_type i1 = nexclabelremaining.find(TYPESEP); nexclabelremaining = nexclabelremaining.substr(i1+1); string::size_type i2 = nexclabelremaining.find(TYPESEP); string nexcread = nexclabelremaining.substr(0, i2); istringstream nexcreadbuffer (nexcread); nexcreadbuffer >> nexc[itype]; } // Read off nexc[ntypes - 1] { string::size_type i1 = nexclabelremaining.find(TYPESEP); nexclabelremaining = nexclabelremaining.substr(i1+1); istringstream nexcreadbuffer (nexclabelremaining); nexcreadbuffer >> nexc[ntypes - 1]; } } // else if ntypes > 1 // nexc is now completely read // Now read off the (compressed) jexc and Ix2exc vectors of vectors: Vect > Ix2old(ntypes); // which Ix2 will be excited Vect > Ix2exc(ntypes); // which Ix2 the excitation has shifted to for (int itype = 0; itype < ntypes; ++itype) { Ix2old[itype] = Vect (ABACUS::max(nexc[itype],1)); Ix2exc[itype] = Vect (ABACUS::max(nexc[itype],1)); } string Ix2exclabelremaining = Ix2exclabel; for (int itype = 0; itype < ntypes - 1; ++itype) { // Read off the Ix2old, Ix2exc: if (nexc[itype] == 0) { // careful here, need to remove a TYPESEP string::size_type i2 = Ix2exclabelremaining.find(TYPESEP); Ix2exclabelremaining = Ix2exclabelremaining.substr(i2+1); } for (int iexc = 0; iexc < nexc[itype]; ++iexc) { //string::size_type i1 = Ix2exclabelremaining.find(INEXCSEP); string::size_type i2 = (iexc < nexc[itype] - 1 ? Ix2exclabelremaining.find(EXCSEP) : Ix2exclabelremaining.find(TYPESEP)); // careful here! string Ix2excIDread = Ix2exclabelremaining.substr(0,i2); int Ix2excID = Convert_STR_to_POSINT(Ix2excIDread); Ix2old[itype][iexc] = OriginIx2[type[itype] ][Ix2excID - M[itype] * (Ix2excID/M[itype])]; // index is remainder w/r to nr of strings of this type // Convention: if remainder is even, moving left. If odd, moving right. // 0 means move one unit left, 1 means move one unit right, etc. Ix2exc[itype][iexc] = Ix2old[itype][iexc] + (Ix2excID/M[itype] % 2 ? 2 : -2) * (Ix2excID/(2 * M[itype]) + 1); // ABACUS++T_8 onwards // Remove everything up to index i2 in Ix2exclabelremaining Ix2exclabelremaining = Ix2exclabelremaining.substr(i2+1); } } // Now read off the Ix2old, Ix2exc of the last type: this is always done for (int iexc = 0; iexc < nexc[ntypes - 1] - 1; ++iexc) { string::size_type i2 = Ix2exclabelremaining.find(EXCSEP); string Ix2excIDread = Ix2exclabelremaining.substr(0,i2); int Ix2excID = Convert_STR_to_POSINT(Ix2excIDread); Ix2old[ntypes - 1][iexc] = OriginIx2[type[ntypes - 1] ][Ix2excID - M[ntypes - 1] * (Ix2excID/M[ntypes - 1])]; // index is remainder w/r to nr of strings of this type // Convention: if remainder is even, moving left. If odd, moving right. Ix2exc[ntypes - 1][iexc] = Ix2old[ntypes - 1][iexc] + (Ix2excID/M[ntypes - 1] % 2 ? 2 : -2) * (Ix2excID/(2 * M[ntypes - 1]) + 1); // ABACUS++T_8 onwards // Remove everything up to index i2 in Ix2exclabelremaining Ix2exclabelremaining = Ix2exclabelremaining.substr(i2+1); } // Now read off the last pair: int Ix2excID = Convert_STR_to_POSINT(Ix2exclabelremaining); Ix2old[ntypes - 1][ABACUS::max(nexc[ntypes - 1] - 1,0)] = OriginIx2[type[ntypes - 1] ][Ix2excID - M[ntypes - 1] * (Ix2excID/M[ntypes - 1])]; // index is remainder w/r to nr of strings of this type // Convention: if remainder is even, moving left. If odd, moving right. Ix2exc[ntypes - 1][ABACUS::max(nexc[ntypes - 1] - 1,0)] = Ix2old[ntypes - 1][nexc[ntypes - 1] - 1] + (Ix2excID/M[ntypes - 1] % 2 ? 2 : -2) * (Ix2excID/(2 * M[ntypes - 1]) + 1); // ABACUS++T_8 onwards State_Label_Data labeldata (type, M, nexc, Ix2old, Ix2exc); return(labeldata); } State_Label_Data Read_State_Label (string label, const Vect& OriginIx2) { Vect > OriginIx2here(1); OriginIx2here[0] = OriginIx2; return(Read_State_Label (label, OriginIx2here)); } string Return_State_Label (State_Label_Data data, const Vect >& OriginIx2) { // This function produces a compressed label. string label; // Write the base: // First, particles of type 0: stringstream M0out; M0out << data.M[0]; label += M0out.str(); for (int itype = 1; itype < data.M.size(); ++itype) { if (data.M[itype] > 0) { label += TYPESEP; stringstream typeout; typeout << data.type[itype]; label += typeout.str(); label += EXCSEP; stringstream Mout; Mout << data.M[itype]; label += Mout.str(); } } label += LABELSEP; // Now the nexc: stringstream nexc0out; nexc0out << data.nexc[0]; label += nexc0out.str(); for (int iexc = 1; iexc < data.nexc.size(); ++iexc) { label += TYPESEP; stringstream nexcout; nexcout << data.nexc[iexc]; label += nexcout.str(); } label += LABELSEP; // Now the displacements: // The conventions are as follows. // For each excitation, an integer number ID is given according to the following rules: // ID % data.M[itype] gives the index of the hole position in OriginIx2. // We now define remainder1 == ID - (ID % data.M[itype]). // remainder1 is interpreted as: remainder1 even/odd means displacement to left/right // remainder1/2 + 1 gives then the displacement in units of quantum nr. // The +1 is to start labeling displacement from 0 (so 0 means displace by one unit). for (int itype = 0; itype < data.M.size(); ++itype) { if (itype > 0) label += TYPESEP; for (int iexc = 0; iexc < data.nexc[itype]; ++iexc) { if (iexc > 0) label += EXCSEP; int excID = abs(data.Ix2exc[itype][iexc] - data.Ix2old[itype][iexc]) - 2; // necessarily even and >= 0 if (data.Ix2exc[itype][iexc] > data.Ix2old[itype][iexc]) excID += 1; // make odd if displacement is to the right int holeindex = -1; do { holeindex++; } while (OriginIx2[data.type[itype] ][holeindex] != data.Ix2old[itype][iexc] && holeindex < OriginIx2[data.type[itype] ].size() - 1); if (holeindex == OriginIx2[data.type[itype] ].size()) ABACUSerror("Going out of bounds in Compress_Label."); excID = excID * data.M[itype] + holeindex; label += Convert_POSINT_to_STR(excID); } // for iexc } // for itype return(label); } string Return_State_Label (State_Label_Data data, const Vect& OriginIx2) { Vect > OriginIx2here(1); OriginIx2here[0] = OriginIx2; return(Return_State_Label (data, OriginIx2here)); } string Return_State_Label (const Vect >& ScanIx2, const Vect >& OriginIx2) { // This function does not assume any ordering of the Ix2. if (ScanIx2.size() != OriginIx2.size()) ABACUSerror("ScanIx2.size() != OriginIx2.size() in Find_Label."); for (int i = 0; i < ScanIx2.size(); ++i) if (ScanIx2[i].size() != OriginIx2[i].size()) ABACUSerror("ScanIx2[i].size() != OriginIx2[i].size() in Find_Label."); // Set the state ulabel: // Count the number of types present: int ntypespresent = 0; for (int is = 0; is < ScanIx2.size(); ++is) if (is == 0 || ScanIx2[is].size() > 0) ntypespresent++; // type 0 is by default always present Vect type_ref(ntypespresent); Vect M_ref(ntypespresent); Vect nexc_ref(0, ntypespresent); // Define type_ref and M_ref: int ntypespresentcheck = 0; for (int is = 0; is < ScanIx2.size(); ++is) if (is == 0 || ScanIx2[is].size() > 0) { // type 0 is by default always present type_ref[ntypespresentcheck] = is; M_ref[ntypespresentcheck++] = ScanIx2[is].size(); } if (ntypespresentcheck != ntypespresent) ABACUSerror("Counting types present wrong in Return_Label."); // Count nr of particle-holes: for (int it = 0; it < ntypespresent; ++it) for (int i = 0; i < M_ref[it]; ++i) if (!OriginIx2[type_ref[it] ].includes(ScanIx2[type_ref[it] ][i])) nexc_ref[it] += 1; Vect > Ix2old_ref(ntypespresent); Vect > Ix2exc_ref(ntypespresent); for (int it = 0; it < ntypespresent; ++it) Ix2old_ref[it] = Vect(ABACUS::max(nexc_ref[it],1)); for (int it = 0; it < ntypespresent; ++it) Ix2exc_ref[it] = Vect(ABACUS::max(nexc_ref[it],1)); for (int it = 0; it < ntypespresent; ++it) { int nexccheck = 0; for (int i = 0; i < M_ref[it]; ++i) if (!OriginIx2[type_ref[it] ].includes(ScanIx2[type_ref[it] ][i])) Ix2exc_ref[it][nexccheck++] = ScanIx2[type_ref[it] ][i]; if (nexccheck != nexc_ref[it]) ABACUSerror("Counting excitations wrong (1) in Return_State_Label"); nexccheck = 0; for (int i = 0; i < M_ref[it]; ++i) if (!ScanIx2[type_ref[it] ].includes(OriginIx2[type_ref[it] ][i])) Ix2old_ref[it][nexccheck++] = OriginIx2[type_ref[it] ][i]; if (nexccheck != nexc_ref[it]) { cout << OriginIx2 << endl; cout << ScanIx2 << endl; cout << nexc_ref[it] << endl; cout << Ix2exc_ref[it] << endl; ABACUSerror("Counting excitations wrong (2) in Return_State_Label"); } // Now order the Ix2old_ref and Ix2exc_ref: Ix2old_ref[it].QuickSort(); Ix2exc_ref[it].QuickSort(); } // for it State_Label_Data labeldata(type_ref, M_ref, nexc_ref, Ix2old_ref, Ix2exc_ref); return(Return_State_Label (labeldata, OriginIx2)); } string Return_State_Label (const Vect& ScanIx2, const Vect& OriginIx2) { Vect > ScanIx2here(1); ScanIx2here[0] = ScanIx2; Vect > OriginIx2here(1); OriginIx2here[0] = OriginIx2; return(Return_State_Label (ScanIx2here, OriginIx2here)); } Vect > Return_Ix2_from_Label (string label_ref, const Vect >& OriginIx2) { // ASSUMPTIONS: // OriginIx2 is ordered. Vect > Ix2 = OriginIx2; // this will fail if the sizes are incompatible State_Label_Data labeldata = Read_State_Label (label_ref, OriginIx2); // Now set the excitations: for (int it = 0; it < labeldata.type.size(); ++it) for (int iexc = 0; iexc < labeldata.nexc[it]; ++iexc) for (int i = 0; i < labeldata.M[it]; ++i) if (Ix2[labeldata.type[it] ][i] == labeldata.Ix2old[it][iexc]) { Ix2[labeldata.type[it] ][i] = labeldata.Ix2exc[it][iexc]; } // Now reorder the Ix2 to follow convention: for (int il = 0; il < Ix2.size(); ++il) Ix2[il].QuickSort(); return(Ix2); } Vect Return_Ix2_from_Label (string label_ref, const Vect& OriginIx2) { Vect > OriginIx2here(1); OriginIx2here[0] = OriginIx2; return(Return_Ix2_from_Label(label_ref, OriginIx2here)[0]); } } // namespace ABACUS