EvalExpr-JIT

A high-performance mathematical expression evaluator with JIT compilation and automatic differentiation support. Builds on top of evalexpr and Cranelift.
This crate is still under development and the API is subject to change.
Features
- š JIT compilation for fast expression evaluation
- š Automatic differentiation (up to any order)
- š¢ Support for multiple variables with consistent ordering
- š§® Higher-order partial derivatives
- š Jacobian matrix computation
- š Batch evaluation of equation systems
Check out the API Reference for more details.
Installation
Install the crate from crates.io:
cargo add evalexpr-jit
or add this to your Cargo.toml:
[dependencies]
evalexpr-jit = "0.1.2"
Quick Start
Single Equation
The Equation struct provides a simple way to evaluate mathematical expressions and compute their derivatives. Variables are automatically detected from the expression and ordered alphabetically.
use evalexpr_jit::Equation;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let eq = Equation::new("2*x + y^2".to_string())?;
let result = eq.eval(&[1.0, 2.0])?;
assert_eq!(result, 6.0);
let dx = eq.derivative("x")?;
let result = dx(&[1.0, 2.0]);
assert_eq!(result, 2.0);
let dxy = eq.derive_wrt(&["x", "y"])?;
let result = dxy(&[1.0, 2.0]);
assert_eq!(result, 0.0);
Ok(())
}
System of Equations
The EquationSystem struct allows you to evaluate multiple equations simultaneously, sharing variables across equations for efficient computation. Variables are automatically collected from all equations and consistently ordered.
use evalexpr_jit::system::EquationSystem;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let system = EquationSystem::new(vec![
"x^2*y".to_string(), "x*y^2".to_string(), ])?;
let results = system.eval(&[2.0, 3.0])?;
assert_eq!(results.as_slice(), &[
12.0, 18.0 ]);
println!("Variables: {:?}", system.sorted_variables());
Ok(())
}
Advanced Usage
System Derivatives and Jacobian
use evalexpr_jit::system::EquationSystem;
use ndarray::Array2;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let system = EquationSystem::new(vec![
"x^2*y".to_string(), "x*y^2".to_string(), ])?;
let jacobian = system.eval_jacobian(&[2.0, 3.0], None)?;
assert_eq!(jacobian[0], vec![12.0, 4.0]); assert_eq!(jacobian[1], vec![9.0, 12.0]);
let jacobian_fn = system.jacobian_wrt(&["x", "y"])?;
let mut results = Array2::zeros((2, 2));
jacobian_fn.eval_into_matrix(&[2.0, 3.0], &mut results)?;
let d2 = system.derive_wrt(&["x", "y"])?;
let mut results = vec![0.0; 2];
d2.eval_into(&[2.0, 3.0], &mut results)?;
assert_eq!(results, vec![
4.0, 6.0 ]);
Ok(())
}
Batch Evaluation
use evalexpr_jit::system::EquationSystem;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let system = EquationSystem::new(vec![
"x^2*y".to_string(),
"x*y^2".to_string(),
])?;
let input_sets = vec![
vec![2.0, 3.0],
vec![1.0, 2.0],
vec![3.0, 4.0],
];
let results = system.eval_parallel(&input_sets)?;
assert_eq!(results[0].as_slice(), &[12.0, 18.0]); assert_eq!(results[1].as_slice(), &[2.0, 4.0]); assert_eq!(results[2].as_slice(), &[36.0, 48.0]);
Ok(())
}
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.