Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Nonanti/mathcore/llms.txt

Use this file to discover all available pages before exploring further.

MathCore is designed to be fast for a symbolic math library — it uses LTO in release builds, delegates matrix operations to nalgebra, and provides optional rayon-based parallelism for batch workloads. This page covers the key knobs available to you, explains the cost of common operations, and shows patterns that avoid unnecessary work.

Release Build Profile

MathCore’s Cargo.toml ships with an optimised release profile that is automatically used when you run cargo build --release or cargo bench:
[profile.release]
lto = true
codegen-units = 1
opt-level = 3
SettingValueEffect
ltotrueLink-time optimisation — the compiler can inline and prune across crate boundaries
codegen-units1Single codegen unit — slower compile, but enables whole-crate optimisation
opt-level3Maximum LLVM optimisation level
LTO is the most impactful of these three settings for MathCore. Because the library relies heavily on small functions called in tight loops (expression tree traversal, operator dispatch), LTO allows the compiler to inline them away and produce substantially tighter machine code.
These settings apply automatically when you add MathCore as a dependency — you do not need to copy them into your own project’s profile, though overriding lto in your workspace root will take precedence.

Operation Cost Estimates

Based on the benchmark suite in benches/expression_bench.rs and the numbers documented in the README:
OperationApproximate cost
Expression parsing~1 μs
Symbolic differentiation (polynomial)~10 μs
Symbolic integration (polynomial)~10–20 μs
Numeric evaluation (pre-parsed)sub-μs
Matrix multiply (via nalgebra)depends on size and BLAS availability
Arbitrary-precision arithmeticvaries with digit count
Matrix operations delegate entirely to nalgebra, which uses BLAS when available on the platform. If your workload is matrix-heavy, linking an optimised BLAS implementation (such as OpenBLAS or MKL) will have a far larger impact than any MathCore-specific tuning.

Parse Once, Evaluate Many Times

The single most impactful optimisation available to application code is to separate parsing from evaluation. MathCore::parse() returns an Expr — the parsed expression tree — which can then be passed to the engine repeatedly without re-parsing the string.
use mathcore::{MathCore, engine::Engine};
use mathcore::prelude::*;

// Parse the expression string ONCE
let expr = MathCore::parse("sin(x)^2 + cos(x)^2").unwrap();
let engine = Engine::new();

// Evaluate it many times in a loop — no string parsing on each iteration
for i in 0..1000 {
    let x = i as f64 * 0.01;
    let mut vars = HashMap::new();
    vars.insert("x".to_string(), x);
    let result = engine.evaluate_with_vars(&expr, &vars).unwrap();
    // use result...
    let _ = result;
}
Contrast this with calling math.evaluate_with_vars(expression_str, &vars) in the loop, which re-parses the string on every iteration.
The benchmark group "evaluation" in benches/expression_bench.rs is structured this way — expressions are parsed once outside the benchmark loop and only the engine.evaluate() call is timed. Adopt the same pattern in your hot paths.

Enable the parallel Feature for Batch Operations

When you need to evaluate the same expression over a large set of inputs (e.g., building a lookup table, computing a loss surface, or processing sensor data), enable the parallel feature to unlock rayon-based parallelism:
[dependencies]
mathcore = { version = "0.3.1", features = ["parallel"] }
parallel requires std. It will not compile for no_std targets.

Prefer f64 Arithmetic for Performance-Sensitive Paths

MathCore supports arbitrary-precision rational arithmetic through num-bigint and num-rational, which is useful for exact results but comes with a significant runtime cost. For performance-sensitive code, stick with the default f64-backed Expr::Number path:
  • Use math.calculate() or math.evaluate_with_vars() for numeric work — these return f64 directly.
  • Avoid constructing PrecisionNumber or BigRational values in hot loops unless exact arithmetic is actually required.

Use MathCore::calculate() for Numeric-Only Expressions

For expressions that contain no variables (pure constant arithmetic), MathCore::calculate() is the most direct path to a result. It parses, evaluates, and returns f64 in one call, without constructing a variable map:
use mathcore::MathCore;

let math = MathCore::new();

// No variables — calculate() is ideal
let result = math.calculate("2^8 + 3^5 - 4^3").unwrap();
println!("{}", result); // 288 - 64 = 224... let the library work it out
Reserve evaluate_with_vars for expressions that actually require variable substitution.

Running the Benchmarks

The full benchmark suite lives in benches/expression_bench.rs and covers parsing, evaluation, differentiation, integration, equation solving, matrix operations, ODEs, and arbitrary-precision arithmetic. Run it with:
cargo bench
Benchmarks use Criterion and produce an HTML report in target/criterion/. The bench profile inherits from release, so LTO and opt-level = 3 apply automatically:
[profile.bench]
inherits = "release"
To run a specific benchmark group, pass a filter string:
# Run only the parsing benchmarks
cargo bench -- parsing

# Run only the differentiation benchmarks
cargo bench -- differentiation
Run cargo bench once to establish a baseline, then re-run it after making changes. Criterion will automatically compare the new results against the saved baseline and report regressions or improvements in the HTML output.

Summary of Recommendations

RecommendationImpact
Always use --release (or cargo bench) for timingHigh — debug builds are 10–100× slower
Parse once, evaluate in a loopHigh — eliminates repeated string parsing
Enable parallel for large batch evaluationsMedium — depends on input size and core count
Link an optimised BLAS for matrix-heavy codeHigh for matrices, zero for scalar math
Use f64 paths instead of arbitrary precisionHigh — BigInt ops are orders of magnitude slower
Prefer calculate() over evaluate() for constant expressionsLow — minor, but cleaner code

Build docs developers (and LLMs) love