| Crates.io | formulac |
| lib.rs | formulac |
| version | 0.5.0 |
| created_at | 2025-08-10 04:08:13.65828+00 |
| updated_at | 2025-09-21 05:49:26.332941+00 |
| description | A complex-number and extensible function supported math expression parser for Rust |
| homepage | |
| repository | https://github.com/KATOI4423/formulac.git |
| max_upload_size | |
| id | 1788480 |
| size | 200,503 |
formulac is a Rust library for parsing, evaluating, and differentiating mathematical expressions.
It supports complex numbers, user-defined functions, and higher-order derivatives.
Ideal for symbolic computation, mathematical simulations, and evaluating formulas in Rust applications.
num_complex::Complex<f64>.+, -, *, /, ^, and standard functions like sin, cos, exp, log, and more.
See src/parser.rs or API Overview for the list of available functions, constants, and operator symbols.+, -) and binary operators (+, -, *, /, ^) are represented as UnaryOperatorKind and BinaryOperatorKind.AstNode structures, enabling inspection, simplification, and compilation into executable closures.UserDefinedTable).diff operator (e.g., diff(sin(x), x)).Add to your Cargo.toml:
cargo add formulac
use num_complex::Complex;
use formulac::{compile, Variables, UserDefinedTable};
fn main() {
let mut vars = Variables::new();
vars.insert(&[("a", Complex::new(3.0, 2.0))]);
let users = UserDefinedTable::new();
let formula = "sin(z) + a * cos(z)";
let expr = compile(formula, &["z"], &vars, &users)
.expect("Failed to compile formula");
let result = expr(&[Complex::new(1.0, 2.0)]); // evaluates 'sin(1+2i) + (3+2i) * cos(1+2i)'
println!("Result = {}", result);
}
use num_complex::Complex;
use formulac::{compile, Variables, UserDefinedTable, UserDefinedFunction};
fn main() {
// Create user-defined function table
let mut users = UserDefinedTable::new();
// Define a function f(x) = x^2 + 1
let func = UserDefinedFunction::new(
"f",
|args: &[Complex<f64>]| args[0] * args[0] + Complex::new(1.0, 0.0),
1,
);
users.register("f", func);
let mut vars = Variables::new();
let expr = compile("f(3)", &[], &vars, &users).unwrap();
assert_eq!(expr(&[]), Complex::new(10.0, 0.0));
}
formulac can represent derivative expressions in the AST.
Built-in functions (e.g. sin, cos, exp, log, …) already have derivative rules,
but user-defined functions require the user to explicitly register their derivative form.
Note on Differential Order:
i8::MAX (127). Attempting to compute a derivative higher than this will result in a runtime error.You can directly write differentiation expressions using the diff operator:
use num_complex::Complex;
use formulac::{compile, Variables, UserDefinedTable};
fn main() {
let vars = Variables::new();
let users = UserDefinedTable::new();
// Differentiate sin(x) with respect to x
let formula = "diff(sin(x), x)";
let expr = compile(formula, &["x"], &vars, &users)
.expect("Failed to compile formula");
let result = expr(&[Complex::new(1.0, 0.0)]); // evaluates cos(1)
println!("Result = {}", result);
}
When computing derivatives of order 2 or higher, specify the order:
use num_complex::Complex;
use formulac::{compile, Variables, UserDefinedTable};
fn main() {
let vars = Variables::new();
let users = UserDefinedTable::new();
// Differentiate sin(x) with respect to x
let formula = "diff(sin(x), x, 2)";
let expr = compile(formula, &["x"], &vars, &users)
.expect("Failed to compile formula");
let result = expr(&[Complex::new(1.0, 0.0)]); // evaluates to -sin(1)
println!("Result = {}", result);
}
You can define your own functions and provide derivatives for them. The derivative must be registered in the same order as the function arguments.
use num_complex::Complex;
use formulac::{compile, Variables, UserDefinedTable, UserDefinedFunction};
fn main() {
let mut users = UserDefinedTable::new();
// Define f(x) = x^2
let func = UserDefinedFunction::new(
"f",
|args: &[Complex<f64>]| args[0] * args[0],
1,
).with_derivative(
// derivative f'(x) = 2x
vec![|args: &[Complex<f64>]| Complex::new(2.0, 0.0) * args[0]],
);
users.register("f", func);
let vars = Variables::new();
let expr = compile("diff(f(x), x)", &["x"], &vars, &users).unwrap();
let result = expr(&[Complex::new(3.0, 0.0)]); // evaluates f'(3) = 6
println!("Result: {}", result);
}
For functions with multiple variables, you can register partial derivatives with respect to each argument. Use the same order as the function arguments.
use num_complex::Complex;
use formulac::{compile, Variables, UserDefinedTable, UserDefinedFunction};
fn main() {
let mut users = UserDefinedTable::new();
// Define g(x, y) = x^2 * y + y^3
let func = UserDefinedFunction::new(
"g",
|args: &[Complex<f64>]| args[0]*args[0]*args[1] + args[1]*args[1]*args[1],
2,
).with_derivative(vec![
// partial derivative w.r.t x: ∂g/∂x = 2*x*y
|args: &[Complex<f64>]| Complex::new(2.0, 0.0) * args[0] * args[1],
// partial derivative w.r.t y: ∂g/∂y = x^2 + 3*y^2
|args: &[Complex<f64>]| args[0]*args[0] + Complex::new(3.0, 0.0)*args[1]*args[1],
]);
users.register("g", func);
let vars = Variables::new();
let expr_dx = compile("diff(g(x, y), x)", &["x", "y"], &vars, &users).unwrap();
let result_dx = expr_dx(&[Complex::new(2.0, 0.0), Complex::new(3.0, 0.0)]);
println!("∂g/∂x at (2, 3) = {}", result_dx); // 12
let expr_dy = compile("diff(g(x, y), y)", &["x", "y"], &vars, &users).unwrap();
let result_dy = expr_dy(&[Complex::new(2.0, 0.0), Complex::new(3.0, 0.0)]);
println!("∂g/∂y at (2, 3) = {}", result_dy); // 31
}
compile
Compiles a formula string into a Rust closure Fn(&[Complex<f64>]) -> Complex<f64> that evaluates the expression for given variable values.
Variables
A lookup table mapping variable names (strings) to Complex<f64> values, used during parsing.
UserDefinedTable
Allows registration of custom functions under user-defined names for use in expressions.
| String | Value | Description |
|---|---|---|
E |
e |
The base of natural logarithm (≈ 2.71828) |
FRAC_1_PI |
1 / π |
Reciprocal of π |
FRAC_1_SQRT_2 |
1 / √2 |
Reciprocal of square root of 2 |
FRAC_2_PI |
2 / π |
2 divided by π |
FRAC_2_SQRT_PI |
2 / √π |
2 divided by square root of π |
FRAC_PI_2 |
π / 2 |
Half of π |
FRAC_PI_3 |
π / 3 |
One-third of π |
FRAC_PI_4 |
π / 4 |
One-fourth of π |
FRAC_PI_6 |
π / 6 |
One-sixth of π |
FRAC_PI_8 |
π / 8 |
One-eighth of π |
LN_2 |
ln(2) |
Natural logarithm of 2 |
LN_10 |
ln(10) |
Natural logarithm of 10 |
LOG2_10 |
log2(10) |
Base-2 logarithm of 10 |
LOG2_E |
log2(e) |
Base-2 logarithm of e |
LOG10_2 |
log10(2) |
Base-10 logarithm of 2 |
LOG10_E |
log10(e) |
Base-10 logarithm of e |
PI |
π |
Ratio of circle circumference to diameter |
SQRT_2 |
√2 |
Square root of 2 |
TAU |
2 * π |
Full circle in radians |
| String | Function | Description |
|---|---|---|
+ |
Positive |
Identity operator |
- |
Negative |
Negation operator |
| String | Function | Description |
|---|---|---|
+ |
Add |
Addition |
- |
Sub |
Subtraction |
* |
Mul |
Multiplication |
/ |
Div |
Division |
^ |
Pow |
Power (x^y) |
| String | Function | Description |
|---|---|---|
sin |
Sin(x) |
Sine function |
cos |
Cos(x) |
Cosine function |
tan |
Tan(x) |
Tangent function |
asin |
Asin(x) |
Arc sine |
acos |
Acos(x) |
Arc cosine |
atan |
Atan(x) |
Arc tangent |
sinh |
Sinh(x) |
Hyperbolic sine |
cosh |
Cosh(x) |
Hyperbolic cosine |
tanh |
Tanh(x) |
Hyperbolic tangent |
asinh |
Asinh(x) |
Hyperbolic arcsine |
acosh |
Acosh(x) |
Hyperbolic arccosine |
atanh |
Atanh(x) |
Hyperbolic arctangent |
exp |
Exp(x) |
Exponential function e^x |
ln |
Ln(x) |
Natural logarithm |
log10 |
Log10(x) |
Base-10 logarithm |
sqrt |
Sqrt(x) |
Square root |
abs |
Abs(x) |
Absolute value |
conj |
Conj(x) |
Complex conjugate |
pow |
Pow(x, y) |
x raised to y (complex exponent) |
powi |
Powi(x, n) |
x raised to integer n |
| String | Function | Description |
|---|---|---|
diff(f, x) |
diff(f, x) |
First-order derivative of f with respect to x |
diff(f, x, n) |
diff(f, x, n) |
n-th order derivative of f with respect to x (max i8::MAX) |
The formulac crate provides benchmarks using the Criterion crate to measure both compilation and execution performance.
Note:
criterion crate as a dev-dependency and are intended for development/testing purposes only.The benchmarks are located in benches/benches.rs and cover:
Run the benchmarks with:
cargo bench
Both compile and exec times are measured. Criterion generates detailed statistics and plots in target/criterion.
Open the generated HTML report in a browser to view benchmark results and comparisons:
open target/criterion/report/index.html
Licensed under MIT OR Apache-2.0 — choose the license that best suits your project.
Contributions, feature requests, and bug reports are welcome! Please feel free to open issues or submit pull requests via the GitHub repository.