static inline const typename Tensor::elt_t do_expected12(const iTEBD<Tensor> &psi, const Tensor &Op12, int site) { if (!psi.is_canonical()) { return do_expected12(psi.canonical_form(), Op12, site); } else { tensor::index a, i, b, j; const Tensor &AlA = psi.combined_matrix(0); const Tensor &BlB = psi.combined_matrix(1); AlA.get_dimensions(&a, &i, &b); BlB.get_dimensions(&b, &j, &a); Tensor v1 = psi.left_boundary(0); Tensor v2 = v1; if (site & 1) { v1 = propagate_right(v1, AlA); v2 = v1; const Tensor BlBAlA = reshape(fold(BlB, -1, AlA, 0), b, j*i, b); v1 = propagate_right(v1, BlBAlA, Op12); v2 = propagate_right(v2, BlBAlA); v1 = propagate_right(v1, BlB); v2 = propagate_right(v2, BlB); } else { const Tensor AlABlB = reshape(fold(AlA, -1, BlB, 0), a, i*j, a); v1 = propagate_right(v1, AlABlB, Op12); v2 = propagate_right(v2, AlABlB); } return trace(v1) / trace(v2); } }
static inline const typename Tensor::elt_t do_string_order(const iTEBD<Tensor> &psi, const Tensor &Opi, int i, const Tensor &Opmiddle, const Tensor &Opj, int j) { if (i == j) { return expected(psi, mmult(Opi, Opj), i); } else if (i > j) { return do_string_order(psi, Opj, j, Opmiddle, Opi, i); } else if (!psi.is_canonical()) { return do_string_order(psi.canonical_form(), Opi, i, Opmiddle, Opj, j); } else { j = j - i; i = i & 1; j = j + i; Tensor v1 = psi.left_boundary(0); Tensor v2 = v1; const Tensor none; const Tensor *op; for (int site = 0; (site <= j) || !(site & 1); ++site) { if (site == i) op = &Opi; else if (site == j) op = &Opj; else if (site > i && site < j) op = &Opmiddle; else op = &none; v1 = propagate_right(v1, psi.combined_matrix(site), *op); v2 = propagate_right(v2, psi.combined_matrix(site)); } return trace(v1) / trace(v2); } }
static inline const Tensor do_string_order_many(const iTEBD<Tensor> &psi, const Tensor &Opi, const Tensor &Opmiddle, const Tensor &Opj, int N) { if (!psi.is_canonical()) { return do_string_order_many(psi.canonical_form(), Opi, Opmiddle, Opj, N); } else { Tensor v1 = psi.left_boundary(0); Tensor v2 = v1; Tensor output(N); Tensor nextv2; for (int site = 0; (site < N); ++site) { const Tensor &aux = psi.combined_matrix(site); Tensor v = propagate_right(v1, aux, site? Opj : mmult(Opi,Opj)); if (nextv2.size()) { v2 = nextv2; } else { v2 = propagate_right(v2, aux); } if (!(site & 1)) { const Tensor &aux = psi.combined_matrix(site+1); nextv2 = propagate_right(v2, aux); v = propagate_right(v, aux); output.at(site) = trace(v) / trace(nextv2); } else { nextv2 = Tensor(); output.at(site) = trace(v) / trace(v2); } if (site) { v1 = propagate_right(v1, aux, Opmiddle); } else { v1 = propagate_right(v1, aux, Opi); } } return output; } }
const iTEBD<Tensor> evolve_itime(iTEBD<Tensor> psi, const Tensor &H12, double dt, tensor::index nsteps, double tolerance, tensor::index max_dim, tensor::index deltan, int method, std::vector<double> *energies, std::vector<double> *entropies) { static const double FR_param[5] = {0.67560359597983, 1.35120719195966, -0.17560359597983, -1.70241438391932}; Tensor eH12[4]; //int method = 2; switch (method) { case 1: /* Second order Trotter expansion */ eH12[1] = linalg::expm((-dt/2) * H12); case 0: /* First order Trotter expansion */ eH12[0] = linalg::expm((-dt) * H12); break; default: /* Fourth order Trotter expansion */ for (int i = 0; i < 4; i++) { eH12[i] = linalg::expm((-dt*FR_param[i]) * H12); } } Tensor Id = Tensor::eye(H12.rows()); double time = 0; psi = psi.canonical_form(); double E = energy(psi, H12), S = psi.entropy(); if (energies) energies->push_back(E); if (entropies) entropies->push_back(S); if (!deltan) { deltan = 1; } std::cout.precision(5); std::cout << nsteps << ", " << dt << " x " << deltan << " = " << dt * deltan << std::endl; std::cout << "t=" << time << ";\tE=" << E << "; dE=" << 0.0 << ";\tS=" << S << "; dS=" << 0.0 << ";\tl=" << std::max(psi.left_dimension(0), psi.right_dimension(0)) << std::endl << "l = " << matrix_form(real(psi.left_vector(0))) << std::endl; for (size_t phases = (nsteps + deltan - 1) / deltan; phases; phases--) { for (size_t i = 0; (i < deltan); i++) { switch (method) { case 0: psi = psi.apply_operator(eH12[0], 0, tolerance, max_dim); psi = psi.apply_operator(eH12[0], 1, tolerance, max_dim); break; case 1: psi = psi.apply_operator(eH12[1], 0, tolerance, max_dim); psi = psi.apply_operator(eH12[0], 1, tolerance, max_dim); psi = psi.apply_operator(eH12[1], 0, tolerance, max_dim); break; default: psi = psi.apply_operator(eH12[0], 0, tolerance, max_dim); psi = psi.apply_operator(eH12[1], 1, tolerance, max_dim); psi = psi.apply_operator(eH12[2], 0, tolerance, max_dim); psi = psi.apply_operator(eH12[3], 1, tolerance, max_dim); psi = psi.apply_operator(eH12[2], 0, tolerance, max_dim); psi = psi.apply_operator(eH12[1], 1, tolerance, max_dim); psi = psi.apply_operator(eH12[0], 0, tolerance, max_dim); } time += dt; } psi = psi.canonical_form(); double newE = energy(psi, H12); double newS = psi.entropy(); if (energies) energies->push_back(newE); if (entropies) entropies->push_back(newS); std::cout << "t=" << time << ";\tE=" << newE << "; dE=" << newE-E << ";\tS=" << newS << "; dS=" << newS-S << ";\tl=" << std::max(psi.left_dimension(0), psi.right_dimension(0)) << std::endl << "l = " << matrix_form(real(psi.left_vector(0))) << std::endl; E = newE; S = newS; } return psi; }