/* energy.c: Compute energetic properties of quantum systems Copyright 2013 Hendrik Weimer This file is part of libquantum libquantum is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. libquantum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with libquantum; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include "energy.h" #include "qureg.h" #include "qtime.h" #include "complex.h" extern void dstevd_(char *jobz, int *n, double *d, double *e, double *z, int *ldz, double *work, int *lwork, int *iwork, int *liwork, int *info); /* Modified Lanczos algorithm that iterates over a series of 2x2 matrix diagonalzations [E. Dagotto & A. Moreo, Phys. Rev. D 31, 865 (1985)] */ double quantum_lanczos_modified(quantum_reg H(MAX_UNSIGNED, double), double epsilon, quantum_reg *reg) { double E0=DBL_MAX, Eold=DBL_MAX, E1, E2, t; quantum_reg tmp, tmp2; int i; COMPLEX_FLOAT h01; double h00, h11; for(i=0; isize; i++) { quantum_normalize(reg); tmp = quantum_matrix_qureg(H, 0, reg, QUANTUM_RK4_NODELETE); h00 = quantum_real(quantum_dot_product(&tmp, reg)); E0 = h00; if(fabs(E0-Eold)size; n++) { lwork = n*n+4*n+1; work = realloc(work, lwork*sizeof(double)); liwork = 5*n+3; iwork = realloc(iwork, lwork*sizeof(int)); eig = realloc(eig, n*n*sizeof(double)); d = realloc(d, n*sizeof(double)); e = realloc(e, n*sizeof(double)); if(!(work && iwork && eig && d && e)) quantum_error(QUANTUM_ENOMEM); memcpy(d, a, n*sizeof(double)); for(i=0; i 0) quantum_error(QUANTUM_ELAPACKCONV); E0 = d[0]; if(fabs(E0-Eold) < epsilon) break; Eold = E0; phi = realloc(phi, (n+1)*sizeof(quantum_reg)); a = realloc(a, (n+1)*sizeof(double)); b = realloc(b, (n+1)*sizeof(double)); if(!(phi && a && b)) quantum_error(QUANTUM_ENOMEM); quantum_memman(sizeof(quantum_reg)+2*sizeof(double)); quantum_copy_qureg(&phi[n-1], &phi[n]); quantum_scalar_qureg(-a[n-1], &phi[n]); quantum_vectoradd_inplace(&phi[n], &tmp); quantum_delete_qureg(&tmp); quantum_copy_qureg(&phi[n-2], &tmp); quantum_scalar_qureg(-b[n-2], &tmp); quantum_vectoradd_inplace(&phi[n], &tmp); /* printf("%i %f\n", n, quantum_prob(quantum_dot_product(&phi[n], &phi[0]))); */ quantum_delete_qureg(&tmp); tmp = quantum_matrix_qureg(H, 0, &phi[n], QUANTUM_RK4_NODELETE); norm = quantum_dot_product(&phi[n], &phi[n]); a[n] = quantum_dot_product(&tmp, &phi[n]) / norm; b[n-1] = norm / quantum_dot_product(&phi[n-1], &phi[n-1]); } if(n == reg->size) { quantum_error(QUANTUM_ENOCONVERGE); return nan("0"); } for(i=0; isize; i++) { reg->amplitude[i] = 0; for(j=0; jamplitude[i] += eig[j]*phi[j].amplitude[i]; } quantum_delete_qureg(&tmp); for(i=0; isize; i++) { quantum_rk4(reg, 0, dt, H, QUANTUM_RK4_IMAGINARY | QUANTUM_RK4_NODELETE); reg2 = quantum_matrix_qureg(H, 0, reg, QUANTUM_RK4_NODELETE); E0 = quantum_real(quantum_dot_product(®2, reg)); quantum_delete_qureg(®2); if(fabs(Eold-E0)size) { quantum_error(QUANTUM_ENOCONVERGE); return nan("0"); } else return E0; } /* Wrapper around the various solver functions */ double quantum_groundstate(quantum_reg *reg, double epsilon, quantum_reg H(MAX_UNSIGNED, double), int solver, double stepsize) { switch(solver) { case QUANTUM_SOLVER_LANCZOS: return quantum_lanczos(H, epsilon, reg); case QUANTUM_SOLVER_LANCZOS_MODIFIED: return quantum_lanczos_modified(H, epsilon, reg); case QUANTUM_SOLVER_IMAGINARY_TIME: return quantum_imaginary_time(H, epsilon, stepsize, reg); default: quantum_error(QUANTUM_ENOSOLVER); return nan("0"); } }