fn expmv_chebyshev<F: SemiflowFloat, Op: SymmetricLinearOp<F>>(
op: &Op,
tau: F,
v: &[F],
out: &mut [F],
tol: F,
scratch: &mut ScratchPool<F>,
) -> Result<(), SemiflowError> {
let n = op.n();
let lambda_max = op.lambda_max_bound();
let z_total = tau * lambda_max / F::from(2.0_f64).unwrap();
let s = cheb_substep_count(z_total);
let step_tau = tau / F::from(f64::from(s)).unwrap(); let z_sub = step_tau * lambda_max / F::from(2.0_f64).unwrap();
let m = chebyshev_degree(z_sub, tol);
let em_z = (-z_sub).exp();
let scale = F::from(2.0_f64).unwrap() / lambda_max;
let two = F::from(2.0_f64).unwrap();
let mut t_prev = scratch.take_vec(n);
let mut t_curr = scratch.take_vec(n);
let mut spmv = scratch.take_vec(n);
let mut result = scratch.take_vec(n);
let mut current = scratch.take_vec(n);
current.copy_from_slice(v);
for _ in 0..s {
chebyshev_step(
op, ¤t, &mut t_prev, &mut t_curr, &mut spmv, &mut result,
n, m, scale, two, z_sub, em_z, z_total,
)?;
core::mem::swap(&mut current, &mut result);
}
out[..n].copy_from_slice(¤t);
scratch.return_vec(t_prev);
scratch.return_vec(t_curr);
scratch.return_vec(spmv);
scratch.return_vec(result);
scratch.return_vec(current);
Ok(())
}
fn expmv_lanczos<F: SemiflowFloat, Op: SymmetricLinearOp<F>>(
op: &Op,
tau: F,
v: &[F],
out: &mut [F],
m_max: usize,
scratch: &mut ScratchPool<F>,
) -> Result<(), SemiflowError> {
let n = op.n();
let lambda_max = op.lambda_max_bound();
let (s, m) = lanczos_select_s_m(lambda_max, tau);
let m = (m as usize).min(m_max);
let step_tau = tau / F::from(f64::from(s)).unwrap();
let mut current = scratch.take_vec(n);
let mut next = scratch.take_vec(n);
current.copy_from_slice(v);
for _ in 0..s {
lanczos_step_inner(op, ¤t, &mut next, step_tau, m, scratch)?;
core::mem::swap(&mut current, &mut next);
}
out[..n].copy_from_slice(¤t);
scratch.return_vec(current);
scratch.return_vec(next);
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn graph_expmv_krylov<F, Op>(
op: &Op,
tau: F,
v: &[F],
out: &mut [F],
path: KrylovPath,
tol: F,
scratch: &mut ScratchPool<F>,
) -> Result<(), SemiflowError>
where
F: SemiflowFloat,
Op: SymmetricLinearOp<F>,
{
validate_tau(tau)?;
match path {
KrylovPath::Chebyshev => {
expmv_chebyshev(op, tau, v, out, tol, scratch)?;
}
KrylovPath::Lanczos { m_max } => {
expmv_lanczos(op, tau, v, out, m_max, scratch)?;
}
KrylovPath::ImplicitEuler { n_steps } => {
implicit_euler_action(op as &dyn SymmetricLinearOp<F>, v, out,
tau, n_steps, tol, scratch)?;
}
}
Ok(())
}