1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//! Pure Rust implementation of DACE, the Differential Algebra Computational
//! Toolbox.
//!
//! DACE computes with truncated multivariate Taylor polynomials ("differential
//! algebra"): it propagates high-order expansions of arbitrary multivariate
//! functions through arithmetic and elementary-function composition, with a
//! configurable cut-off epsilon and truncation order. This crate is a full
//! rewrite of [DACE 2.1](https://github.com/dacelib/dace) in pure Rust.
//!
//! # Quickstart
//!
//! ```
//! dace_rs::init(20, 2).unwrap();
//! let x = dace_rs::Da::variable(1);
//! let y = dace_rs::Da::variable(2);
//! let f = (x.clone() * x.clone() + y).sin();
//! // coefficient of x^2 in sin(x^2+y) at the origin is cos(0) = 1
//! assert!((f.get_coefficient(&[2, 0]) - 1.0).abs() < 1e-14);
//! ```
//!
//! # Multithreading
//!
//! [`Da`] and [`CompiledDa`] are `Send + Sync`: sharing them across threads
//! (e.g. [Rayon], or PyO3's `allow_threads`) is supported. New threads need
//! no explicit initialization — computation settings (epsilon cutoff,
//! truncation order) and scratch buffers are lazily derived from the active
//! context on each thread's first use.
//!
//! After [`init`] is called again, every thread re-derives its settings on
//! next use, as if the thread had never been used; user-set epsilon and
//! truncation order therefore do not survive re-initialization on any
//! thread. Values keep operating on their original context, and mixing
//! values from different contexts in one operation panics (existing
//! semantics, enforced by `Da::assert_same_context`).
//!
//! [`Da::random`] uses a per-thread LCG seeded with a fixed identical value
//! on every thread: parallel draws produce the same sequence on each thread,
//! not distinct streams.
//!
//! ```
//! dace_rs::init(20, 2).unwrap();
//! let x = dace_rs::Da::variable(1);
//! let c = std::thread::spawn(move || {
//! let y = dace_rs::Da::variable(2);
//! (x * y).get_coefficient(&[1, 1])
//! })
//! .join()
//! .unwrap();
//! assert_eq!(c, 1.0);
//! ```
//!
//! [Rayon]: https://docs.rs/rayon
pub use ;
pub use ;
pub use Da;
pub use ;
pub use DaceError;
pub use CompiledDa;
pub use ;
pub use ;
/// The weighted sum `afac * a + bfac * b` (`daceWeightedSum`).
///
/// Unlike the C routine of the same name, this is aliasing-safe.
///
/// # Panics
///
/// Panics with [`DaceError`] when `a` and `b` belong to different DACE
/// contexts.
/// Tests mutate the process-global DACE context; serialize context-touching
/// tests with this lock.
pub