You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LiebLin_Bethe_State.cc 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. /**********************************************************
  2. This software is part of J.-S. Caux's ABACUS library.
  3. Copyright (c) J.-S. Caux.
  4. -----------------------------------------------------------
  5. File: LiebLin_Bethe_State.cc
  6. Purpose: Definitions for LiebLin_Bethe_State class.
  7. ***********************************************************/
  8. #include "ABACUS.h"
  9. using namespace std;
  10. namespace ABACUS {
  11. //***************************************************************************************************
  12. // Function definitions: class LiebLin_Bethe_State
  13. LiebLin_Bethe_State::LiebLin_Bethe_State ()
  14. : c_int (0.0), L(0.0), cxL(0.0), N(0),
  15. Ix2_available(Vect<int>(0, 1)), index_first_hole_to_right (Vect<int>(0,1)),
  16. displacement (Vect<int>(0,1)), Ix2(Vect<int>(0, 1)), lambdaoc(Vect<DP>(0.0, 1)),
  17. S(Vect<DP>(0.0, 1)), dSdlambdaoc(Vect<DP>(0.0, 1)), diffsq(0.0), prec(ITER_REQ_PREC_LIEBLIN),
  18. conv(0), iter_Newton(0), E(0.0), iK(0), K(0.0), lnnorm(-100.0)
  19. {
  20. stringstream Nout; Nout << N; label = Nout.str() + LABELSEP + ABACUScoding[0] + LABELSEP;
  21. }
  22. LiebLin_Bethe_State::LiebLin_Bethe_State (DP c_int_ref, DP L_ref, int N_ref)
  23. : c_int(c_int_ref), L(L_ref), cxL(c_int_ref * L_ref), N(N_ref),
  24. Ix2_available(Vect<int>(0, 2)), index_first_hole_to_right (Vect<int>(0,N)),
  25. displacement (Vect<int>(0,N)), Ix2(Vect<int>(0, N)), lambdaoc(Vect<DP>(0.0, N)),
  26. S(Vect<DP>(0.0, N)), dSdlambdaoc(Vect<DP>(0.0, N)),
  27. diffsq(0.0), prec(ABACUS::max(1.0, 1.0/(c_int * c_int)) * ITER_REQ_PREC_LIEBLIN),
  28. conv(0), iter_Newton(0), E(0.0), iK(0), K(0.0), lnnorm(-100.0)
  29. {
  30. if (c_int < 0.0) ABACUSerror("You must use a positive interaction parameter !");
  31. if (N < 0) ABACUSerror("Particle number must be strictly positive.");
  32. stringstream Nout; Nout << N; label = Nout.str() + LABELSEP + ABACUScoding[0] + LABELSEP;
  33. // Set quantum numbers to ground-state configuration:
  34. for (int i = 0; i < N; ++i) Ix2[i] = -(N-1) + 2*i;
  35. Vect<int> OriginIx2 = Ix2;
  36. (*this).Set_Label_from_Ix2 (OriginIx2);
  37. }
  38. LiebLin_Bethe_State& LiebLin_Bethe_State::operator= (const LiebLin_Bethe_State& RefState)
  39. {
  40. if (this != &RefState) {
  41. c_int = RefState.c_int;
  42. L = RefState.L;
  43. cxL = RefState.cxL;
  44. N = RefState.N;
  45. label = RefState.label;
  46. Ix2_available = RefState.Ix2_available;
  47. index_first_hole_to_right = RefState.index_first_hole_to_right;
  48. displacement = RefState.displacement;
  49. Ix2 = RefState.Ix2;
  50. lambdaoc = RefState.lambdaoc;
  51. S = RefState.S;
  52. dSdlambdaoc = RefState.dSdlambdaoc;
  53. diffsq = RefState.diffsq;
  54. prec = RefState.prec;
  55. conv = RefState.conv;
  56. iter_Newton = RefState.iter_Newton;
  57. E = RefState.E;
  58. iK = RefState.iK;
  59. K = RefState.K;
  60. lnnorm = RefState.lnnorm;
  61. }
  62. return(*this);
  63. }
  64. void LiebLin_Bethe_State::Set_to_Label (string label_ref, const Vect<int>& OriginStateIx2)
  65. {
  66. State_Label_Data labeldata = Read_State_Label (label_ref, OriginStateIx2);
  67. if (N != labeldata.M[0]) {
  68. cout << label_ref << endl;
  69. cout << labeldata.M << endl;
  70. ABACUSerror("Trying to set an incorrect label on LiebLin_Bethe_State: N != M[0].");
  71. }
  72. if (N != OriginStateIx2.size()) {
  73. cout << label_ref << endl;
  74. cout << labeldata.M << endl;
  75. ABACUSerror("Trying to set an incorrect label on LiebLin_Bethe_State: "
  76. "N != OriginStateIx2.size().");
  77. }
  78. label = label_ref;
  79. Vect<int> OriginStateIx2ordered = OriginStateIx2;
  80. OriginStateIx2ordered.QuickSort();
  81. // Set all Ix2 to OriginState's Ix2:
  82. for (int i = 0; i < N; ++i) Ix2[i] = OriginStateIx2ordered[i];
  83. // Now set the excitations:
  84. for (int iexc = 0; iexc < labeldata.nexc[0]; ++iexc)
  85. for (int i = 0; i < N; ++i)
  86. if (Ix2[i] == labeldata.Ix2old[0][iexc]) Ix2[i] = labeldata.Ix2exc[0][iexc];
  87. // Now reorder the Ix2 to follow convention:
  88. Ix2.QuickSort();
  89. (*this).Set_Label_from_Ix2 (OriginStateIx2ordered);
  90. }
  91. void LiebLin_Bethe_State::Set_to_Label (string label_ref)
  92. {
  93. // This function assumes that OriginState is the ground state.
  94. Vect<int> OriginStateIx2(N);
  95. for (int i = 0; i < N; ++i) OriginStateIx2[i] = -N + 1 + 2*i;
  96. (*this).Set_to_Label(label_ref, OriginStateIx2);
  97. }
  98. void LiebLin_Bethe_State::Set_Label_from_Ix2 (const Vect<int>& OriginStateIx2)
  99. {
  100. // This function does not assume any ordering of the Ix2.
  101. if (N != OriginStateIx2.size()) ABACUSerror("N != OriginStateIx2.size() in Set_Label_from_Ix2.");
  102. // Set the state label:
  103. Vect<int> type_ref(0,1);
  104. Vect<int> M_ref(N, 1);
  105. Vect<int> nexc_ref(0, 1);
  106. // Count nr of particle-holes:
  107. for (int i = 0; i < N; ++i) if (!OriginStateIx2.includes(Ix2[i])) nexc_ref[0] += 1;
  108. Vect<Vect<int> > Ix2old_ref(1);
  109. Vect<Vect<int> > Ix2exc_ref(1);
  110. Ix2old_ref[0] = Vect<int>(ABACUS::max(nexc_ref[0],1));
  111. Ix2exc_ref[0] = Vect<int>(ABACUS::max(nexc_ref[0],1));
  112. int nexccheck = 0;
  113. for (int i = 0; i < N; ++i)
  114. if (!OriginStateIx2.includes(Ix2[i])) Ix2exc_ref[0][nexccheck++] = Ix2[i];
  115. if (nexccheck != nexc_ref[0])
  116. ABACUSerror("Counting excitations wrong (1) in LiebLin_Bethe_State::Set_Label_from_Ix2");
  117. nexccheck = 0;
  118. for (int i = 0; i < N; ++i)
  119. if (!Ix2.includes (OriginStateIx2[i])) Ix2old_ref[0][nexccheck++] = OriginStateIx2[i];
  120. if (nexccheck != nexc_ref[0]) {
  121. cout << "nexc_ref[0] = " << nexc_ref[0] << "\tnexccheck = " << nexccheck << endl;
  122. cout << OriginStateIx2 << endl;
  123. cout << Ix2 << endl;
  124. cout << nexc_ref[0] << endl;
  125. cout << Ix2old_ref[0] << endl;
  126. cout << Ix2exc_ref[0] << endl;
  127. ABACUSerror("Counting excitations wrong (2) in LiebLin_Bethe_State::Set_Label_from_Ix2");
  128. }
  129. // Now order the Ix2old_ref and Ix2exc_ref:
  130. Ix2old_ref[0].QuickSort();
  131. Ix2exc_ref[0].QuickSort();
  132. State_Label_Data labeldata(type_ref, M_ref, nexc_ref, Ix2old_ref, Ix2exc_ref);
  133. label = Return_State_Label (labeldata, OriginStateIx2);
  134. }
  135. void LiebLin_Bethe_State::Set_Label_Internals_from_Ix2 (const Vect<int>& OriginStateIx2)
  136. {
  137. if (N != OriginStateIx2.size())
  138. ABACUSerror("N != OriginStateIx2.size() in Set_Label_Internals_from_Ix2.");
  139. Vect<int> OriginStateIx2ordered = OriginStateIx2;
  140. OriginStateIx2ordered.QuickSort();
  141. // Set the state label:
  142. Vect<int> type_ref(0,1);
  143. Vect<int> M_ref(N, 1);
  144. Vect<int> nexc_ref(0, 1);
  145. // Count nr of particle-holes:
  146. for (int i = 0; i < N; ++i) if (!OriginStateIx2.includes(Ix2[i])) nexc_ref[0] += 1;
  147. Vect<Vect<int> > Ix2old_ref(1);
  148. Vect<Vect<int> > Ix2exc_ref(1);
  149. Ix2old_ref[0] = Vect<int>(ABACUS::max(nexc_ref[0],1));
  150. Ix2exc_ref[0] = Vect<int>(ABACUS::max(nexc_ref[0],1));
  151. int nexccheck = 0;
  152. for (int i = 0; i < N; ++i)
  153. if (Ix2[i] != OriginStateIx2ordered[i]) {
  154. Ix2old_ref[0][nexccheck] = OriginStateIx2ordered[i];
  155. Ix2exc_ref[0][nexccheck++] = Ix2[i];
  156. }
  157. State_Label_Data labeldata(type_ref, M_ref, nexc_ref, Ix2old_ref, Ix2exc_ref);
  158. label = Return_State_Label (labeldata, OriginStateIx2);
  159. // Construct the Ix2_available vector: we give one more quantum number on left and right:
  160. int navailable = 2 + (ABACUS::max(Ix2.max(), OriginStateIx2.max())
  161. - ABACUS::min(Ix2.min(), OriginStateIx2.min()))/2 - N + 1;
  162. Ix2_available = Vect<int>(navailable);
  163. index_first_hole_to_right = Vect<int>(N);
  164. // First set Ix2_available to all holes from left
  165. for (int i = 0; i < Ix2_available.size(); ++i)
  166. Ix2_available[i] = ABACUS::min(Ix2.min(), OriginStateIx2.min()) - 2 + 2*i;
  167. // Now shift according to Ix2 of OriginState:
  168. for (int j = 0; j < N; ++j) {
  169. int i = 0;
  170. while (Ix2_available[i] < OriginStateIx2ordered[j]) i++;
  171. // We now have Ix2_available[i] == OriginStateIx2[j].
  172. // Shift all Ix2_available to the right of this by 2;
  173. for (int i1 = i; i1 < navailable; ++i1) Ix2_available[i1] += 2;
  174. index_first_hole_to_right[j] = i;
  175. }
  176. // Ix2_available and index_first_hole_to_right are now fully defined.
  177. // Now set displacement vector:
  178. displacement = Vect<int>(0, N);
  179. // Set displacement vector from the Ix2:
  180. for (int j = 0; j < N; ++j) {
  181. if (Ix2[j] < OriginStateIx2ordered[j]) {
  182. // Ix2[j] must be equal to some OriginState_Ix2_available[i]
  183. // for i < OriginState_index_first_hole_to_right[j]
  184. while (Ix2[j] != Ix2_available[index_first_hole_to_right[j] + displacement[j] ]) {
  185. if (index_first_hole_to_right[j] + displacement[j] == 0) {
  186. cout << label << endl << j << endl << OriginStateIx2 << endl
  187. << Ix2 << endl << Ix2_available
  188. << endl << index_first_hole_to_right << endl << displacement << endl;
  189. ABACUSerror("Going down too far in Set_Label_Internals...");
  190. }
  191. displacement[j]--;
  192. }
  193. }
  194. if (Ix2[j] > OriginStateIx2ordered[j]) {
  195. // Ix2[j] must be equal to some Ix2_available[i] for i >= index_first_hole_to_right[j]
  196. displacement[j] = 1; // start with this value to prevent segfault
  197. while (Ix2[j] != Ix2_available[index_first_hole_to_right[j] - 1 + displacement[j] ]) {
  198. if (index_first_hole_to_right[j] + displacement[j] == Ix2_available.size() - 1) {
  199. cout << label << endl << j << endl << OriginStateIx2 << endl
  200. << Ix2 << endl << Ix2_available
  201. << endl << index_first_hole_to_right << endl << displacement << endl;
  202. ABACUSerror("Going up too far in Set_Label_Internals...");
  203. }
  204. displacement[j]++;
  205. }
  206. }
  207. }
  208. }
  209. bool LiebLin_Bethe_State::Check_Admissibility (char whichDSF)
  210. {
  211. // For testing with restricted Hilbert space:
  212. //if (Ix2.min() < -13 || Ix2.max() > 13) return(false);
  213. return(true);
  214. }
  215. void LiebLin_Bethe_State::Find_Rapidities (bool reset_rapidities)
  216. {
  217. // This function finds the rapidities of the eigenstate
  218. // sentinel value, recalculated if Newton method used in the last step of iteration.
  219. lnnorm = -100.0;
  220. diffsq = 1.0;
  221. if (reset_rapidities) (*this).Set_Free_lambdaocs();
  222. iter_Newton = 0;
  223. DP damping = 1.0;
  224. DP diffsq_prev = 1.0e+6;
  225. Vect_DP RHSBAE (0.0, N); // contains RHS of BAEs
  226. Vect_DP dlambdaoc (0.0, N); // contains delta lambdaoc computed from Newton's method
  227. SQMat_DP Gaudin (0.0, N);
  228. Vect_INT indx (N);
  229. while (diffsq > prec && !is_nan(diffsq) && iter_Newton < 100) {
  230. (*this).Iterate_BAE_Newton(damping, RHSBAE, dlambdaoc, Gaudin, indx);
  231. if (diffsq > diffsq_prev && damping > 0.5) damping /= 2.0;
  232. else if (diffsq < diffsq_prev) damping = 1.0;
  233. diffsq_prev = diffsq;
  234. }
  235. conv = ((diffsq < prec) && (*this).Check_Rapidities()) ? 1 : 0;
  236. if (!conv) {
  237. cout << "Alert! State " << label << " did not converge... diffsq " << diffsq
  238. << "\titer_Newton " << iter_Newton << (*this) << endl;
  239. }
  240. return;
  241. }
  242. bool LiebLin_Bethe_State::Check_Rapidities()
  243. {
  244. bool nonan = true;
  245. for (int j = 0; j < N; ++j) nonan *= !is_nan(lambdaoc[j]);
  246. return nonan;
  247. }
  248. /**
  249. For the repulsive Lieb-Liniger model, all eigenstates have real rapidities
  250. (there are no strings). All string deviations are thus set to zero.
  251. */
  252. DP LiebLin_Bethe_State::String_delta()
  253. {
  254. return(0.0);
  255. }
  256. /**
  257. Checks whether the quantum numbers are symmetrically distributed: \f$\{ I \} = \{ -I \}\f$.
  258. */
  259. bool LiebLin_Bethe_State::Check_Symmetry ()
  260. {
  261. bool symmetric_state = true;
  262. Vect<int> Ix2check = Ix2;
  263. Ix2check.QuickSort();
  264. for (int alpha = 0; alpha <= N/2; ++alpha)
  265. symmetric_state = symmetric_state && (Ix2check[alpha] == -Ix2check[N - 1 - alpha]);
  266. return(symmetric_state);
  267. }
  268. /**
  269. This function computes the log of the norm of a `LiebLin_Bethe_State` instance.
  270. This is obtained from the Gaudin-Korepin norm formula
  271. \f{eqnarray*}{
  272. \langle 0 | \prod_{j=0}^{N-1} C(\lambda_j) \prod_{j=0}^{N-1} B(\lambda_j) | 0 \rangle
  273. = \prod_{j=0}^{N-2}\prod_{k=j+1}^{N-1}
  274. \frac{(\lambda_j - \lambda_k )^2 + c^2}{(\lambda_j - \lambda_k)^2}
  275. \times ~\mbox{Det}_N G
  276. \f}
  277. in which \f$G\f$ is the Gaudin matrix computed by
  278. LiebLin_Bethe_State::Build_Reduced_Gaudin_Matrix.
  279. */
  280. void LiebLin_Bethe_State::Compute_lnnorm ()
  281. {
  282. if (lnnorm == -100.0) { // else Gaudin part already calculated by Newton method
  283. SQMat_DP Gaudin_Red(N);
  284. (*this).Build_Reduced_Gaudin_Matrix(Gaudin_Red);
  285. complex<DP> lnnorm_CX = lndet_LU_dstry(Gaudin_Red);
  286. if (abs(imag(lnnorm_CX)) > 1.0e-6) {
  287. cout << "lnnorm_CX = " << lnnorm_CX << endl;
  288. ABACUSerror("Gaudin norm of LiebLin_Bethe_State should be real and positive.");
  289. }
  290. lnnorm = real(lnnorm_CX);
  291. // Add the pieces outside of Gaudin determinant
  292. for (int j = 0; j < N - 1; ++j) for (int k = j+1; k < N; ++k)
  293. lnnorm += log(1.0 + 1.0/pow(lambdaoc[j] - lambdaoc[k], 2.0));
  294. }
  295. return;
  296. }
  297. /**
  298. This function solves the Bethe equations, computes the energy, momentum and state norm.
  299. It calls LiebLin_Bethe_State::Find_Rapidities, LiebLin_Bethe_State::Compute_Energy,
  300. LiebLin_Bethe_State::Compute_Momentum and LiebLin_Bethe_State::Compute_lnnorm.
  301. Assumptions:
  302. - the set of quantum numbers is admissible.
  303. */
  304. void LiebLin_Bethe_State::Compute_All (bool reset_rapidities)
  305. {
  306. (*this).Find_Rapidities (reset_rapidities);
  307. if (conv == 1) {
  308. (*this).Compute_Energy ();
  309. (*this).Compute_Momentum ();
  310. (*this).Compute_lnnorm ();
  311. }
  312. return;
  313. }
  314. void LiebLin_Bethe_State::Set_Free_lambdaocs()
  315. {
  316. if (cxL >= 1.0)
  317. for (int a = 0; a < N; ++a) lambdaoc[a] = PI * Ix2[a]/cxL;
  318. // For small values of c, use better approximation using approximate
  319. // zeroes of Hermite polynomials: see Gaudin eqn 4.71.
  320. if (cxL < 1.0) {
  321. DP oneoversqrtcLN = 1.0/pow(cxL * N, 0.5);
  322. for (int a = 0; a < N; ++a) lambdaoc[a] = oneoversqrtcLN * PI * Ix2[a];
  323. }
  324. return;
  325. }
  326. void LiebLin_Bethe_State::Iterate_BAE (DP damping)
  327. {
  328. // does one step of simple iterations
  329. DP sumtheta = 0.0;
  330. Vect_DP dlambdaoc (0.0, N);
  331. for (int j = 0; j < N; ++j) {
  332. sumtheta = 0.0;
  333. for (int k = 0; k < N; ++k) sumtheta += atan((lambdaoc[j] - lambdaoc[k]));
  334. sumtheta *= 2.0;
  335. dlambdaoc[j] = damping * ((PI*Ix2[j] - sumtheta)/cxL - lambdaoc[j]);
  336. }
  337. diffsq = 0.0;
  338. for (int i = 0; i < N; ++i) {
  339. lambdaoc[i] += dlambdaoc[i];
  340. // Normalize the diffsq by the typical value of the rapidities:
  341. if (cxL > 1.0) diffsq += dlambdaoc[i] * dlambdaoc[i]/(lambdaoc[i] * lambdaoc[i] + 1.0e-6);
  342. else diffsq += cxL * cxL * dlambdaoc[i] * dlambdaoc[i]/(lambdaoc[i] * lambdaoc[i] + 1.0e-6);
  343. }
  344. diffsq /= DP(N);
  345. return;
  346. }
  347. void LiebLin_Bethe_State::Iterate_BAE_S (DP damping)
  348. {
  349. // This is essentially Newton's method but only in one variable.
  350. // The logic is that the derivative of the LHS of the BE_j w/r to lambdaoc_j is much larger
  351. // than with respect to lambdaoc_l with l != j.
  352. Vect_DP dlambdaoc (0.0, N);
  353. // Start by calculating S and dSdlambdaoc:
  354. for (int j = 0; j < N; ++j) {
  355. S[j] = 0.0;
  356. for (int k = 0; k < N; ++k) S[j] += atan((lambdaoc[j] - lambdaoc[k]));
  357. S[j] *= 2.0/cxL;
  358. dSdlambdaoc[j] = 0.0;
  359. for (int k = 0; k < N; ++k)
  360. dSdlambdaoc[j] += 1.0/((lambdaoc[j] - lambdaoc[k]) * (lambdaoc[j] - lambdaoc[k]) + 1.0);
  361. dSdlambdaoc[j] *= 2.0/(PI * cxL);
  362. dlambdaoc[j] = (PI*Ix2[j]/cxL - S[j] + lambdaoc[j] * dSdlambdaoc[j])
  363. /(1.0 + dSdlambdaoc[j]) - lambdaoc[j];
  364. }
  365. diffsq = 0.0;
  366. for (int i = 0; i < N; ++i) {
  367. lambdaoc[i] += damping * dlambdaoc[i];
  368. // Normalize the diffsq by the typical value of the rapidities:
  369. if (cxL > 1.0) diffsq += dlambdaoc[i] * dlambdaoc[i]/(lambdaoc[i] * lambdaoc[i] + 1.0e-6);
  370. else diffsq += cxL * cxL * dlambdaoc[i] * dlambdaoc[i]/(lambdaoc[i] * lambdaoc[i] + 1.0e-6);
  371. }
  372. diffsq /= DP(N);
  373. iter_Newton++;
  374. return;
  375. }
  376. /**
  377. Performs one step of the matrix Newton method on the rapidities.
  378. */
  379. void LiebLin_Bethe_State::Iterate_BAE_Newton (DP damping, Vect_DP& RHSBAE, Vect_DP& dlambdaoc, SQMat_DP& Gaudin, Vect_INT& indx)
  380. {
  381. DP sumtheta = 0.0;
  382. // for large |lambda|, use atan (lambda) = sgn(lambda) pi/2 - atan(1/lambda)
  383. int atanintshift = 0;
  384. DP lambdahere = 0.0;
  385. // Compute the RHS of the BAEs:
  386. for (int j = 0; j < N; ++j) {
  387. sumtheta = 0.0;
  388. atanintshift = 0;
  389. for (int k = 0; k < N; ++k)
  390. if (j != k) { // otherwise 0
  391. if (fabs(lambdahere = lambdaoc[j] - lambdaoc[k]) < 1.0) { // use straight atan
  392. sumtheta += atan(lambdahere);
  393. }
  394. else { // for large rapidities, use dual form of atan, extracting pi/2 factors
  395. atanintshift += sgn_DP(lambdahere);
  396. sumtheta -= atan(1.0/lambdahere);
  397. }
  398. }
  399. sumtheta *= 2.0;
  400. RHSBAE[j] = cxL * lambdaoc[j] + sumtheta - PI*(Ix2[j] - atanintshift);
  401. }
  402. (*this).Build_Reduced_Gaudin_Matrix (Gaudin);
  403. for (int j = 0; j < N; ++j) dlambdaoc[j] = - RHSBAE[j];
  404. DP d;
  405. ludcmp (Gaudin, indx, d);
  406. lubksb (Gaudin, indx, dlambdaoc);
  407. bool ordering_changed = false;
  408. for (int j = 0; j < N-1; ++j)
  409. if (lambdaoc[j] + dlambdaoc[j] > lambdaoc[j+1] + dlambdaoc[j+1]) ordering_changed = true;
  410. // To prevent Newton from diverging, we limit the size of the rapidity changes.
  411. // The leftmost and rightmost rapidities can grow by one order of magnitude per iteration step.
  412. if (ordering_changed) {
  413. // We explicitly ensure that the ordering remains correct after the iteration step.
  414. bool ordering_still_changed = false;
  415. DP maxdlambdaoc = 0.0;
  416. do {
  417. ordering_still_changed = false;
  418. if (dlambdaoc[0] < 0.0 && fabs(dlambdaoc[0])
  419. > (maxdlambdaoc = 10.0*ABACUS::max(fabs(lambdaoc[0]), fabs(lambdaoc[N-1]))))
  420. dlambdaoc[0] = -maxdlambdaoc;
  421. if (lambdaoc[0] + dlambdaoc[0] > lambdaoc[1] + dlambdaoc[1]) {
  422. dlambdaoc[0] = 0.25 * (lambdaoc[1] + dlambdaoc[1] - lambdaoc[0] ); // max quarter distance
  423. ordering_still_changed = true;
  424. }
  425. if (dlambdaoc[N-1] > 0.0 && fabs(dlambdaoc[N-1])
  426. > (maxdlambdaoc = 10.0*ABACUS::max(fabs(lambdaoc[0]), fabs(lambdaoc[N-1]))))
  427. dlambdaoc[N-1] = maxdlambdaoc;
  428. if (lambdaoc[N-1] + dlambdaoc[N-1] < lambdaoc[N-2] + dlambdaoc[N-2]) {
  429. dlambdaoc[N-1] = 0.25 * (lambdaoc[N-2] + dlambdaoc[N-2] - lambdaoc[N-1]);
  430. ordering_still_changed = true;
  431. }
  432. for (int j = 1; j < N-1; ++j) {
  433. if (lambdaoc[j] + dlambdaoc[j] > lambdaoc[j+1] + dlambdaoc[j+1]) {
  434. dlambdaoc[j] = 0.25 * (lambdaoc[j+1] + dlambdaoc[j+1] - lambdaoc[j]);
  435. ordering_still_changed = true;
  436. }
  437. if (lambdaoc[j] + dlambdaoc[j] < lambdaoc[j-1] + dlambdaoc[j-1]) {
  438. dlambdaoc[j] = 0.25 * (lambdaoc[j-1] + dlambdaoc[j-1] - lambdaoc[j]);
  439. ordering_still_changed = true;
  440. }
  441. }
  442. } while (ordering_still_changed);
  443. }
  444. diffsq = 0.0;
  445. for (int i = 0; i < N; ++i) {
  446. // Normalize the diffsq by the typical value of the rapidities:
  447. if (cxL > 1.0) diffsq += dlambdaoc[i] * dlambdaoc[i]/(lambdaoc[i] * lambdaoc[i] + 1.0e-6);
  448. else diffsq += cxL * cxL * dlambdaoc[i] * dlambdaoc[i]/(lambdaoc[i] * lambdaoc[i] + 1.0e-6);
  449. }
  450. diffsq /= DP(N);
  451. if (ordering_changed) diffsq = 1.0; // reset if Newton wanted to change ordering
  452. for (int j = 0; j < N; ++j) lambdaoc[j] += damping * dlambdaoc[j];
  453. iter_Newton++;
  454. // if we've converged, calculate the norm here, since the work has been done...
  455. if (diffsq < prec && !ordering_changed) {
  456. lnnorm = 0.0;
  457. for (int j = 0; j < N; j++) lnnorm += log(fabs(Gaudin[j][j]));
  458. // Add the pieces outside of Gaudin determinant
  459. for (int j = 0; j < N - 1; ++j)
  460. for (int k = j+1; k < N; ++k)
  461. lnnorm += log(1.0 + 1.0/pow(lambdaoc[j] - lambdaoc[k], 2.0));
  462. }
  463. return;
  464. }
  465. void LiebLin_Bethe_State::Compute_Energy()
  466. {
  467. E = 0.0;
  468. for (int j = 0; j < N; ++j) E += lambdaoc[j] * lambdaoc[j];
  469. E *= c_int * c_int;
  470. }
  471. void LiebLin_Bethe_State::Compute_Momentum()
  472. {
  473. iK = 0;
  474. for (int j = 0; j < N; ++j) {
  475. iK += Ix2[j];
  476. }
  477. if (iK % 2) {
  478. cout << Ix2 << endl;
  479. cout << iK << "\t" << iK % 2 << endl;
  480. ABACUSerror("Sum of Ix2 is not even: inconsistency.");
  481. }
  482. iK /= 2; // sum of Ix2 is guaranteed even.
  483. K = 2.0 * iK * PI/L;
  484. }
  485. /**
  486. The fundamental scattering kernel for Lieb-Liniger,
  487. \f[
  488. K (\tilde{\lambda}) = \frac{ 2 }{\tilde{\lambda}^2 + 1}
  489. \f]
  490. given two indices for the rapidities as arguments.
  491. */
  492. DP LiebLin_Bethe_State::Kernel (int a, int b)
  493. {
  494. return(2.0/(pow(lambdaoc[a] - lambdaoc[b], 2.0) + 1.0));
  495. }
  496. /**
  497. The fundamental scattering kernel for Lieb-Liniger,
  498. \f[
  499. K (\tilde{\lambda}) = \frac{ 2 }{\tilde{\lambda}^2 + 1}
  500. \f]
  501. given the rapidity difference as argument.
  502. */
  503. DP LiebLin_Bethe_State::Kernel (DP lambdaoc_ref)
  504. {
  505. return(2.0/(lambdaoc_ref * lambdaoc_ref + 1.0));
  506. }
  507. /**
  508. This function constructs the Gaudin matrix \f$G\f$
  509. which is defined as the Hessian of the Yang-Yang action \f$S^{YY}\f$,
  510. \f[
  511. G_{jk} = \delta_{jk} \left\{ cL + \sum_{l} K (\tilde{\lambda}_j - \tilde{\lambda}_l) \right\}
  512. - K (\tilde{\lambda}_j - \tilde{\lambda}_k).
  513. \f]
  514. */
  515. void LiebLin_Bethe_State::Build_Reduced_Gaudin_Matrix (SQMat<DP>& Gaudin_Red)
  516. {
  517. if (Gaudin_Red.size() != N)
  518. ABACUSerror("Passing matrix of wrong size in Build_Reduced_Gaudin_Matrix.");
  519. DP sum_Kernel = 0.0;
  520. for (int j = 0; j < N; ++j)
  521. for (int k = 0; k < N; ++k) {
  522. if (j == k) {
  523. sum_Kernel = 0.0;
  524. for (int kp = 0; kp < N; ++kp)
  525. if (j != kp) sum_Kernel += Kernel (lambdaoc[j] - lambdaoc[kp]);
  526. Gaudin_Red[j][k] = cxL + sum_Kernel;
  527. }
  528. else Gaudin_Red[j][k] = - Kernel (lambdaoc[j] - lambdaoc[k]);
  529. }
  530. return;
  531. }
  532. /**
  533. For a summetric `LiebLin_Bethe_State`, this function computes the Gaudin matrix
  534. as an \f$N/2 \times N/2\f$ matrix to accelerate computations.
  535. */
  536. void LiebLin_Bethe_State::Build_Reduced_BEC_Quench_Gaudin_Matrix (SQMat<DP>& Gaudin_Red)
  537. {
  538. // Passing a matrix of dimension N/2
  539. if (N % 2 != 0) ABACUSerror("Choose a state with even numer of particles please");
  540. // Check Parity invariant
  541. bool ck = true;
  542. for (int j = 0; j < N/2; ++j){ if(Ix2[j] != - Ix2[N-j-1]) ck = false;}
  543. if (!ck) ABACUSerror("Choose a parity invariant state please");
  544. if (Gaudin_Red.size() != N/2)
  545. ABACUSerror("Passing matrix of wrong size in Build_Reduced_Gaudin_Matrix.");
  546. DP sum_Kernel = 0.0;
  547. for (int j = 0; j < N/2; ++j)
  548. for (int k = 0; k < N/2; ++k) {
  549. if (j == k) {
  550. sum_Kernel = 0.0;
  551. for (int kp = N/2; kp < N; ++kp)
  552. if (j + N/2 != kp)
  553. sum_Kernel += Kernel (lambdaoc[j+N/2] - lambdaoc[kp])
  554. + Kernel (lambdaoc[j+N/2] + lambdaoc[kp]);
  555. Gaudin_Red[j][k] = cxL + sum_Kernel;
  556. }
  557. else Gaudin_Red[j][k] = - (Kernel (lambdaoc[j+ N/2] - lambdaoc[k+ N/2])
  558. + Kernel (lambdaoc[j+ N/2] + lambdaoc[k+ N/2]) );
  559. }
  560. return;
  561. }
  562. /**
  563. This function changes the Ix2 of a given state by annihilating a particle and hole
  564. pair specified by ipart and ihole (counting from the left, starting with index 0).
  565. */
  566. void LiebLin_Bethe_State::Annihilate_ph_pair (int ipart, int ihole,
  567. const Vect<int>& OriginStateIx2)
  568. {
  569. State_Label_Data currentdata = Read_State_Label ((*this).label, OriginStateIx2);
  570. if (ipart >= currentdata.nexc[0])
  571. ABACUSerror("Particle label too large in LiebLin_Bethe_State::Annihilate_ph_pair.");
  572. if (ihole >= currentdata.nexc[0])
  573. ABACUSerror("Hole label too large in LiebLin_Bethe_State::Annihilate_ph_pair.");
  574. // Simply remove the given pair:
  575. Vect<int> type_new = currentdata.type;
  576. Vect<int> M_new = currentdata.M;
  577. Vect<int> nexc_new = currentdata.nexc;
  578. nexc_new[0] -= 1; // we drill one more particle-hole pair at level 0
  579. int ntypespresent = 1; // only one type for LiebLin
  580. Vect<Vect<int> > Ix2old_new(ntypespresent);
  581. Vect<Vect<int> > Ix2exc_new(ntypespresent);
  582. for (int it = 0; it < ntypespresent; ++it)
  583. Ix2old_new[it] = Vect<int>(ABACUS::max(nexc_new[it],1));
  584. for (int it = 0; it < ntypespresent; ++it)
  585. Ix2exc_new[it] = Vect<int>(ABACUS::max(nexc_new[it],1));
  586. // Copy earlier data in, leaving out ipart and ihole:
  587. for (int it = 0; it < ntypespresent; ++it) {
  588. for (int i = 0; i < nexc_new[it]; ++i) {
  589. Ix2old_new[it][i] = currentdata.Ix2old[it][i + (i >= ihole)];
  590. Ix2exc_new[it][i] = currentdata.Ix2exc[it][i + (i >= ipart)];
  591. }
  592. }
  593. State_Label_Data newdata (type_new, M_new, nexc_new, Ix2old_new, Ix2exc_new);
  594. (*this).Set_to_Label (Return_State_Label(newdata, OriginStateIx2));
  595. }
  596. /**
  597. Performs a spatial inversion of a `LiebLin_Bethe_State`, mapping all quantum numbers
  598. and rapidities to minus themselves.
  599. */
  600. void LiebLin_Bethe_State::Parity_Flip ()
  601. {
  602. Vect_INT Ix2buff = Ix2;
  603. Vect_DP lambdaocbuff = lambdaoc;
  604. for (int i = 0; i < N; ++i) Ix2[i] = -Ix2buff[N - 1 - i];
  605. for (int i = 0; i < N; ++i) lambdaoc[i] = -lambdaocbuff[N - 1 - i];
  606. iK = -iK;
  607. K = -K;
  608. }
  609. /**
  610. Send information about a `LiebLin_Bethe_State` to the output stream.
  611. */
  612. std::ostream& operator<< (std::ostream& s, const LiebLin_Bethe_State& state)
  613. {
  614. s << endl << "******** State for c = " << state.c_int << " L = " << state.L
  615. << " N = " << state.N << " with label " << state.label << " ********" << endl;
  616. s << "Ix2:" << endl;
  617. for (int j = 0; j < state.N; ++j) s << state.Ix2[j] << " ";
  618. s << endl << "lambdaocs:" << endl;
  619. for (int j = 0; j < state.N; ++j) s << state.lambdaoc[j] << " ";
  620. s << endl << "conv = " << state.conv << " iter_Newton = " << state.iter_Newton << endl;
  621. s << "E = " << state.E << " iK = " << state.iK << " K = " << state.K
  622. << " lnnorm = " << state.lnnorm << endl;
  623. return(s);
  624. }
  625. } // namespace ABACUS