#pragma once #include #include #include "types.hpp" #include "tensor.hpp" #include "factorial.hpp" template Vector normalize(const Eigen::MatrixBase& z) { return z * sqrt((Real)z.size() / (typename Derived::Scalar)(z.transpose() * z)); } template class pSpinModel { private: std::tuple, Tensor> hamGradTensorHelper(const Vector& z, const Tensor& J) const { Tensor J3(z.size(), z.size(), z.size());; J3.setZero(); Matrix Jz = Eigen::Map>(J.data(), z.size(), z.size()); return {Jz, J3}; } template std::tuple, Tensor> hamGradTensorHelper(const Vector& z, const Tensor& J) const { Tensor J3 = contractDown(J, z); Tensor zT = Eigen::TensorMap>(z.data(), {z.size()}); Tensor J3zT = J3.contract(zT, ip00); Matrix Jz = Eigen::Map>(J3zT.data(), z.size(), z.size()); return {Jz, J3}; } template std::tuple, Matrix, Tensor> hamGradHessHelper(const Vector& z, const Tensor& J, const Tensor& ...Js) const { auto [Jz, J3] = hamGradTensorHelper(z, J); Vector Jzz = Jz * z; Scalar Jzzz = Jzz.transpose() * z; Real pBang = factorial(p); Tensor dddH = ((p - 2) * (p - 1) * p / pBang) * J3; Matrix ddH = ((p - 1) * p / pBang) * Jz; Vector dH = (p / pBang) * Jzz; Scalar H = Jzzz / pBang; if constexpr (sizeof...(Js) > 0) { auto [Hs, dHs, ddHs, dddHs] = hamGradHessHelper(z, Js...); H += Hs; dH += dHs; ddH += ddHs; dddH += dddHs; } return {H, dH, ddH, dddH}; } public: std::tuple...> Js; pSpinModel() {} pSpinModel(const std::tuple...>& Js) : Js(Js) {} template pSpinModel(unsigned N, Generator& r, T... μs) { Js = std::make_tuple(μs * generateRealPSpinCouplings(N, r)...); } unsigned dimension() const { return std::get<0>(Js).dimension(0); } template pSpinModel cast() const { return std::apply( [] (const Tensor& ...Ks) -> std::tuple...> { return std::make_tuple(Ks.template cast()...); }, Js ); } template pSpinModel& operator*=(T x) { std::tuple...> newJs = std::apply( [x] (const Tensor& ...Ks) -> std::tuple...> { return std::make_tuple((x * Ks)...); }, Js ); Js = newJs; return *this; } std::tuple, Matrix, Tensor> hamGradHess(const Vector& z) const { return std::apply([&z, this](const Tensor& ...Ks) -> std::tuple, Matrix, Tensor> { return hamGradHessHelper(z, Ks...); }, Js); } Scalar getHamiltonian(const Vector& z) const { Scalar H; std::tie(H, std::ignore, std::ignore, std::ignore) = hamGradHess(z); return H; } Vector getGradient(const Vector& z) const { Vector dH; std::tie(std::ignore, dH, std::ignore, std::ignore) = hamGradHess(z); return dH; } Matrix getHessian(const Vector& z) const { Matrix ddH; std::tie(std::ignore, std::ignore, ddH, std::ignore) = hamGradHess(z); return ddH; } }; template Vector zDot(const Vector& z, const Vector& dH) { return -dH.conjugate() + (dH.dot(z) / z.squaredNorm()) * z.conjugate(); } template Matrix dzDot(const Vector& z, const Vector& dH) { Real z² = z.squaredNorm(); return (dH.conjugate() - (dH.dot(z) / z²) * z.conjugate()) * z.adjoint() / z²; } template Matrix dzDotConjugate(const Vector& z, const Vector& dH, const Matrix& ddH) { Real z² = z.squaredNorm(); return -ddH + (ddH * z.conjugate()) * z.transpose() / z² + (z.dot(dH) / z²) * ( Matrix::Identity(ddH.rows(), ddH.cols()) - z.conjugate() * z.transpose() / z² ); } template Tensor ddzDot(const Vector& z, const Vector& dH) { Tensor zT = Eigen::TensorMap>(z.data(), {z.size()}); Tensor dHT = Eigen::TensorMap>(dH.data(), {dH.size()}); Eigen::array, 0> ei = {}; Scalar z² = z.squaredNorm(); return - zT.conjugate().contract(dHT.conjugate(), ei).contract(zT.conjugate(), ei) / pow(z², 2) - dHT.conjugate().contract(zT.conjugate(), ei).contract(zT.conjugate(), ei) / pow(z², 2) + zT.conjugate().contract(zT.conjugate(), ei).contract(zT.conjugate(), ei) * ((Real)2 * dH.dot(z) / pow(z², 3)); } template Tensor dcdzDot(const Vector& z, const Vector& dH, const Matrix& ddH) { Tensor zT = Eigen::TensorMap>(z.data(), {z.size()}); Tensor dHT = Eigen::TensorMap>(dH.data(), {dH.size()}); Tensor ddHT = Eigen::TensorMap>(ddH.data(), {dH.size(), dH.size()}); Matrix I = Matrix::Identity(z.size(), z.size()); Tensor IT = Eigen::TensorMap>(I.data(), {z.size(), z.size()}); Eigen::array, 0> ei = {}; Scalar z² = z.squaredNorm(); return ddHT.conjugate().contract(zT.conjugate(), ei) / z² +IT.contract(dHT.conjugate(), ei).shuffle((std::array){0,2,1}) / z² -zT.contract(dHT.conjugate(), ei).contract(zT.conjugate(), ei) / pow(z², 2) -ddHT.conjugate().contract(zT, ip00).contract(zT.conjugate(), ei).contract(zT.conjugate(), ei) / pow(z², 2) -IT.contract(zT.conjugate(), ei) * (dH.dot(z) / pow(z², 2)) -IT.contract(zT.conjugate(), ei).shuffle((std::array){0,2,1}) * (dH.dot(z) / pow(z², 2)) +zT.contract(zT.conjugate(), ei).contract(zT.conjugate(), ei) * ((Real)2 * dH.dot(z) / pow(z², 3)) ; } template Tensor ddzDotConjugate(const Vector& z, const Vector& dH, const Matrix& ddH, const Tensor& dddH) { Tensor zT = Eigen::TensorMap>(z.data(), {z.size()}); Tensor dHT = Eigen::TensorMap>(dH.data(), {dH.size()}); Tensor ddHT = Eigen::TensorMap>(ddH.data(), {z.size(), z.size()}); Matrix I = Matrix::Identity(z.size(), z.size()); Tensor IT = Eigen::TensorMap>(I.data(), {z.size(), z.size()}); Eigen::array, 0> ei = {}; Eigen::array, 1> ip00 = {Eigen::IndexPair(0, 0)}; Scalar z² = z.squaredNorm(); return - dddH + dddH.contract(zT.conjugate(), ip00).contract(zT, ei) / z² + IT.contract(ddHT.contract(zT.conjugate(), ip00), ei).shuffle((std::array){0, 2, 1}) / z² + ddHT.contract(zT.conjugate(), ip00).contract(IT, ei) / z² - zT.conjugate().contract(ddHT.contract(zT.conjugate(), ip00), ei).contract(zT, ei) / pow(z², 2) - zT.conjugate().contract(IT, ei) * (z.dot(dH) / pow(z², 2)) - IT.contract(zT.conjugate(), ei).shuffle((std::array){0, 2, 1}) * (z.dot(dH) / pow(z², 2)) - ddHT.contract(zT.conjugate(), ip00).contract(zT.conjugate(), ei).contract(zT, ei) / pow(z², 2) + zT.conjugate().contract(zT.conjugate(), ei).contract(zT, ei) * ((Real)2 * z.dot(dH) / pow(z², 3)); }