ABACUS/src/ODSLF/ODSLF_XXZ_Bethe_State.cc

510 lines
17 KiB
C++

/**********************************************************
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<bool> 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<complex<DP> >& 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<DP> ( 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<DP> ((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<DP> (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