diffsol_c/
vjp_checkpoint.rs1use std::{
2 any::Any,
3 sync::{Arc, Mutex, MutexGuard},
4};
5
6use diffsol::{DefaultSolver, DenseVjpTape, DiffsolError, OdeEquationsImplicit};
7
8use crate::{
9 error::DiffsolRtError, linear_solver_type::LinearSolverType,
10 ode_solver_tag::OdeSolverMethodTag, ode_solver_type::OdeSolverType, scalar_type::Scalar,
11};
12
13pub(crate) trait VjpCheckpoint: Any + Send {
14 fn as_any(&self) -> &dyn Any;
15 fn method(&self) -> OdeSolverType;
16 fn linear_solver(&self) -> LinearSolverType;
17 fn nt(&self) -> usize;
19}
20
21impl dyn VjpCheckpoint + '_ {
22 pub(crate) fn data<M, Eqn, Tag>(&self) -> Result<&VjpCheckpointData<M, Eqn, Tag>, DiffsolError>
23 where
24 M: diffsol::Matrix<T: Scalar> + DefaultSolver + 'static,
25 Eqn: OdeEquationsImplicit<M = M, T = M::T, V = M::V, C = M::C> + 'static,
26 Tag: OdeSolverMethodTag<M, Eqn> + 'static,
27 {
28 self.as_any()
29 .downcast_ref::<VjpCheckpointData<M, Eqn, Tag>>()
30 .ok_or_else(|| {
31 DiffsolError::Other(
32 "VJP checkpoint is incompatible with this ODE solver".to_string(),
33 )
34 })
35 }
36}
37
38pub(crate) struct VjpCheckpointData<M, Eqn, Tag>
42where
43 M: diffsol::Matrix<T: Scalar> + DefaultSolver,
44 Eqn: OdeEquationsImplicit<M = M, T = M::T, V = M::V, C = M::C>,
45 Tag: OdeSolverMethodTag<M, Eqn>,
46{
47 pub(crate) tape: DenseVjpTape<M::V, Tag::State>,
48 pub(crate) params: M::V,
49 method: OdeSolverType,
50 linear_solver: LinearSolverType,
51 _eqn: std::marker::PhantomData<fn() -> Eqn>,
52}
53
54impl<M, Eqn, Tag> VjpCheckpointData<M, Eqn, Tag>
55where
56 M: diffsol::Matrix<T: Scalar> + DefaultSolver,
57 Eqn: OdeEquationsImplicit<M = M, T = M::T, V = M::V, C = M::C>,
58 Tag: OdeSolverMethodTag<M, Eqn>,
59{
60 pub(crate) fn new(
61 tape: DenseVjpTape<M::V, Tag::State>,
62 params: M::V,
63 method: OdeSolverType,
64 linear_solver: LinearSolverType,
65 ) -> Self {
66 Self {
67 tape,
68 params,
69 method,
70 linear_solver,
71 _eqn: std::marker::PhantomData,
72 }
73 }
74}
75
76impl<M, Eqn, Tag> VjpCheckpoint for VjpCheckpointData<M, Eqn, Tag>
77where
78 M: diffsol::Matrix<T: Scalar> + DefaultSolver + 'static,
79 M::V: Send,
80 Tag::State: Send,
81 Eqn: OdeEquationsImplicit<M = M, T = M::T, V = M::V, C = M::C> + 'static,
82 Tag: OdeSolverMethodTag<M, Eqn> + 'static,
83{
84 fn as_any(&self) -> &dyn Any {
85 self
86 }
87
88 fn method(&self) -> OdeSolverType {
89 self.method
90 }
91
92 fn linear_solver(&self) -> LinearSolverType {
93 self.linear_solver
94 }
95
96 fn nt(&self) -> usize {
97 self.tape.t_eval().len()
98 }
99}
100
101#[derive(Clone)]
105pub struct VjpCheckpointWrapper(Arc<Mutex<Box<dyn VjpCheckpoint>>>);
106
107impl VjpCheckpointWrapper {
108 pub(crate) fn new(checkpoint: Box<dyn VjpCheckpoint>) -> Self {
109 Self(Arc::new(Mutex::new(checkpoint)))
110 }
111
112 pub(crate) fn guard(&self) -> Result<MutexGuard<'_, Box<dyn VjpCheckpoint>>, DiffsolRtError> {
113 self.0
114 .lock()
115 .map_err(|_| DiffsolError::Other("VJP checkpoint mutex poisoned".to_string()).into())
116 }
117}