Skip to content

Repository files navigation

dace-rs

Pure Rust implementation of DACE, the Differential Algebra Computational Toolbox.

dace-rs computes with truncated multivariate Taylor polynomials ("differential algebra"): it propagates high-order expansions of arbitrary multivariate functions through arithmetic, elementary-function composition, and full polynomial map inversion, with a configurable cut-off epsilon and truncation order. It is a full rewrite of DACE 2.1 in safe Rust — no C toolchain at build time, no unsafe code in the computation kernels.

English | 简体中文

CI Crates.io Docs.rs License

Contents

Why dace-rs

The existing dace crate is a C-binding wrapper around the upstream library: it requires a C toolchain and links the C core. dace-rs is an independent pure-Rust implementation of the same algorithms and numerics, verified coefficient-for-coefficient against the C reference (see Parity Methodology). It adds Rust-native ergonomics:

  • operator traits (Add/Sub/Mul/Div/Neg + assignments) for Da × Da, Da × f64, f64 × Da;
  • values survive re-initialization (each Da keeps its context; C purges everything);
  • recoverable failures return Result, domain misuse panics with the C error code, informational degradation goes through the log crate — no sticky error state, no exit(1);
  • automatic domain splitting (ads::split, a Rust-only extension with no C counterpart) keeps polynomial enclosures rigorous over large uncertainty boxes via recursive bisection and re-expansion.

Quickstart

use dace_rs::Da;

fn main() {
    dace_rs::init(20, 2).unwrap();                 // order 20, 2 variables
    let x = Da::variable(1);
    let y = Da::variable(2);

    let f = (1.0 + x.clone() * y.clone()).sin();   // Taylor expansion of sin(1+xy)
    println!("{f}");                               // daceWrite-style listing

    // Coefficients: coefficient of x*y in sin(1+xy) is cos(1)
    assert!((f.get_coefficient(&[1, 1]) - 1.0f64.cos()).abs() < 1e-14);
}

See examples/quickstart.rs for a map-iteration example, and the crate documentation for the full API.

Platform Support

All dependencies are pure Rust; there is no build.rs and no C toolchain requirement.

Target CI
Linux x86-64 ubuntu-latest
Linux aarch64 ubuntu-24.04-arm
Windows x86-64 windows-latest
Windows aarch64 windows-11-arm

Arithmetic kernels use a fixed accumulation order and default floating-point settings (no fast-math, no FMA contraction), so results are bit-identical across the four platforms; only scalar transcendentals (f64::sin, ...) may differ by a few ulps between libm implementations.

API Map (C++ → Rust)

DACE C++ dace-rs
DA::DA(var), DA::identity Da::variable / [Da::identity]
DA::cons, DA::linear, DA::gradient Da::cons / [Da::linear] / [Da::gradient]
DA::getCoefficient, setCoefficient [Da::get_coefficient] / [Da::set_coefficient]
DA::deriv, DA::integ, DA::trim [Da::deriv] / [Da::integ] / [Da::trim]
exp, log, sin, tan, asin, ... [dace_rs::exp] etc. (free fns) and Da methods
BesselJFunction etc. [dace_rs::bessel_j] etc.
GammaFunction, PsiFunction [dace_rs::gamma] / [dace_rs::psi]
DA::norm, orderNorm, estimNorm, bound, convRadius [Da::norm] etc.
DA::compile, compiledDA::eval Da::compile / CompiledDa::eval / [CompiledDa::eval_da]
DA::plug, DA::eval [Da::plug] / [Da::eval] / [Da::eval_da]
DA::replaceVariable, scaleVariable, translateVariable [Da::replace_variable] etc.
DA::read/write (blob), operator>>/<< [Da::to_blob]/[Da::from_blob], [Display]/[FromStr]
DASimpleFormatter SimpleFormat presets and format_da
AlgebraicVector<DA>::invert DaVector::invert
— (no C counterpart; Rust-only extension) ads::split with AdsConfig/AdsResult

Not ported (upstream experimental/off by default): AlgebraicMatrix, dacecompat aliases, the MATLAB interface.

Parity Methodology

The C library has no test suite, so dace-rs is verified against the C reference directly:

  • Goldens: dev/golden/gen.sh builds the C library and runs a fixed case table (dev/golden/main.c) covering arithmetic, all elementary and special functions, calculus, norms, evaluation, and blob export at (6,3), (20,6), and (6,2) contexts with several constant-term choices. The committed tests/golden/cases.txt is replayed by tests/parity.rs in CI (no C toolchain needed); coefficients agree within rtol 1e-10 (arithmetic within 1e-13, verified bit-identical in many cases).
  • Bit-level checks during development: the monomial encoding tables, the multiply/inverse kernels, the text format, and the elementary-function layer were compared byte-for-byte against the C library on this machine.

Two upstream C bugs are deliberately not reproduced; both divergences are documented in the rustdoc of the affected functions:

  1. daceReplaceVariable indexes its exponent array with 1-based variable numbers (documented semantics say 1-based replacement; implemented is effectively from+1 → val·(to+1), a silent no-op for from == nvmax). dace-rs implements the documented semantics.
  2. dacePower with negative powers calls the multiplicative inverse on an aliased result, and the Newton iteration is not aliasing safe; C returns wrong coefficients (C's pow(A,-2) disagrees with C's own minv(sqr(A))). dace-rs returns the correct value.

Benchmarks

Criterion benchmarks for the core kernels live in benches/kernels.rs. Run the full suite with cargo bench (or cargo bench --bench kernels for this target only); filter a single benchmark with e.g. cargo bench mul/20x6.

Multiplication, the elementary functions (sin, sqrt, exp), compilation, and compiled evaluation are each measured in two configurations: order 6 with 2 variables (28 monomial slots) and order 20 with 6 variables (230,230 slots). Map inversion is measured at 6/2 and 10/4 instead: a single near-identity map inversion at order 20 with 6 variables takes ≈ 29 s per call (measured on the baseline machine below, release build), so that magnitude is recorded here and kept out of the regular bench loop.

Baseline medians (default criterion settings, Linux x86-64, AMD Ryzen Threadripper 9960X, bench/release profile):

Benchmark Config Median
mul/6x2 order 6, 2 vars 124 ns
mul/20x6 order 20, 6 vars 137 µs
sin/6x2 order 6, 2 vars 969 ns
sin/20x6 order 20, 6 vars 2.68 ms
sqrt/6x2 order 6, 2 vars 973 ns
sqrt/20x6 order 20, 6 vars 2.61 ms
exp/6x2 order 6, 2 vars 969 ns
exp/20x6 order 20, 6 vars 2.64 ms
compile/6x2 order 6, 2 vars 198 ns
compile/20x6 order 20, 6 vars 97.4 µs
eval/6x2 order 6, 2 vars 23.5 ns
eval/20x6 order 20, 6 vars 33.4 ns
invert/6x2 order 6, 2 vars 6.64 µs
invert/10x4 order 10, 4 vars 979 µs

Criterion persists results under target/criterion/; re-running cargo bench reports the change against the previous run (change: [...]), which is the intended before/after workflow for kernel changes.

The usual caveat applies (see Platform Support): arithmetic kernels use a fixed accumulation order and default floating-point settings, and these microbenchmarks do not generalize to arbitrary workloads.

License

Apache-2.0. dace-rs is a derivative work of DACE (Copyright 2016 Politecnico di Milano and contributors; Copyright 2014 Dinamica Srl). See LICENSE, NOTICE, and THIRD_PARTY_NOTICES.md.

About

Pure Rust implementation of DACE, the Differential Algebra Computational Toolbox

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages