mod operator;
mod validation;
#[cfg(test)]
mod tests;
pub(crate) use operator::EffectiveHamiltonian2SiteBlockSparse;
use ariadnetor_core::Scalar;
use ariadnetor_linalg::{BlockScalars, TruncSvdParams, trunc_svd};
use ariadnetor_mps::{Mpo, Mps};
use ariadnetor_tensor::{BlockSparseLayout, BlockSparseStorage, BlockSparseTensor, Host, Sector};
#[cfg(feature = "arpack")]
use crate::krylov::arpack_smallest;
use crate::krylov::lanczos_smallest;
use super::heff_error::DmrgHeffError;
use super::solver::{DmrgScalar, LocalEigensolverParams};
use ariadnetor_mps::BraketEnvs;
pub struct TwoSiteStepResultBlockSparse<T: Scalar, S: Sector> {
pub eigenvalue: T::Real,
pub residual: T::Real,
pub iters: usize,
pub converged: bool,
pub u: BlockSparseTensor<T, S>,
pub s: BlockScalars<<T as Scalar>::Real, S>,
pub vt: BlockSparseTensor<T, S>,
pub trunc_err: T::Real,
}
pub(crate) fn dmrg_2site_step_block_sparse<T, S>(
envs: &BraketEnvs<BlockSparseStorage<T>, BlockSparseLayout<S>>,
mps: &Mps<BlockSparseStorage<T>, BlockSparseLayout<S>>,
mpo: &Mpo<BlockSparseStorage<T>, BlockSparseLayout<S>>,
site: usize,
eigensolver: &LocalEigensolverParams,
trunc: &TruncSvdParams,
) -> Result<TwoSiteStepResultBlockSparse<T, S>, DmrgHeffError>
where
T: DmrgScalar,
T::Real: Scalar<Real = T::Real>,
S: Sector,
{
let v = validation::validate_inputs(envs, mps, mpo, site, eigensolver)?;
let heff = EffectiveHamiltonian2SiteBlockSparse::new(
v.left, v.w_i, v.w_ip1, v.right, v.mps_i, v.mps_ip1,
)?;
let dim = heff.dim();
if dim == 0 {
return Err(DmrgHeffError::QnMismatch {
site,
field: "psi_template",
detail: format!(
"no flux-allowed (q_l, q_p, q_p, q_r) tuple satisfies psi_flux = {:?} \
given MPS[i].axis 0 = {:?}, MPS[i].axis 1 = {:?}, \
MPS[i+1].axis 1 = {:?}, MPS[i+1].axis 2 = {:?}",
heff.psi_flux(),
v.mps_i.indices()[0].blocks(),
v.mps_i.indices()[1].blocks(),
v.mps_ip1.indices()[1].blocks(),
v.mps_ip1.indices()[2].blocks(),
),
});
}
let (eigenvalue, eigenvector, iters, converged, residual) = match eigensolver {
LocalEigensolverParams::Lanczos(p) => {
let lan = lanczos_smallest::<T, _>(&heff, dim, p)?;
(
lan.eigenvalue,
lan.eigenvector,
lan.iters,
lan.converged,
lan.residual,
)
}
#[cfg(feature = "arpack")]
LocalEigensolverParams::Arpack(p) => {
let res = arpack_smallest::<T, _>(&heff, dim, p)?;
(
res.eigenvalue,
res.eigenvector,
res.iters,
true,
res.residual,
)
}
};
let psi_4d = operator::scatter_flat_to_template(
eigenvector.data_slice(),
&heff.psi_template,
&heff.block_offsets,
&heff.block_coords,
);
let (u, s, vt, trunc_err) = trunc_svd(Host::shared().as_ref(), &psi_4d, 2, trunc)?;
Ok(TwoSiteStepResultBlockSparse {
eigenvalue,
residual,
iters,
converged,
u,
s,
vt,
trunc_err,
})
}