/********************************************************** This software is part of J.-S. Caux's ABACUS library. Copyright (c) ----------------------------------------------------------- File: src/HEIS/XXZ_Bethe_State.cc Purpose: Defines all functions for XXZ_Bethe_State ******************************************************************/ #include "ABACUS.h" using namespace std; namespace ABACUS { // Function prototypes inline DP fbar_XXZ (DP lambda, int par, DP tannzetaover2); DP Theta_XXZ (DP lambda, int nj, int nk, int parj, int park, DP* tannzetaover2); DP hbar_XXZ (DP lambda, int n, int par, DP* si_n_anis_over_2); DP ddlambda_Theta_XXZ (DP lambda, int nj, int nk, int parj, int park, DP* si_n_anis_over_2); //*************************************************************************************************** // Function definitions: class XXZ_Bethe_State XXZ_Bethe_State::XXZ_Bethe_State () : Heis_Bethe_State(), sinhlambda(Lambda(chain, 1)), coshlambda(Lambda(chain, 1)), tanhlambda(Lambda(chain, 1)) {}; XXZ_Bethe_State::XXZ_Bethe_State (const XXZ_Bethe_State& RefState) // copy constructor : Heis_Bethe_State(RefState), sinhlambda(Lambda(RefState.chain, RefState.base)), coshlambda(Lambda(RefState.chain, RefState.base)), tanhlambda(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; } XXZ_Bethe_State::XXZ_Bethe_State (const Heis_Chain& RefChain, int M) : Heis_Bethe_State(RefChain, M), sinhlambda(Lambda(RefChain, M)), coshlambda(Lambda(RefChain, M)), tanhlambda(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 XXZ_Bethe_State constructor"); } XXZ_Bethe_State::XXZ_Bethe_State (const Heis_Chain& RefChain, const Heis_Base& RefBase) : Heis_Bethe_State(RefChain, RefBase), sinhlambda(Lambda(RefChain, RefBase)), coshlambda(Lambda(RefChain, RefBase)), tanhlambda(Lambda(RefChain, RefBase)) { if ((RefChain.Delta <= -1.0) || (RefChain.Delta >= 1.0)) ABACUSerror("Delta out of range in XXZ_Bethe_State constructor"); } /* XXZ_Bethe_State::XXZ_Bethe_State (const Heis_Chain& RefChain, long long int base_id_ref, long long int type_id_ref) : Heis_Bethe_State(RefChain, base_id_ref, type_id_ref), sinhlambda(Lambda(chain, base)), coshlambda(Lambda(chain, base)), tanhlambda(Lambda(chain, base)) { if ((RefChain.Delta <= -1.0) || (RefChain.Delta >= 1.0)) ABACUSerror("Delta out of range in XXZ_Bethe_State constructor"); } */ XXZ_Bethe_State& XXZ_Bethe_State::operator= (const 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; label = RefState.label; sinhlambda = RefState.sinhlambda; coshlambda = RefState.coshlambda; tanhlambda = RefState.tanhlambda; } return(*this); } // Member functions void XXZ_Bethe_State::Set_Free_lambdas() { // Sets all the rapidities to the solutions of the BAEs without scattering terms DP x = 0.0; for (int i = 0; i < chain.Nstrings; ++i) { for (int alpha = 0; alpha < base[i]; ++alpha) { if (chain.par[i] == 1) { //lambda[i][alpha] = atanh(tan(chain.Str_L[i] * 0.5 * chain.anis) * tan(PI * 0.5 * Ix2[i][alpha]/chain.Nsites)); x = tan(chain.Str_L[i] * 0.5 * chain.anis) * tan(PI * 0.5 * Ix2[i][alpha]/chain.Nsites); lambda[i][alpha] = atanh(x/sqrt(1.0 + x*x)); // lambda then always initiated real } else if (chain.par[i] == -1) { //lambda[i][alpha] = atanh(-tan(PI * 0.5 * Ix2[i][alpha]/chain.Nsites)/tan(chain.Str_L[i] * 0.5 * chain.anis)); x = -tan(PI * 0.5 * Ix2[i][alpha]/chain.Nsites)/tan(chain.Str_L[i] * 0.5 * chain.anis); lambda[i][alpha] = atanh(x/sqrt(1.0 + x*x)); // lambda then always initiated real } else ABACUSerror("Invalid parities in Set_Free_lambdas."); //cout << tan(chain.Str_L[i] * 0.5 * chain.anis) << endl; //cout << "Set_Free_lambdas: " << i << "\t" << alpha << "\t" << lambda[i][alpha] << "\t" << tan(chain.Str_L[i] * 0.5 * chain.anis) * tan(PI * 0.5 * Ix2[i][alpha]/chain.Nsites) << endl; } } return; } void 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 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 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 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) /*&& !(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 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 * 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 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 * 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; //if (is_nan(BE[j][alpha])) cout << "BE nan: " << j << "\t" << alpha << "\t" << lambda[j][alpha] << "\t" << tanhlambda[j][alpha] << endl; } } DP 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 * //(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])) /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 * 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."); } if (fabs(arg) < 1.0) { new_lambda = atanh(arg); } //else cout << "Rapidity blows up !\t" << lambda[j][alpha] << "\t" << new_lambda << endl; } // else return(new_lambda); } bool 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; } DP XXZ_Bethe_State::String_delta () { // Computes the sum of absolute value of \delta^{a, a+1} in string hypothesis, for a given bethe eigenstate DP delta = 0.0; int occupied_strings = 0; for (int i = 0; i < (*this).chain.Nstrings; ++i) if ((*this).chain.Str_L[i] > 1) occupied_strings += (*this).base.Nrap[i]; //if ((*this).conv == 0) delta = 1.0; if (occupied_strings == 0) delta = 0.0; else { Vect_DP ln_deltadiff(0.0, 1000); // contains ln |delta^{a, a+1}| Vect_DP deltadiff(0.0, 1000); // contains |delta^{a, a+1}| complex log_BAE_reg = 0.0; for (int j = 0; j < (*this).chain.Nstrings; ++j) { for (int alpha = 0; alpha < (*this).base[j]; ++alpha) { ln_deltadiff = 0.0; for (int a = 1; a <= (*this).chain.Str_L[j]; ++a) { if ((*this).chain.Str_L[j] > 1) { // else the BAE are already 1 log_BAE_reg = DP((*this).chain.Nsites) * log(sinh((*this).lambda[j][alpha] + 0.5 * II * (*this).chain.anis * ((*this).chain.Str_L[j] + 1.0 - 2.0 * a + 1.0) + 0.25 * II * PI * (1.0 - (*this).chain.par[j])) /sinh((*this).lambda[j][alpha] + 0.5 * II * (*this).chain.anis * ((*this).chain.Str_L[j] + 1.0 - 2.0 * a - 1.0) + 0.25 * II * PI * (1.0 - (*this).chain.par[j]))); for (int k = 0; k < (*this).chain.Nstrings; ++k) for (int beta = 0; beta < (*this).base[k]; ++beta) for (int b = 1; b <= (*this).chain.Str_L[k]; ++b) { if ((j != k) || (alpha != beta) || (a != b - 1)) log_BAE_reg += log(sinh(((*this).lambda[j][alpha] + 0.5 * II * (*this).chain.anis * ((*this).chain.Str_L[j] + 1.0 - 2.0 * a ) + 0.25 * II * PI * (1.0 - (*this).chain.par[j])) - ((*this).lambda[k][beta] + 0.5 * II * (*this).chain.anis * ((*this).chain.Str_L[k] + 1.0 - 2.0 * b ) + 0.25 * II * PI * (1.0 - (*this).chain.par[k])) - II * (*this).chain.anis)); if ((j != k) || (alpha != beta) || (a != b + 1)) log_BAE_reg -= log(sinh(((*this).lambda[j][alpha] + 0.5 * II * (*this).chain.anis * ((*this).chain.Str_L[j] + 1.0 - 2.0 * a ) + 0.25 * II * PI * (1.0 - (*this).chain.par[j])) - ((*this).lambda[k][beta] + 0.5 * II * (*this).chain.anis * ((*this).chain.Str_L[k] + 1.0 - 2.0 * b ) + 0.25 * II * PI * (1.0 - (*this).chain.par[k])) + II * (*this).chain.anis)); } // The regular LHS of BAE is now defined. Now sum up the deltas... if (a == 1) ln_deltadiff[0] = - real(log_BAE_reg); else if (a < (*this).chain.Str_L[j]) ln_deltadiff[a - 1] = ln_deltadiff[a-2] - real(log_BAE_reg); else if (a == (*this).chain.Str_L[j]) ln_deltadiff[a-1] = real(log_BAE_reg); } // if ((*this).chain.Str_L[j] > 1) } // for (int a = 1; ... for (int a = 0; a < (*this).chain.Str_L[j]; ++a) { deltadiff[a] = ln_deltadiff[a] != 0.0 ? exp(ln_deltadiff[a]) : 0.0; delta += fabs(deltadiff[a]); } } // alpha sum } // j sum if (is_nan(delta)) delta = 1.0; // sentinel } // else return delta; } void 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 XXZ_Bethe_State::Compute_Momentum () { int sum_Ix2 = 0; DP sum_M = 0.0; for (int j = 0; j < chain.Nstrings; ++j) { sum_M += 0.5 * (1.0 + chain.par[j]) * base[j]; for (int alpha = 0; alpha < base[j]; ++alpha) { sum_Ix2 += Ix2[j][alpha]; } } iK = (chain.Nsites/2) * int(sum_M + 0.1) - (sum_Ix2/2); // + 0.1: for safety... while (iK >= chain.Nsites) iK -= chain.Nsites; while (iK < 0) iK += chain.Nsites; K = PI * sum_M - PI * sum_Ix2/chain.Nsites; while (K >= 2.0*PI) K -= 2.0*PI; while (K < 0.0) K += 2.0*PI; return; } */ void 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 += 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 * 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 (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 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 fbar_XXZ."); return (result); } DP Theta_XXZ (DP tanhlambda, int nj, int nk, int parj, int park, DP* tannzetaover2) { DP result = 0.0; if ((nj == 1) && (nk == 1)) result = fbar_XXZ(tanhlambda, parj*park, tannzetaover2[2]); else { result = (nj == nk) ? 0.0 : fbar_XXZ(tanhlambda, parj*park, tannzetaover2[fabs(nj - nk)]); for (int a = 1; a < ABACUS::min(nj, nk); ++a) result += 2.0 * fbar_XXZ(tanhlambda, parj*park, tannzetaover2[fabs(nj - nk) + 2*a]); result += fbar_XXZ(tanhlambda, parj*park, tannzetaover2[nj + nk]); } return (result); } DP 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 hbar_XXZ."); return (result); } DP 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 : 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 * hbar_XXZ(lambda, fabs(nj - nk) + 2*a, parj*park, si_n_anis_over_2); result += hbar_XXZ(lambda, nj + nk, parj*park, si_n_anis_over_2); return (result); } XXZ_Bethe_State Add_Particle_at_Center (const XXZ_Bethe_State& RefState) { if (2*RefState.base.Mdown == RefState.chain.Nsites) ABACUSerror("Trying to add a down spin to a zero-magnetized chain in Add_Particle_at_Center."); Vect newM = RefState.base.Nrap; newM[0] = newM[0] + 1; Heis_Base newBase (RefState.chain, newM); XXZ_Bethe_State ReturnState (RefState.chain, newBase); for (int il = 1; il < RefState.chain.Nstrings; ++il) for (int alpha = 0; alpha < RefState.base.Nrap[il]; ++alpha) ReturnState.Ix2[il][alpha] = RefState.Ix2[il][alpha]; // Add a quantum number in middle (explicitly: to right of index M[0]/2) // and shift quantum numbers by half-integer away from added one: ReturnState.Ix2[0][RefState.base.Nrap[0]/2] = RefState.Ix2[0][RefState.base.Nrap[0]/2] - 1; for (int i = 0; i < RefState.base.Nrap[0] + 1; ++i) ReturnState.Ix2[0][i + (i >= RefState.base.Nrap[0]/2)] = RefState.Ix2[0][i] - 1 + 2*(i >= RefState.base.Nrap[0]/2); return(ReturnState); } XXZ_Bethe_State Remove_Particle_at_Center (const XXZ_Bethe_State& RefState) { if (RefState.base.Nrap[0] == 0) ABACUSerror("Trying to remove a down spin in an empty Nrap[0] state."); Vect newM = RefState.base.Nrap; newM[0] = newM[0] - 1; Heis_Base newBase (RefState.chain, newM); XXZ_Bethe_State ReturnState (RefState.chain, newBase); for (int il = 1; il < RefState.chain.Nstrings; ++il) for (int alpha = 0; alpha < RefState.base.Nrap[il]; ++alpha) ReturnState.Ix2[il][alpha] = RefState.Ix2[il][alpha]; // Remove midmost and shift quantum numbers by half-integer towards removed one: for (int i = 0; i < RefState.base.Nrap[0]-1; ++i) ReturnState.Ix2[0][i] = RefState.Ix2[0][i + (i >= RefState.base.Nrap[0]/2)] + 1 - 2*(i >= RefState.base.Nrap[0]/2); return(ReturnState); } } // namespace ABACUS