diffsol_c/lib.rs
1//! # diffsol-c
2//!
3//! diffsol-c is a companion crate to [diffsol](https://crates.io/crates/diffsol) that
4//! provides two higher-level APIs on top of the core `diffsol` library:
5//!
6//! 1. A **dynamic dispatch** API that wraps the generic solver in runtime-dispatched types,
7//! allowing you to select the matrix backend, scalar type, linear solver, ODE solver method,
8//! and JIT backend at runtime rather than at compile time.
9//! 2. A **C FFI** API that exposes the dynamic dispatch API via `extern "C"` functions,
10//! enabling integration with C, Wasm, Matlab and other languages
11//! with a C-compatible interface.
12//!
13//! ## Dynamic Dispatch API
14//!
15//! The core of the dynamic dispatch API is the [OdeWrapper] struct. It wraps the internal
16//! solver state in an `Arc<Mutex<...>>` so that it can be shared across threads and across
17//! FFI boundaries. Unlike the core `diffsol` crate — which requires you to specify the matrix
18//! type, code generation backend, ODE equation type, linear solver, and solver method all as
19//! generic parameters — `OdeWrapper` erases these type parameters behind trait objects so you
20//! can choose them at runtime.
21//!
22//! To create an `OdeWrapper`, use [OdeWrapper::new_callbacks] if you have the equations as
23//! C callbacks (see [ode_callbacks]), or one of the feature-gated DiffSL constructors:
24//! - `new_jit` if you have DiffSL code to JIT-compile (requires the
25//! `diffsl-cranelift` or `diffsl-llvm` feature).
26//! - `new_external` if you have pre-compiled DiffSL symbols (requires the
27//! `external` feature).
28//! - `new_external_dynamic` if you have a shared library with pre-compiled
29//! DiffSL symbols (requires the `diffsl-external-dynamic` feature).
30//!
31//! Once created, the `OdeWrapper` provides methods to configure solver tolerances and options
32//! (e.g. [OdeWrapper::set_rtol], [OdeWrapper::set_atol], [OdeWrapper::set_t0],
33//! [OdeWrapper::set_h0]), query equation metadata (e.g. [OdeWrapper::get_nstates],
34//! [OdeWrapper::get_nparams], [OdeWrapper::get_nout]), and access separate option handles
35//! via [OdeWrapper::get_options] (returning an [OdeSolverOptions]) and
36//! [OdeWrapper::get_ic_options] (returning an [InitialConditionSolverOptions]).
37//!
38//! Solving is done via the following methods:
39//! - [OdeWrapper::solve] — adaptive-time integration to a final time.
40//! - [OdeWrapper::solve_dense] — integration to a specified set of time points.
41//! - [OdeWrapper::solve_fwd_sens] — forward sensitivity analysis.
42//! - [OdeWrapper::solve_continuous_adjoint] — continuous adjoint sensitivity analysis.
43//! - [OdeWrapper::solve_adjoint_fwd] / [OdeWrapper::solve_adjoint_bkwd] — discrete adjoint
44//! sensitivity analysis (forward + backward pass).
45//! - [OdeWrapper::solve_vjp_fwd] / [OdeWrapper::solve_vjp_bkwd] — reverse-mode
46//! differentiation of the solver steps (forward + backward pass).
47//!
48//! Each solve method returns a [SolutionWrapper], from which you can extract the solution
49//! values via [SolutionWrapper::get_ys], [SolutionWrapper::get_ts], and
50//! [SolutionWrapper::get_sens]. These methods return [Tensor] objects, which own the
51//! Rust-allocated data, and which the host language can read without copying. The inputs, for
52//! example `params` and `t_eval`, are [TensorView] objects, which borrow the data of the caller.
53//!
54//! The adoint solve methods involve an [AdjointCheckpointWrapper] that stores forward-pass
55//! checkpoint data required for the backward pass. The VJP solve methods use a
56//! [VjpCheckpointWrapper] in the same way.
57//!
58//! ### Runtime configuration types
59//!
60//! The dynamic dispatch API uses the following enums to configure the solver at runtime:
61//! - [OdeSolverType] — the ODE solver method ([OdeSolverType::Bdf],
62//! [OdeSolverType::Esdirk34], [OdeSolverType::TrBdf2], [OdeSolverType::Tsit45]).
63//! - [MatrixType] — the matrix backend ([MatrixType::NalgebraDense],
64//! [MatrixType::FaerDense], [MatrixType::FaerSparse]).
65//! - [ScalarType] — the floating-point type ([ScalarType::F32], [ScalarType::F64]).
66//! - [LinearSolverType] — the linear solver for implicit methods
67//! ([LinearSolverType::Default], [LinearSolverType::Lu], [LinearSolverType::Klu]).
68//! - [JitBackendType] — the JIT backend for compiling DiffSL code
69//! (`Cranelift` or `Llvm` depending on enabled features).
70//!
71//! ### Error handling
72//!
73//! All operations that can fail in the dynamic dispatch API return
74//! `Result<_, [DiffsolRtError]>`, a runtime error type wrapping the core
75//! [DiffsolError](diffsol::error::DiffsolError).
76//!
77//! ## C FFI API
78//!
79//! The C FFI API is exposed via `extern "C"` functions across several modules suffixed `_c`.
80//! These functions wrap the dynamic dispatch API using raw pointers and integer error codes
81//! so that they can be called from C or any language with C interop. The public `_c` modules
82//! are:
83//! - [ode_c] — create, configure, solve, and destroy [OdeWrapper] handles.
84//! - [ode_callbacks_c] — create an [OdeWrapper] from equations given as C callbacks.
85//! - `ode_diffsl_c` — create an [OdeWrapper] from DiffSL equations (JIT or external symbols).
86//! - [solution_wrapper_c] — extract solution data and destroy [SolutionWrapper] handles.
87//! - [vjp_checkpoint_c] — destroy [VjpCheckpointWrapper] handles.
88//! - [ode_options_c] — get/set solver convergence and performance options.
89//! - [initial_condition_options_c] — get/set initial condition solver options.
90//! - [matrix_type_c], [scalar_type_c], [linear_solver_type_c],
91//! [ode_solver_type_c], [jit_c] — query and convert enum values.
92//! - [tensor_c] — inspect and free [Tensor] data.
93//! - [error_c] — retrieve and clear thread-local error messages.
94//! - [string_c] — allocate and free Rust-owned strings from C.
95//!
96//! A build of this crate makes a dynamic library (`libdiffsol_c.so`, `.dylib` or `.dll`) and
97//! the C header `target/<profile>/include/diffsol.h`. A static library is made on request, with
98//! `cargo rustc -p diffsol-c --lib --crate-type staticlib`.
99//! The build script makes the header with cbindgen, and the header agrees with the features of
100//! the build. The README and the examples in `examples/diffsol-c-logistic/c` of the workspace
101//! show how to compile and link a C program.
102//!
103//! All C FFI functions follow a common pattern:
104//! - Return `i32` (0 = success, negative = error).
105//! - Store error details in a thread-local variable retrievable via functions in [error_c].
106//! - Use raw pointers for ownership transfer (caller allocates/frees via dedicated functions).
107//!
108//! See [c_api_utils] for the internal macros and helper functions used by the C FFI layer.
109//!
110//! ## Feature flags
111//!
112//! The crate requires at least one of the following features to be enabled:
113//! - `diffsl-cranelift` — enable the Cranelift JIT backend for DiffSL code.
114//! - `diffsl-llvm` — enable the LLVM JIT backend for DiffSL code (requires an LLVM
115//! installation; use a version-specific feature like `diffsl-llvm21`).
116//! - `external` — enable statically linked pre-compiled DiffSL symbols.
117//! - `external-dynamic` — enable dynamically loaded pre-compiled DiffSL symbols.
118//!
119//! Additional features:
120//! - `suitesparse` — enable the KLU sparse linear solver.
121//! - `sundials` — enable SUNDIALS support (via the core `diffsol` crate).
122//! - `cuda` — enable CUDA GPU support (via the core `diffsol` crate). Deprecated.
123//!
124//! ## Utility functions
125//!
126//! The [utils] module provides a few standalone functions:
127//! - [utils::version] — returns the crate version.
128//! - [utils::is_klu_available] — checks whether KLU was compiled in.
129
130// Configure dlmalloc as the global allocator for WASM targets
131// dlmalloc is a maintained alternative to the unmaintained wee_alloc
132#[cfg(target_arch = "wasm32")]
133use dlmalloc::GlobalDlmalloc;
134
135#[cfg(not(any(
136 feature = "external",
137 feature = "external-dynamic",
138 feature = "diffsl-cranelift",
139 feature = "diffsl-llvm"
140)))]
141compile_error!(
142 "diffsol-c requires one of `external`, `external-dynamic`, `diffsl-cranelift`, or `diffsl-llvm`."
143);
144
145#[cfg(target_arch = "wasm32")]
146#[global_allocator]
147static ALLOCATOR: GlobalDlmalloc = GlobalDlmalloc;
148
149#[cfg(all(feature = "diffsl-llvm15", feature = "diffsl-llvm16"))]
150compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
151#[cfg(all(feature = "diffsl-llvm15", feature = "diffsl-llvm17"))]
152compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
153#[cfg(all(feature = "diffsl-llvm15", feature = "diffsl-llvm18"))]
154compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
155#[cfg(all(feature = "diffsl-llvm15", feature = "diffsl-llvm19"))]
156compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
157#[cfg(all(feature = "diffsl-llvm15", feature = "diffsl-llvm20"))]
158compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
159#[cfg(all(feature = "diffsl-llvm15", feature = "diffsl-llvm21"))]
160compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
161#[cfg(all(feature = "diffsl-llvm16", feature = "diffsl-llvm17"))]
162compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
163#[cfg(all(feature = "diffsl-llvm16", feature = "diffsl-llvm18"))]
164compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
165#[cfg(all(feature = "diffsl-llvm16", feature = "diffsl-llvm19"))]
166compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
167#[cfg(all(feature = "diffsl-llvm16", feature = "diffsl-llvm20"))]
168compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
169#[cfg(all(feature = "diffsl-llvm16", feature = "diffsl-llvm21"))]
170compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
171#[cfg(all(feature = "diffsl-llvm17", feature = "diffsl-llvm18"))]
172compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
173#[cfg(all(feature = "diffsl-llvm17", feature = "diffsl-llvm19"))]
174compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
175#[cfg(all(feature = "diffsl-llvm17", feature = "diffsl-llvm20"))]
176compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
177#[cfg(all(feature = "diffsl-llvm17", feature = "diffsl-llvm21"))]
178compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
179#[cfg(all(feature = "diffsl-llvm18", feature = "diffsl-llvm19"))]
180compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
181#[cfg(all(feature = "diffsl-llvm18", feature = "diffsl-llvm20"))]
182compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
183#[cfg(all(feature = "diffsl-llvm18", feature = "diffsl-llvm21"))]
184compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
185#[cfg(all(feature = "diffsl-llvm19", feature = "diffsl-llvm20"))]
186compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
187#[cfg(all(feature = "diffsl-llvm19", feature = "diffsl-llvm21"))]
188compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
189#[cfg(all(feature = "diffsl-llvm20", feature = "diffsl-llvm21"))]
190compile_error!("diffsol-c cannot enable more than one `diffsl-llvm*` feature.");
191
192/// Adjoint checkpoint wrapper for storing and retrieving forward-pass checkpoint data.
193///
194/// This module provides [AdjointCheckpointWrapper], a thread-safe wrapper around the
195/// internal `AdjointCheckpoint` trait object. It is created during the forward pass of a
196/// discrete adjoint solve (via [OdeWrapper::solve_adjoint_fwd])
197/// and consumed during the backward pass (via [OdeWrapper::solve_adjoint_bkwd]).
198///
199/// The internal `AdjointCheckpoint` trait erases the concrete matrix, codegen, and solver tag
200/// types, allowing the checkpoint to be shared between the forward and backward solvers which
201/// may use different ODE solver methods (e.g. BDF forward, ESDIRK backward).
202///
203/// The `AdjointCheckpointData<M, Eqn, Tag>` struct stores the concrete [CheckpointingPath](diffsol::CheckpointingPath)
204/// plus the forward solver metadata (method, linear solver, parameters).
205pub mod adjoint_checkpoint;
206/// Macros and helper functions for the C FFI layer.
207///
208/// This module provides the internal infrastructure used by the `*_c` modules to implement
209/// `extern "C"` functions. It defines:
210/// - Return code constants: `DIFFSOL_OK` (0), `DIFFSOL_ERR` (-1), `DIFFSOL_BAD_ARG` (-2).
211/// - Conversion traits `CMapTo<Out>` / `CMapFrom<In>` for mapping between Rust and C types.
212/// - Helper functions for common patterns: `map_get`, `map_set`, `invalid_arg_at`, `error_at`,
213/// `null_err_at`, `valid_f64_ptr`.
214/// - Convenience macros: `c_invalid_arg!`, `c_error!`, `c_null_err!`, `c_getter_simple!`,
215/// `c_setter_simple!`.
216///
217/// This module is not intended for external use; it exists to share boilerplate across the
218/// `_c` modules.
219pub mod c_api_utils;
220/// Runtime error type for the dynamic dispatch API.
221///
222/// This module defines [DiffsolRtError], a newtype wrapper around
223/// [DiffsolError](diffsol::error::DiffsolError). It implements
224/// `Display`, `std::error::Error`, and `From<DiffsolError>`. All operations in the
225/// dynamic dispatch API that can fail return `Result<_, DiffsolRtError>`.
226pub mod error;
227/// C FFI error handling.
228///
229/// This module provides thread-local error storage and `extern "C"` functions for retrieving
230/// and clearing error information from C code:
231/// - `diffsol_error_code` — returns `DIFFSOL_OK`, `DIFFSOL_ERR`, or `DIFFSOL_BAD_ARG`.
232/// - `diffsol_last_error_message` — returns a pointer to the last error message.
233/// - `diffsol_last_error_file` / `diffsol_last_error_line` — return the source location of the last error.
234/// - `diffsol_clear_last_error` — clears the thread-local error state.
235#[path = "error_c.rs"]
236pub mod error_c;
237/// Options for the initial condition solver used before integration.
238///
239/// This module defines [InitialConditionSolverOptions], a handle obtained via
240/// [OdeWrapper::get_ic_options]. It provides
241/// getters and setters for configuring the nonlinear root-finding solver that computes
242/// the initial state of the ODE system:
243/// - Line search settings: [InitialConditionSolverOptions::get_use_linesearch],
244/// [InitialConditionSolverOptions::get_max_linesearch_iterations].
245/// - Newton iteration limits: [InitialConditionSolverOptions::get_max_newton_iterations],
246/// [InitialConditionSolverOptions::get_max_linear_solver_setups].
247/// - Step control: [InitialConditionSolverOptions::get_step_reduction_factor],
248/// [InitialConditionSolverOptions::get_armijo_constant].
249///
250/// Also includes [InitialConditionSolverOptionsSnapshot], a serializable snapshot used
251/// for serde round-tripping of solver configuration.
252pub mod initial_condition_options;
253/// C FFI functions for getting and setting [InitialConditionSolverOptions].
254///
255/// Provides `extern "C"` getter/setter functions for each option field exposed by
256/// `InitialConditionSolverOptions`, using `i32` for boolean values and `f64`/`usize`
257/// for numeric fields.
258#[path = "initial_condition_options_c.rs"]
259pub mod initial_condition_options_c;
260/// JIT backend type for compiling DiffSL code at runtime.
261///
262/// This module defines [JitBackendType], an enum representing the available JIT
263/// compilation backends for DiffSL code:
264/// - `Cranelift` — available when the `diffsl-cranelift` feature is enabled.
265/// - `Llvm` — available when the `diffsl-llvm` feature is enabled.
266///
267/// The function [default_enabled_jit_backend] returns the preferred backend based on which
268/// features are compiled in (LLVM is preferred over Cranelift if both are available).
269pub mod jit;
270/// C FFI functions for querying [JitBackendType] enum values.
271///
272/// Provides `extern "C"` functions to enumerate available JIT backends, check whether a
273/// backend value is valid, and get the name string of a backend.
274#[path = "jit_c.rs"]
275pub mod jit_c;
276/// Linear solver type for implicit ODE solvers.
277///
278/// This module defines [LinearSolverType], an enum specifying which linear solver to use
279/// inside implicit ODE methods (BDF, ESDIRK, TR-BDF2):
280/// - [LinearSolverType::Default] — the solver's default choice (typically LU).
281/// - [LinearSolverType::Lu] — LU decomposition (dense or sparse as appropriate).
282/// - [LinearSolverType::Klu] — KLU sparse linear solver (requires `suitesparse` feature).
283pub mod linear_solver_type;
284/// C FFI functions for querying and converting [LinearSolverType] enum values.
285///
286/// Provides `extern "C"` functions to map between `i32` values and the `LinearSolverType`
287/// enum variants, and to get the name of a linear solver type as a C string.
288#[path = "linear_solver_type_c.rs"]
289pub mod linear_solver_type_c;
290/// Matrix backend type for the ODE solver.
291///
292/// This module defines [MatrixType], an enum specifying the matrix/linear algebra backend:
293/// - [MatrixType::NalgebraDense] — dense matrix using the [nalgebra](https://nalgebra.org) crate.
294/// - [MatrixType::FaerDense] — dense matrix using the [faer](https://github.com/sarah-ek/faer-rs) crate.
295/// - [MatrixType::FaerSparse] — sparse matrix using the [faer](https://github.com/sarah-ek/faer-rs) crate.
296pub mod matrix_type;
297/// C FFI functions for querying and converting [MatrixType] enum values.
298///
299/// Provides `extern "C"` functions to map between `i32` values and the `MatrixType` enum
300/// variants, and to get the name of a matrix type as a C string.
301#[path = "matrix_type_c.rs"]
302pub mod matrix_type_c;
303/// Dynamic dispatch ODE wrapper — the primary entry point for the dynamic dispatch API.
304///
305/// This module defines [OdeWrapper], a thread-safe handle around an internal ODE solver.
306/// `OdeWrapper` erases the generic type parameters of the core `diffsol` solver (matrix type,
307/// codegen backend, linear solver, solver method) so that they can be chosen at runtime rather
308/// than compile time. The internal state is stored behind an `Arc<Mutex<...>>` for safe sharing
309/// across threads.
310///
311/// # Constructors
312/// - `new_jit` — JIT-compile DiffSL code (requires `diffsl-cranelift` or `diffsl-llvm`).
313/// - `new_external` — use statically linked pre-compiled DiffSL symbols (requires `external`).
314/// - `new_external_dynamic` — load pre-compiled DiffSL symbols from a shared library
315/// (requires `diffsl-external-dynamic`).
316///
317/// # Configuration
318/// Tolerances: [OdeWrapper::set_rtol], [OdeWrapper::set_atol], [OdeWrapper::set_t0],
319/// [OdeWrapper::set_h0], [OdeWrapper::set_integrate_out].
320/// Sensitivity tolerances: [OdeWrapper::set_sens_rtol], [OdeWrapper::set_sens_atol],
321/// [OdeWrapper::set_out_rtol], [OdeWrapper::set_out_atol],
322/// [OdeWrapper::set_param_rtol], [OdeWrapper::set_param_atol].
323/// Solver selection: [OdeWrapper::set_ode_solver], [OdeWrapper::set_linear_solver].
324///
325/// # Solving
326/// - [OdeWrapper::solve] — adaptive-time integration.
327/// - [OdeWrapper::solve_dense] — integration to specified time points.
328/// - [OdeWrapper::solve_fwd_sens] — forward sensitivity analysis.
329/// - [OdeWrapper::solve_continuous_adjoint] — continuous adjoint.
330/// - [OdeWrapper::solve_adjoint_fwd] / [OdeWrapper::solve_adjoint_bkwd] — discrete adjoint.
331/// - [OdeWrapper::solve_vjp_fwd] / [OdeWrapper::solve_vjp_bkwd] — reverse mode
332/// through the solver steps.
333///
334/// # Low-level evaluation
335/// - [OdeWrapper::y0] — compute initial state.
336/// - [OdeWrapper::rhs] — evaluate the RHS function.
337/// - [OdeWrapper::rhs_jac_mul] — evaluate the Jacobian-vector product.
338///
339/// # Serialization
340/// `OdeWrapper` implements `Serialize`/`Deserialize` for JIT-backed solvers.
341pub mod ode;
342/// C FFI functions for creating, configuring, solving, and destroying [OdeWrapper] objects.
343///
344/// Provides `extern "C"` functions for the full lifecycle of an ODE solver:
345/// - `diffsol_ode_wrapper_new_*` — constructors (feature-gated by JIT backend or external).
346/// - `diffsol_ode_wrapper_get_*` / `diffsol_ode_wrapper_set_*` — getters/setters for tolerances,
347/// time settings, solver type, and linear solver.
348/// - `diffsol_ode_wrapper_y0`, `diffsol_ode_wrapper_rhs`, `diffsol_ode_wrapper_rhs_jac_mul` —
349/// low-level RHS evaluation.
350/// - `diffsol_ode_wrapper_solve`, `diffsol_ode_wrapper_solve_dense`,
351/// `diffsol_ode_wrapper_solve_fwd_sens`, `diffsol_ode_wrapper_solve_continuous_adjoint`,
352/// `diffsol_ode_wrapper_solve_adjoint_fwd`, `diffsol_ode_wrapper_solve_adjoint_bkwd` —
353/// solve functions returning [SolutionWrapper] pointers.
354/// - `diffsol_ode_solve_vjp_fwd`, `diffsol_ode_solve_vjp_bkwd` — reverse mode
355/// through the solver steps, with a [VjpCheckpointWrapper] between the two passes.
356/// - `diffsol_ode_wrapper_free` — free an `OdeWrapper`.
357/// - Serialization: `diffsol_ode_wrapper_serialize`, `diffsol_ode_wrapper_deserialize`.
358#[path = "ode_c.rs"]
359pub mod ode_c;
360/// ODE equations defined by C callbacks.
361///
362/// [OdeCallbacks] implements every flavour of [diffsol::OdeEquations] on top of a table of C
363/// function pointers, [OdeCallbacksDesc], one for each closure accepted by
364/// [diffsol::OdeBuilder] plus a `user_data` argument. See the module documentation for the
365/// callback conventions and the ownership of `user_data`.
366pub mod ode_callbacks;
367/// C FFI functions for creating an [OdeWrapper] from equations given as C callbacks.
368///
369/// - `diffsol_ode_new_callbacks_f64` / `diffsol_ode_new_callbacks_f32` — construct an [OdeWrapper]
370/// from a [DiffsolOdeCallbacksF64](ode_callbacks::DiffsolOdeCallbacksF64) /
371/// [DiffsolOdeCallbacksF32](ode_callbacks::DiffsolOdeCallbacksF32) descriptor.
372#[path = "ode_callbacks_c.rs"]
373pub mod ode_callbacks_c;
374/// DiffSL equations: the [OdeWrapper] constructors (`new_jit`, `new_external`,
375/// `new_external_dynamic`), the solver factories, and the `SolveEqn` impls for each code
376/// generation backend. All items are `pub(crate)`, apart from the [OdeWrapper] methods.
377mod ode_diffsl;
378/// C API constructors for DiffSL equations: JIT-compiled code, and external symbols.
379#[cfg(any(
380 feature = "external",
381 feature = "diffsl-external-dynamic",
382 feature = "diffsl-cranelift",
383 feature = "diffsl-llvm",
384))]
385#[path = "ode_diffsl_c.rs"]
386pub mod ode_diffsl_c;
387/// ODE solver convergence and performance options for the dynamic dispatch API.
388///
389/// This module defines [OdeSolverOptions], a handle obtained via
390/// [OdeWrapper::get_options]. It provides getters and
391/// setters for tuning the nonlinear solver and time-stepping behaviour of the ODE integrator:
392/// - Nonlinear solver: [OdeSolverOptions::get_max_nonlinear_solver_iterations],
393/// [OdeSolverOptions::get_max_error_test_failures],
394/// [OdeSolverOptions::get_max_nonlinear_solver_failures].
395/// - Jacobian updates: [OdeSolverOptions::get_update_jacobian_after_steps],
396/// [OdeSolverOptions::get_update_rhs_jacobian_after_steps],
397/// [OdeSolverOptions::get_threshold_to_update_jacobian],
398/// [OdeSolverOptions::get_threshold_to_update_rhs_jacobian].
399/// - Step size: [OdeSolverOptions::get_min_timestep].
400/// - BDF derivative solves (forward sensitivities, VJPs):
401/// [OdeSolverOptions::get_derivative_solve_tolerance],
402/// [OdeSolverOptions::get_derivative_solve_max_iter].
403///
404/// Also includes [OdeSolverOptionsSnapshot], a serializable snapshot used for serde
405/// round-tripping of solver configuration.
406pub mod ode_options;
407/// C FFI functions for getting and setting [OdeSolverOptions].
408///
409/// Provides `extern "C"` getter/setter functions for each option field exposed by
410/// `OdeSolverOptions`, using `f64` for floating-point values and `usize` for integer fields.
411#[path = "ode_options_c.rs"]
412pub mod ode_options_c;
413mod ode_solver_tag;
414/// ODE solver method type.
415///
416/// This module defines [OdeSolverType], an enum specifying which ODE integration method to use:
417/// - [OdeSolverType::Bdf] — Backward Differentiation Formula (stiff ODEs, singular mass matrices).
418/// - [OdeSolverType::Esdirk34] — Explicit Singly Diagonally Implicit Runge-Kutta (moderately stiff).
419/// - [OdeSolverType::TrBdf2] — Trapezoidal BDF of order 2 (moderately stiff).
420/// - [OdeSolverType::Tsit45] — Tsitouras 4/5th order Explicit Runge-Kutta (non-stiff, explicit).
421///
422/// The internal `solve` methods on this enum dispatch to the appropriate diffsol solver type
423/// via tag structs defined in the private `ode_solver_tag` module.
424pub mod ode_solver_type;
425/// C FFI functions for querying and converting [OdeSolverType] enum values.
426///
427/// Provides `extern "C"` functions to map between `i32` values and the `OdeSolverType` enum
428/// variants, and to get the name of an ODE solver type as a C string.
429#[path = "ode_solver_type_c.rs"]
430pub mod ode_solver_type_c;
431/// Floating-point scalar type for diffisol.
432///
433/// This module defines [ScalarType], an enum identifying the floating-point type used
434/// by the solver:
435/// - [ScalarType::F32] — 32-bit single precision.
436/// - [ScalarType::F64] — 64-bit double precision.
437///
438/// It also defines the [Scalar] trait (combining [DiffSlScalar](diffsol::DiffSlScalar)
439/// with [ToScalarType]) and the [ToScalarType] trait for mapping Rust types (`f32`, `f64`)
440/// to their `ScalarType` variant.
441pub mod scalar_type;
442/// C FFI functions for querying and converting [ScalarType] enum values.
443///
444/// Provides `extern "C"` functions to map between `i32` values and the `ScalarType` enum
445/// variants (`F32` / `F64`), and to get the name of a scalar type as a C string.
446#[path = "scalar_type_c.rs"]
447pub mod scalar_type_c;
448/// Internal trait used by [SolutionWrapper] for type-erased solution access.
449///
450/// The `Solution` trait provides the object-safe interface that `SolutionWrapper` wraps.
451/// It is implemented for [diffsol::Solution] for all compatible vector
452/// types `V`. The trait is `pub(crate)` — the public API is exposed through `SolutionWrapper`.
453pub mod solution;
454/// Solution wrapper for the dynamic dispatch API.
455///
456/// This module defines [SolutionWrapper], a thread-safe handle around a type-erased ODE
457/// solution. Returned by all solve methods on [OdeWrapper], it
458/// provides methods to extract the solution data:
459/// - [SolutionWrapper::get_ys] — the state values at each time point (returns [Tensor]).
460/// - [SolutionWrapper::get_ts] — the time points (returns [Tensor]).
461/// - [SolutionWrapper::get_sens] — the sensitivity matrices (returns `Vec<Tensor>`).
462///
463/// `SolutionWrapper` implements `Serialize`, serializing as `{dtype, ts, ys, sensitivities}`, with
464/// the values in the scalar type of the solver (`dtype`).
465pub mod solution_wrapper;
466/// C FFI functions for extracting data from and freeing [SolutionWrapper] objects.
467///
468/// Provides `extern "C"` functions to retrieve the time points, state values, and sensitivities
469/// from a `SolutionWrapper`, and to free the wrapper when no longer needed.
470#[path = "solution_wrapper_c.rs"]
471pub mod solution_wrapper_c;
472/// Core dynamic dispatch trait and its implementation.
473///
474/// Defines the `Solve` trait, the object-safe trait that erases the generic type parameters
475/// of the core `diffsol` solver. Each combination of matrix type, codegen backend, and solver
476/// method implements this trait. The concrete `GenericSolve<M, CG>` struct provides the
477/// implementation.
478///
479/// Also provides factory functions (`solve_factory_jit`, `solve_factory_external`,
480/// `solve_factory_external_dynamic`) that create the appropriate `Box<dyn Solve>` for a given
481/// configuration. These are called by [OdeWrapper]'s constructors.
482///
483/// All items in this module are `pub(crate)`; the public API is exposed through `OdeWrapper`.
484pub mod solve;
485/// The hooks for each equation type that the solver uses.
486///
487/// Defines the `SolveEqn` trait, and implements it for DiffSL equations with each code
488/// generation backend. The hooks give serialization, the requirement checks before a solve, and
489/// the errors that the equations recorded. All items are `pub(crate)`.
490mod solve_eqn;
491/// Internal macros for generating ODE solver option accessor methods.
492///
493/// This module provides macros used by the `Solve` trait implementation
494/// to automatically generate getter/setter methods for initial condition and ODE solver options.
495/// The macros are `pub(crate)` and intended only for internal use within the `diffsol-c` crate.
496pub mod solve_macros;
497/// C FFI memory management helpers for string and byte buffer allocation.
498///
499/// Provides `extern "C"` functions for allocating and freeing Rust-owned memory from C code:
500/// - `diffsol_alloc_string` / `diffsol_free_string` — allocate/free Rust-owned C strings.
501/// - `diffsol_alloc` / `diffsol_free` — allocate/free byte buffers.
502///
503/// These are used by the other `_c` modules when returning dynamically sized data (e.g.
504/// serialized equation blobs) to C callers.
505#[path = "string_c.rs"]
506pub mod string_c;
507/// Arrays that Rust and the host language share without a copy.
508///
509/// This module defines two types, a bridge between numeric arrays in Rust and in the host
510/// language (Python, C, Wasm/JS). Both store a raw data pointer together with shape, strides
511/// (in bytes) and scalar type metadata.
512/// - [Tensor] is an output. It always owns the value that holds its data (a `Box<dyn Any>`), so
513/// the data stays valid while the `Tensor` exists. It is the return type of
514/// [SolutionWrapper::get_ys], [SolutionWrapper::get_ts], [SolutionWrapper::get_sens] and of the
515/// [OdeWrapper] methods that give values.
516/// - [TensorView] is an input, for example `params` and `t_eval` of the [OdeWrapper] solve
517/// methods. It does not own its data, and the lifetime of the view is that of the data. It is
518/// small, `Copy`, only on the stack, and has at most [tensor::MAX_NDIM] (3) axes.
519/// - [TensorViewMut] is a mutable view, the output `y` of a C callback (see [ode_callbacks]).
520/// No two of its indices give the same value.
521///
522/// [TensorView] and [TensorViewMut] have the C layout of [tensor::RawLayout] (the fields `ptr`,
523/// `dtype`, `ndim`, `shape` and `strides`), so a C callback reads their fields directly.
524///
525/// # Batches
526/// A diffsol vector or dense matrix can have more than one lane (`nbatch`). The arrays use the
527/// column-major order of diffsol, and the last axis of an array of lanes is always the lane,
528/// also when `nbatch` is 1. For a diffsol vector, the
529/// shape is `[n, nbatch]`. For a dense matrix, the shape is `[nrows, ncols, nbatch]`. If an input
530/// array has one lane, all the lanes get its values.
531///
532/// # Key methods
533/// - [Tensor::from_vec] — make an array that owns a `Vec`, in column-major order.
534/// - [Tensor::new] — make an array that owns any value that holds the data on the heap
535/// (`unsafe`).
536/// - [Tensor::view] — a [TensorView] of an array, with no copy.
537/// - [TensorView::from_slice] — view a slice, in column-major order.
538/// - [TensorView::new] — view data with strides that obey the layout rules (`unsafe`: the caller
539/// keeps the data valid while the view exists). It gives an error for other layouts, for
540/// example a row-major array.
541/// - [Tensor::column], [Tensor::columns] ([TensorView::column], [TensorView::columns]) — the
542/// columns `[:, j, k]` as slices, with no copy. Each column is contiguous, by the layout rules.
543/// - [Tensor::index] ([TensorView::index]) — a reference to one value. The [Tensor] docs give
544/// the data layout and the layout rules.
545/// - [Tensor::shape], [Tensor::strides], [Tensor::dtype], [Tensor::data_ptr] (and the same
546/// methods of [TensorView]) — the metadata. With these, a host language can show the data with
547/// no copy, for example as a NumPy array with the same shape and strides.
548pub mod tensor;
549/// C FFI functions for inspecting and freeing [Tensor] objects.
550///
551/// Provides `extern "C"` functions for querying `Tensor` metadata (dimensions, strides,
552/// data type, raw pointer) and for freeing a `Tensor` previously returned by this library. The C
553/// header uses the same name, `Tensor`.
554#[path = "tensor_c.rs"]
555pub mod tensor_c;
556/// Utility functions for querying library capabilities.
557///
558/// Provides standalone functions useful for runtime capability checks:
559/// - [version] — returns the crate version string.
560/// - [is_klu_available] — returns `true` if the `suitesparse` feature (KLU sparse linear solver) was enabled at compile time.
561pub mod utils;
562/// Internal validation of linear solver compatibility with matrix types.
563///
564/// Provides `validate_linear_solver::<M>(linear_solver)` which checks that a given
565/// [LinearSolverType] is compatible with a
566/// matrix type `M`. For example, KLU is only valid for `FaerSparseMat<f64>` when the
567/// `suitesparse` feature is enabled. Uses `LuValidator<M>` and `KluValidator<M>` traits
568/// to associate each matrix type with its valid linear solver implementations.
569pub mod valid_linear_solver;
570/// VJP checkpoint wrapper for keeping the forward pass of a reverse-mode solve.
571///
572/// This module provides [VjpCheckpointWrapper], a thread-safe wrapper around the internal
573/// `VjpCheckpoint` trait object. It is created by the forward pass of a VJP solve (via
574/// [OdeWrapper::solve_vjp_fwd]) and used by one or more backward passes (via
575/// [OdeWrapper::solve_vjp_bkwd]).
576///
577/// It holds a [DenseVjpTape](diffsol::DenseVjpTape): the solver state after each step of the
578/// forward solve. The backward pass must use the solver of the forward pass, so the checkpoint
579/// also keeps the method, the linear solver and the parameters.
580pub mod vjp_checkpoint;
581/// C FFI function for freeing [VjpCheckpointWrapper] objects, which
582/// `diffsol_ode_solve_vjp_fwd` returns.
583#[path = "vjp_checkpoint_c.rs"]
584pub mod vjp_checkpoint_c;
585
586#[cfg(test)]
587mod test_support;
588
589#[cfg(test)]
590mod ode_callbacks_requirements_test;
591
592pub use adjoint_checkpoint::AdjointCheckpointWrapper;
593pub use error::DiffsolRtError;
594pub use initial_condition_options::{
595 InitialConditionSolverOptions, InitialConditionSolverOptionsSnapshot,
596};
597pub use jit::{default_enabled_jit_backend, JitBackendType};
598pub use linear_solver_type::LinearSolverType;
599pub use matrix_type::MatrixType;
600pub use ode::OdeWrapper;
601pub use ode_callbacks::{
602 for_each_batch, CallbackMatrix, CallbackScalar, OdeCallbackError, OdeCallbacks,
603 OdeCallbacksDesc,
604};
605pub use ode_options::{OdeSolverOptions, OdeSolverOptionsSnapshot};
606pub use ode_solver_type::OdeSolverType;
607pub use scalar_type::{Scalar, ScalarType, ToScalarType};
608pub use solution_wrapper::SolutionWrapper;
609pub use tensor::{Tensor, TensorView, TensorViewMut};
610pub use utils::{is_klu_available, version};
611pub use vjp_checkpoint::VjpCheckpointWrapper;