formulac
formulac is a Rust library for parsing, evaluating, and differentiating mathematical expressions.
It supports complex numbers, user-defined functions, higher-order derivatives, and generic numeric types.
Ideal for symbolic computation, mathematical simulations, and evaluating formulas in Rust applications.
Features
- Generic numeric backend (T: Real)
- Arbitrary-precision support via
Realtrait - Supports
f64as well as custom numeric types (e.g., arbitrary precision floats) - Designed without requiring
Copy, enabling efficient use of non-trivial numeric types
- Arbitrary-precision support via
- Complex number support
- Built on
num_complex::Complex<T>.
- Built on
- Const-generic API
- Function argument arity is encoded in the type system (
Builder<T, N>) - Eliminates runtime argument length checks and enables compile-time optimization
- Function argument arity is encoded in the type system (
- Reverse Polish Notation (RPN)
- Converts infix expressions to RPN using the Shunting-Yard algorithm
- Built-in mathematical operators & functions
- Supports
+,-,*,/,^, and standard functions likesin,cos,exp,log, and more - See
src/astnode.rsor API Overview for the list of available functions, constants, and operator symbols
- Supports
- Abstract Syntax Tree (AST)
- Expressions are parsed into
AstNodestructures, enabling inspection, simplification, and compilation into executable closures
- Expressions are parsed into
- User-defined functions
- Easily register custom functions via
Builder::with_user_functions
- Easily register custom functions via
- Symbolic differentiation
- Supports
diff(...)operator - Higher-order derivatives supported
- Supports
- Safe and dependency-light
- No
unsafe - Minimal dependencies
- No
Usage
Add to your Cargo.toml:
Basic Example
use Complex;
use Builder;
Using Custom Numeric Types
formulac is generic over numeric type T.
new
can be replaced with other types implementing Real.
Requirements for T
T must implement the crate-defined Real trait, which is used throughout the library
as the underlying numeric type for Complex<T>.
It provides:
- Basic arithmetic operations
- Conversion from primitive numeric types
- Mathematical constants and functions
This design allows integration with:
- arbitrary precision floats
- domain-specific numeric types
Note:
Tis not required to implementCopy- Values are handled via
Cloneinternally
For full details, see crate::core::Real.
Registering a Custom Function
You can register custom functions using Builder::with_user_functions.
use Complex;
use ;
Differentiation Support
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.
If no derivative is provided, diff(...) will result in an error at compile time (during compile()).
Note on Differential Order:
- Only integer-order derivatives are supported; fractional derivatives are not allowed.
- The maximum allowed order is
i8::MAX(127). Attempting to compute a derivative higher than this will result in a runtime error.
Differentiation Example
You can directly write differentiation expressions using the diff operator:
use Complex;
use ;
When computing derivatives of order 2 or higher, specify the order:
use Complex;
use ;
Example: User-defined function with derivative
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 Complex;
use ;
Example: Multi-variable functions (Partial derivatives)
For functions with multiple variables, you can register partial derivatives with respect to each argument. Use the same order as the function arguments.
use Complex;
use ;
Core Types & API Overview
-
Builder<T, const N: usize>Compiles a formula string into a Rust closureFn([Complex<T>; N]) -> Complex<T>that evaluates the expression for given variable values. -
UserFn<T>Represents a user-defined function. Accepts a fixed-size array[Complex<T>; N]as arguments.
Notes on Design
Tis not required to implementCopy- Enables support for heavy numeric types (e.g., arbitrary precision floats)
- Values are handled via
Clone- Cost depends on the underlying type
- For small types (e.g.,
f64), this is negligible - For large types, this trades performance for flexibility
- Closure require:
T: Send + Sync + 'static- This is needed because the compiled function captures owned data
- Enables safe reuse across threads
Available mathematical constants
| 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 |
Available unary operators
| String | Function | Description |
|---|---|---|
+ |
Positive |
Identity operator |
- |
Negative |
Negation operator |
Available binary operators
| String | Function | Description |
|---|---|---|
+ |
Add |
Addition |
- |
Sub |
Subtraction |
* |
Mul |
Multiplication |
/ |
Div |
Division |
^ |
Pow |
Power (x^y) |
Available Functions
| 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 |
Available differential operator
| 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) |
Benchmarking
The formulac crate provides benchmarks using the Criterion crate to measure both compilation and execution performance.
Note:
- Criterion is a dev-dependency, so benchmarks are only available in development builds.
- :warning: Some benchmarks (e.g., 1000 nested operations) may take longer to run.
- Benchmarks require the
criterioncrate as a dev-dependency and are intended for development/testing purposes only.
Benchmark Source
The benchmarks are located in benches/benches.rs and cover:
- Linear expressions (many operands like polynomials)
- Nested expressions (e.g., sin(sin(...)))
- Numeric literals
- Expressions with and without parentheses
- Many constants references (up to 100 constants)
- Differentiate expressions
- Invalid expressions (error cases)
- Practical expressions (polynomials, wave functions, exponential decay)
- Comparison of direct calls vs. parsed calls for standard functions (sin, cos, pow, etc.)
Run Benchmarks
Run the benchmarks with:
Both compile and exec times are measured. Criterion generates detailed statistics and plots in target/criterion.
Viewing Results
Open the generated HTML report in a browser to view benchmark results and comparisons:
License
Licensed under MIT OR Apache-2.0 — choose the license that best suits your project.
Contribution & Contact
Contributions, feature requests, and bug reports are welcome! Please feel free to open issues or submit pull requests via the GitHub repository.