/********************************************************** This software is part of J.-S. Caux's ABACUS library. Copyright (c) J.-S. Caux. ----------------------------------------------------------- File: src/ODSLF/ODSLF_XXZ_Bethe_State.cc Purpose: defines Bethe states for 1d spinless fermions. ***********************************************************/ #include "ABACUS.h" using namespace std; namespace ABACUS { // Function prototypes inline DP ODSLF_fbar_XXZ (DP lambda, int par, DP tannzetaover2); DP ODSLF_Theta_XXZ (DP lambda, int nj, int nk, int parj, int park, DP* tannzetaover2); DP ODSLF_hbar_XXZ (DP lambda, int n, int par, DP* si_n_anis_over_2); DP ODSLF_ddlambda_Theta_XXZ (DP lambda, int nj, int nk, int parj, int park, DP* si_n_anis_over_2); //*************************************************************************************************** // Function definitions: class ODSLF_XXZ_Bethe_State ODSLF_XXZ_Bethe_State::ODSLF_XXZ_Bethe_State () : ODSLF_Bethe_State(), sinhlambda(ODSLF_Lambda(chain, 1)), coshlambda(ODSLF_Lambda(chain, 1)), tanhlambda(ODSLF_Lambda(chain, 1)) {}; ODSLF_XXZ_Bethe_State::ODSLF_XXZ_Bethe_State (const ODSLF_XXZ_Bethe_State& RefState) // copy constructor : ODSLF_Bethe_State(RefState), sinhlambda(ODSLF_Lambda(RefState.chain, RefState.base)), coshlambda(ODSLF_Lambda(RefState.chain, RefState.base)), tanhlambda(ODSLF_Lambda(RefState.chain, RefState.base)) { // copy arrays into new ones //cout << "Calling XXZ state copy constructor." << endl; for (int j = 0; j < RefState.chain.Nstrings; ++j) { for (int alpha = 0; alpha < RefState.base[j]; ++j) { sinhlambda[j][alpha] = RefState.sinhlambda[j][alpha]; coshlambda[j][alpha] = RefState.coshlambda[j][alpha]; tanhlambda[j][alpha] = RefState.tanhlambda[j][alpha]; } } //cout << "Done calling XXZ state copy constructor." << endl; } ODSLF_XXZ_Bethe_State::ODSLF_XXZ_Bethe_State (const Heis_Chain& RefChain, int M) : ODSLF_Bethe_State(RefChain, M), sinhlambda(ODSLF_Lambda(RefChain, M)), coshlambda(ODSLF_Lambda(RefChain, M)), tanhlambda(ODSLF_Lambda(RefChain, M)) { //cout << "Here in XXZ BS constructor." << endl; //cout << (*this).lambda[0][0] << endl; //cout << "OK" << endl; if ((RefChain.Delta <= -1.0) || (RefChain.Delta >= 1.0)) ABACUSerror("Delta out of range in ODSLF_XXZ_Bethe_State constructor"); } ODSLF_XXZ_Bethe_State::ODSLF_XXZ_Bethe_State (const Heis_Chain& RefChain, const ODSLF_Base& RefBase) : ODSLF_Bethe_State(RefChain, RefBase), sinhlambda(ODSLF_Lambda(RefChain, RefBase)), coshlambda(ODSLF_Lambda(RefChain, RefBase)), tanhlambda(ODSLF_Lambda(RefChain, RefBase)) { if ((RefChain.Delta <= -1.0) || (RefChain.Delta >= 1.0)) ABACUSerror("Delta out of range in ODSLF_XXZ_Bethe_State constructor"); } ODSLF_XXZ_Bethe_State::ODSLF_XXZ_Bethe_State (const Heis_Chain& RefChain, long long int base_id_ref, long long int type_id_ref) : ODSLF_Bethe_State(RefChain, base_id_ref, type_id_ref), sinhlambda(ODSLF_Lambda(chain, base)), coshlambda(ODSLF_Lambda(chain, base)), tanhlambda(ODSLF_Lambda(chain, base)) { if ((RefChain.Delta <= -1.0) || (RefChain.Delta >= 1.0)) ABACUSerror("Delta out of range in ODSLF_XXZ_Bethe_State constructor"); } ODSLF_XXZ_Bethe_State& ODSLF_XXZ_Bethe_State::operator= (const ODSLF_XXZ_Bethe_State& RefState) { if (this != &RefState) { chain = RefState.chain; base = RefState.base; offsets = RefState.offsets; Ix2 = RefState.Ix2; lambda = RefState.lambda; BE = RefState.BE; diffsq = RefState.diffsq; conv = RefState.conv; iter = RefState.iter; iter_Newton = RefState.iter_Newton; E = RefState.E; iK = RefState.iK; K = RefState.K; lnnorm = RefState.lnnorm; base_id = RefState.base_id; type_id = RefState.type_id; id = RefState.id; maxid = RefState.maxid; nparticles = RefState.nparticles; sinhlambda = RefState.sinhlambda; coshlambda = RefState.coshlambda; tanhlambda = RefState.tanhlambda; } return(*this); } // Member functions void ODSLF_XXZ_Bethe_State::Set_Free_lambdas() { // Sets all the rapidities to the solutions of the BAEs without scattering terms for (int i = 0; i < chain.Nstrings; ++i) { for (int alpha = 0; alpha < base[i]; ++alpha) { if(chain.par[i] == 1) lambda[i][alpha] = (tan(chain.Str_L[i] * 0.5 * chain.anis) * tan(PI * 0.5 * Ix2[i][alpha]/chain.Nsites)); else if (chain.par[i] == -1) lambda[i][alpha] = (-tan((PI * 0.5 * Ix2[i][alpha])/chain.Nsites)/tan(chain.Str_L[i] * 0.5 * chain.anis)); else ABACUSerror("Invalid parities in Set_Free_lambdas."); } } return; } void ODSLF_XXZ_Bethe_State::Compute_sinhlambda() { for (int j = 0; j < chain.Nstrings; ++j) { for (int alpha = 0; alpha < base[j]; ++alpha) sinhlambda[j][alpha] = sinh(lambda[j][alpha]); } return; } void ODSLF_XXZ_Bethe_State::Compute_coshlambda() { for (int j = 0; j < chain.Nstrings; ++j) { for (int alpha = 0; alpha < base[j]; ++alpha) coshlambda[j][alpha] = cosh(lambda[j][alpha]); } return; } void ODSLF_XXZ_Bethe_State::Compute_tanhlambda() { for (int j = 0; j < chain.Nstrings; ++j) { for (int alpha = 0; alpha < base[j]; ++alpha) tanhlambda[j][alpha] = tanh(lambda[j][alpha]); } return; } bool ODSLF_XXZ_Bethe_State::Check_Admissibility(char option) { // This function checks the admissibility of the Ix2's of a state: // returns false if there are higher strings with Ix2 = 0, a totally symmetric distribution of I's at each level, // and strings of equal length modulo 2 and parity with Ix2 = 0, meaning at least two equal roots in BAE. bool answer = true; Vect Zero_at_level(false, chain.Nstrings); // whether there exists an Ix2 == 0 at a given level bool higher_string_on_zero = false; for (int j = 0; j < chain.Nstrings; ++j) { // The following line puts answer to true if there is at least one higher string with zero Ix2 for (int alpha = 0; alpha < base[j]; ++alpha) if ((Ix2[j][alpha] == 0) && (chain.Str_L[j] >= 2)) higher_string_on_zero = true; for (int alpha = 0; alpha < base[j]; ++alpha) if (Ix2[j][alpha] == 0) Zero_at_level[j] = true; // NOTE: if base[j] == 0, Zero_at_level[j] remains false. } // check symmetry of Ix2 at each level, if there exists a potentially risky Ix2... bool symmetric_state = (*this).Check_Symmetry(); bool string_coincidence = false; for (int j1 = 0; j1 < chain.Nstrings; ++j1) { for (int j2 = j1 + 1; j2 < chain.Nstrings; ++j2) if (Zero_at_level[j1] && Zero_at_level[j2] && (chain.par[j1] == chain.par[j2]) && (!((chain.Str_L[j1] + chain.Str_L[j2])%2))) string_coincidence = true; } bool M_odd_and_onep_on_zero = false; if (option == 'z') { // for Sz, if M is odd, exclude symmetric states with a 1+ on zero // (zero rapidities in left and right states, so FF det not defined). bool is_ground_state = base.Nrap[0] == base.Mdown && Ix2[0][0] == -(base.Mdown - 1) && Ix2[0][base.Mdown-1] == base.Mdown - 1; if (Zero_at_level[0] && (base.Mdown % 2) && !is_ground_state) M_odd_and_onep_on_zero = true; } bool onep_onem_on_zero = false; if (option == 'm' || option == 'p') { // for Smin, we also exclude symmetric states with 1+ and 1- strings on zero if (Zero_at_level[0] && Zero_at_level[1]) onep_onem_on_zero = true; } answer = !(symmetric_state && (higher_string_on_zero || string_coincidence || onep_onem_on_zero || M_odd_and_onep_on_zero)); // Now check that no Ix2 is equal to +N (since we take -N into account, and I + N == I by periodicity of exp) for (int j = 0; j < chain.Nstrings; ++j) for (int alpha = 0; alpha < base[j]; ++alpha) if ((Ix2[j][alpha] < -chain.Nsites) || (Ix2[j][alpha] >= chain.Nsites)) answer = false; if (!answer) { E = 0.0; K = 0.0; conv = 0; iter = 0; iter_Newton = 0; lnnorm = -100.0; } return(answer); // answer == true: nothing wrong with this Ix2_config } void ODSLF_XXZ_Bethe_State::Compute_BE (int j, int alpha) { tanhlambda[j][alpha] = tanh(lambda[j][alpha]); DP sumtheta = 0.0; for (int k = 0; k < chain.Nstrings; ++k) for (int beta = 0; beta < base[k]; ++beta) { if ((chain.Str_L[j] == 1) && (chain.Str_L[k] == 1)) sumtheta += (chain.par[j] == chain.par[k]) ? atan((tanhlambda[j][alpha] - tanhlambda[k][beta]) /((1.0 - tanhlambda[j][alpha] * tanhlambda[k][beta]) * chain.ta_n_anis_over_2[2])) : - atan(((tanhlambda[j][alpha] - tanhlambda[k][beta]) /(1.0 - tanhlambda[j][alpha] * tanhlambda[k][beta])) * chain.ta_n_anis_over_2[2]) ; else sumtheta += 0.5 * ODSLF_Theta_XXZ((tanhlambda[j][alpha] - tanhlambda[k][beta]) /(1.0 - tanhlambda[j][alpha] * tanhlambda[k][beta]), chain.Str_L[j], chain.Str_L[k], chain.par[j], chain.par[k], chain.ta_n_anis_over_2); } sumtheta *= 2.0; BE[j][alpha] = ((chain.par[j] == 1) ? 2.0 * atan(tanhlambda[j][alpha]/chain.ta_n_anis_over_2[chain.Str_L[j]]) : -2.0 * atan(tanhlambda[j][alpha] * chain.ta_n_anis_over_2[chain.Str_L[j]])) - (sumtheta + PI*Ix2[j][alpha])/chain.Nsites; } void ODSLF_XXZ_Bethe_State::Compute_BE () { // Fills in the BE members with the value of the Bethe equations. (*this).Compute_tanhlambda(); DP sumtheta = 0.0; for (int j = 0; j < chain.Nstrings; ++j) for (int alpha = 0; alpha < base[j]; ++alpha) { sumtheta = 0.0; for (int k = 0; k < chain.Nstrings; ++k) for (int beta = 0; beta < base[k]; ++beta) { if ((chain.Str_L[j] == 1) && (chain.Str_L[k] == 1)) sumtheta += (chain.par[j] == chain.par[k]) ? atan((tanhlambda[j][alpha] - tanhlambda[k][beta]) /((1.0 - tanhlambda[j][alpha] * tanhlambda[k][beta]) * chain.ta_n_anis_over_2[2])) : - atan(((tanhlambda[j][alpha] - tanhlambda[k][beta]) /(1.0 - tanhlambda[j][alpha] * tanhlambda[k][beta])) * chain.ta_n_anis_over_2[2]) ; else sumtheta += 0.5 * ODSLF_Theta_XXZ((tanhlambda[j][alpha] - tanhlambda[k][beta]) /(1.0 - tanhlambda[j][alpha] * tanhlambda[k][beta]), chain.Str_L[j], chain.Str_L[k], chain.par[j], chain.par[k], chain.ta_n_anis_over_2); } sumtheta *= 2.0; BE[j][alpha] = ((chain.par[j] == 1) ? 2.0 * atan(tanhlambda[j][alpha]/chain.ta_n_anis_over_2[chain.Str_L[j]]) : -2.0 * atan(tanhlambda[j][alpha] * chain.ta_n_anis_over_2[chain.Str_L[j]])) - (sumtheta + PI*Ix2[j][alpha])/chain.Nsites; } } DP ODSLF_XXZ_Bethe_State::Iterate_BAE (int j, int alpha) { // Returns a new iteration value for lambda[j][alpha] given tanhlambda and BE Lambdas // Assumes that tanhlambda[][] and BE[][] have been computed. DP new_lambda = 0.0; DP arg = 0.0; if (chain.par[j] == 1) arg = chain.ta_n_anis_over_2[chain.Str_L[j]] * tan(0.5 * //(PI * Ix2[j][alpha] + sumtheta)/chain.Nsites (2.0 * atan(tanhlambda[j][alpha]/chain.ta_n_anis_over_2[chain.Str_L[j]]) - BE[j][alpha]) ); else if (chain.par[j] == -1) arg = -tan(0.5 * (-2.0 * atan(tanhlambda[j][alpha] * chain.ta_n_anis_over_2[chain.Str_L[j]]) - BE[j][alpha])) /chain.ta_n_anis_over_2[chain.Str_L[j]]; if (fabs(arg) < 1.0) { new_lambda = atanh(arg); } else { new_lambda = lambda[j][alpha]; // back to drawing board... int block = 0; // counter to prevent runaway while loop DP new_tanhlambda = 0.0; DP sumtheta = 0.0; arg = 10.0; // reset value to start while loop while ((fabs(arg) > 1.0) && (block++ < 100)) { // recompute the diverging root on its own... new_lambda *= 1.01; // try to go slowly towards infinity... new_tanhlambda = tanh(new_lambda); sumtheta = 0.0; for (int k = 0; k < chain.Nstrings; ++k) { for (int beta = 0; beta < base[k]; ++beta) if ((chain.Str_L[j] == 1) && (chain.Str_L[k] == 1)) sumtheta += (chain.par[j] == chain.par[k]) ? atan((new_tanhlambda - tanhlambda[k][beta]) /((1.0 - new_tanhlambda * tanhlambda[k][beta]) * chain.ta_n_anis_over_2[2])) : - atan(((new_tanhlambda - tanhlambda[k][beta]) /(1.0 - new_tanhlambda * tanhlambda[k][beta])) * chain.ta_n_anis_over_2[2]) ; else sumtheta += 0.5 * ODSLF_Theta_XXZ((new_tanhlambda - tanhlambda[k][beta]) /(1.0 - new_tanhlambda * tanhlambda[k][beta]), chain.Str_L[j], chain.Str_L[k], chain.par[j], chain.par[k], chain.ta_n_anis_over_2); } sumtheta *= 2.0; if (chain.par[j] == 1) arg = chain.ta_n_anis_over_2[chain.Str_L[j]] * tan(0.5 * (PI * Ix2[j][alpha] + sumtheta)/chain.Nsites); else if (chain.par[j] == -1) arg = -tan(0.5 * (PI * Ix2[j][alpha] + sumtheta)/chain.Nsites)/chain.ta_n_anis_over_2[chain.Str_L[j]]; else ABACUSerror("Invalid parities in Iterate_BAE."); } } return(new_lambda); } bool ODSLF_XXZ_Bethe_State::Check_Rapidities() { bool nonan = true; for (int j = 0; j < chain.Nstrings; ++j) for (int alpha = 0; alpha < base[j]; ++alpha) nonan *= !is_nan(lambda[j][alpha]); return nonan; } void ODSLF_XXZ_Bethe_State::Compute_Energy () { DP sum = 0.0; for (int j = 0; j < chain.Nstrings; ++j) { for (int alpha = 0; alpha < base[j]; ++alpha) { sum += sin(chain.Str_L[j] * chain.anis) / (chain.par[j] * cosh(2.0 * lambda[j][alpha]) - cos(chain.Str_L[j] * chain.anis)); } } sum *= - chain.J * sin(chain.anis); E = sum; return; } void ODSLF_XXZ_Bethe_State::Build_Reduced_Gaudin_Matrix (SQMat >& Gaudin_Red) { if (Gaudin_Red.size() != base.Nraptot) ABACUSerror("Passing matrix of wrong size in Build_Reduced_Gaudin_Matrix."); int index_jalpha; int index_kbeta; DP sum_hbar_XXZ = 0.0; DP sinzetasq = pow(sin(chain.anis), 2.0); (*this).Compute_sinhlambda(); (*this).Compute_coshlambda(); index_jalpha = 0; for (int j = 0; j < chain.Nstrings; ++j) { for (int alpha = 0; alpha < base[j]; ++alpha) { index_kbeta = 0; for (int k = 0; k < chain.Nstrings; ++k) { for (int beta = 0; beta < base[k]; ++beta) { if ((j == k) && (alpha == beta)) { sum_hbar_XXZ = 0.0; for (int kp = 0; kp < chain.Nstrings; ++kp) { for (int betap = 0; betap < base[kp]; ++betap) { if (!((j == kp) && (alpha == betap))) sum_hbar_XXZ += ODSLF_ddlambda_Theta_XXZ (lambda[j][alpha] - lambda[kp][betap], chain.Str_L[j], chain.Str_L[kp], chain.par[j], chain.par[kp], chain.si_n_anis_over_2); } } Gaudin_Red[index_jalpha][index_kbeta] = complex ( chain.Nsites * ODSLF_hbar_XXZ (lambda[j][alpha], chain.Str_L[j], chain.par[j], chain.si_n_anis_over_2) - sum_hbar_XXZ); } else { if ((chain.Str_L[j] == 1) && (chain.Str_L[k] == 1)) Gaudin_Red[index_jalpha][index_kbeta] = complex ((chain.par[j] * chain.par[k] == 1) ? chain.si_n_anis_over_2[4] /(pow(sinhlambda[j][alpha] * coshlambda[k][beta] - coshlambda[j][alpha] * sinhlambda[k][beta], 2.0) + sinzetasq) : chain.si_n_anis_over_2[4] /(-pow(coshlambda[j][alpha] * coshlambda[k][beta] - sinhlambda[j][alpha] * sinhlambda[k][beta], 2.0) + sinzetasq) ); else Gaudin_Red[index_jalpha][index_kbeta] = complex (ODSLF_ddlambda_Theta_XXZ (lambda[j][alpha] - lambda[k][beta], chain.Str_L[j], chain.Str_L[k], chain.par[j], chain.par[k], chain.si_n_anis_over_2)); } index_kbeta++; } } index_jalpha++; } } return; } // **************************************************************************************************** // non-member functions inline DP ODSLF_fbar_XXZ (DP tanhlambda, int par, DP tannzetaover2) { DP result = 0.0; if (par == 1) result = 2.0 * atan(tanhlambda/tannzetaover2); else if (par == -1) result = -2.0 * atan(tanhlambda * tannzetaover2); else ABACUSerror("Faulty parity in ODSLF_fbar_XXZ."); return (result); } DP ODSLF_Theta_XXZ (DP tanhlambda, int nj, int nk, int parj, int park, DP* tannzetaover2) { DP result = 0.0; if ((nj == 1) && (nk == 1)) result = ODSLF_fbar_XXZ(tanhlambda, parj*park, tannzetaover2[2]); else { result = (nj == nk) ? 0.0 : ODSLF_fbar_XXZ(tanhlambda, parj*park, tannzetaover2[fabs(nj - nk)]); for (int a = 1; a < ABACUS::min(nj, nk); ++a) result += 2.0 * ODSLF_fbar_XXZ(tanhlambda, parj*park, tannzetaover2[fabs(nj - nk) + 2*a]); result += ODSLF_fbar_XXZ(tanhlambda, parj*park, tannzetaover2[nj + nk]); } return (result); } DP ODSLF_hbar_XXZ (DP lambda, int n, int par, DP* si_n_anis_over_2) { DP result = 0.0; if (par == 1) result = si_n_anis_over_2[2*n]/(pow(sinh(lambda), 2.0) + pow(si_n_anis_over_2[n], 2.0)); else if (par == -1) result = si_n_anis_over_2[2*n]/(-pow(cosh(lambda), 2.0) + pow(si_n_anis_over_2[n], 2.0)); else ABACUSerror("Faulty parity in ODSLF_hbar_XXZ."); return (result); } DP ODSLF_ddlambda_Theta_XXZ (DP lambda, int nj, int nk, int parj, int park, DP* si_n_anis_over_2) { DP result = (nj == nk) ? 0.0 : ODSLF_hbar_XXZ(lambda, fabs(nj - nk), parj*park, si_n_anis_over_2); for (int a = 1; a < ABACUS::min(nj, nk); ++a) result += 2.0 * ODSLF_hbar_XXZ(lambda, fabs(nj - nk) + 2*a, parj*park, si_n_anis_over_2); result += ODSLF_hbar_XXZ(lambda, nj + nk, parj*park, si_n_anis_over_2); return (result); } } // namespace ABACUS