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.

Expr is the core algebraic data type of MathCore. Every parsed expression, every intermediate computation, and every final result is represented as an Expr tree. The variants cover the full range of constructs the library can work with — literal numbers (real and complex), symbolic variables, binary and unary operations, named function calls, and first-class representations of unevaluated derivatives and integrals. Because Expr derives Clone and Debug, trees can be inspected, cloned, and pattern-matched freely.

pub enum Expr

#[derive(Debug, Clone)]
pub enum Expr {
    Number(f64),
    Complex(Complex64),
    Symbol(String),
    Binary {
        op: BinaryOp,
        left: Box<Expr>,
        right: Box<Expr>,
    },
    Unary {
        op: UnaryOp,
        expr: Box<Expr>,
    },
    Function {
        name: String,
        args: Vec<Expr>,
    },
    Derivative {
        expr: Box<Expr>,
        var: String,
        order: u32,
    },
    Integral {
        expr: Box<Expr>,
        var: String,
        lower: Option<Box<Expr>>,
        upper: Option<Box<Expr>>,
    },
}

Variants

Number(f64)

A real floating-point constant. This is the most common leaf node produced by evaluation.
use mathcore::types::Expr;

let n = Expr::Number(3.14);

Complex(Complex64)

A complex number, using num_complex::Complex64 (Complex<f64>). Produced when operations result in a complex value.
use mathcore::types::Expr;
use num_complex::Complex64;

let c = Expr::Complex(Complex64::new(1.0, 2.0)); // 1 + 2i
The Display impl formats this as "re+imi" or "re-|im|i" depending on the sign of the imaginary part.

Symbol(String)

A named variable or constant that has not yet been bound to a value.
use mathcore::types::Expr;

let x = Expr::Symbol("x".to_string());

Binary { op: BinaryOp, left: Box<Expr>, right: Box<Expr> }

A binary operation applied to two sub-expressions. Both sub-expressions are heap-allocated to allow recursion.
use mathcore::types::{Expr, BinaryOp};

// Represents (x + 1)
let tree = Expr::Binary {
    op: BinaryOp::Add,
    left: Box::new(Expr::Symbol("x".to_string())),
    right: Box::new(Expr::Number(1.0)),
};

Unary { op: UnaryOp, expr: Box<Expr> }

A unary operation applied to a single sub-expression.
use mathcore::types::{Expr, UnaryOp};

// Represents -(x)
let neg = Expr::Unary {
    op: UnaryOp::Negate,
    expr: Box::new(Expr::Symbol("x".to_string())),
};

Function { name: String, args: Vec<Expr> }

A named function call with zero or more arguments. Built-in functions include sin, cos, tan, exp, ln, sqrt, and others recognized by the parser and engine.
use mathcore::types::Expr;

// Represents sin(x)
let f = Expr::Function {
    name: "sin".to_string(),
    args: vec![Expr::Symbol("x".to_string())],
};
println!("{}", f); // sin(x)

Derivative { expr: Box<Expr>, var: String, order: u32 }

An unevaluated derivative of expr with respect to var of the given order. Produced when the parser encounters derivative notation; the calculus subsystem evaluates this into a concrete Expr.
use mathcore::types::Expr;

// Represents d²/dx²(sin(x))
let d = Expr::Derivative {
    expr: Box::new(Expr::Function {
        name: "sin".to_string(),
        args: vec![Expr::Symbol("x".to_string())],
    }),
    var: "x".to_string(),
    order: 2,
};
println!("{}", d); // d^2/dx^2(sin(x))

Integral { expr: Box<Expr>, var: String, lower: Option<Box<Expr>>, upper: Option<Box<Expr>> }

An unevaluated integral. When lower and upper are both None the integral is indefinite; when both are Some it is definite. The Display impl renders ∫ expr dvar for indefinite and ∫[lower,upper] expr dvar for definite integrals.
use mathcore::types::Expr;

// ∫ x dx  (indefinite)
let indef = Expr::Integral {
    expr: Box::new(Expr::Symbol("x".to_string())),
    var: "x".to_string(),
    lower: None,
    upper: None,
};
println!("{}", indef); // ∫ x dx

// ∫[0,1] x dx  (definite)
let def = Expr::Integral {
    expr: Box::new(Expr::Symbol("x".to_string())),
    var: "x".to_string(),
    lower: Some(Box::new(Expr::Number(0.0))),
    upper: Some(Box::new(Expr::Number(1.0))),
};
println!("{}", def); // ∫[0,1] x dx

pub enum BinaryOp

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BinaryOp {
    Add,       // left + right
    Subtract,  // left - right
    Multiply,  // left * right
    Divide,    // left / right
    Power,     // left ^ right
    Modulo,    // left % right
}
BinaryOp is Copy, so it can be used freely in pattern-matching arms without cloning.
VariantSymbolExample expression
Add+x + 1
Subtract-x - 1
Multiply*2 * x
Divide/x / 2
Power^x ^ 3
Modulo%x % 2

pub enum UnaryOp

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum UnaryOp {
    Negate,    // -(expr)
    Factorial, // expr!
    Abs,       // |expr|
}
VariantDisplay formatExample
Negate-(expr)-(x)
Factorialexpr!5!
Abs|expr||x|

impl Expr — helper methods

zero() -> Expr

pub fn zero() -> Self
Returns Expr::Number(0.0). Convenience constructor for the additive identity.
use mathcore::types::Expr;

let z = Expr::zero();
assert!(z.is_zero());

one() -> Expr

pub fn one() -> Self
Returns Expr::Number(1.0). Convenience constructor for the multiplicative identity.
use mathcore::types::Expr;

let o = Expr::one();
assert!(o.is_one());

is_zero(&self) -> bool

pub fn is_zero(&self) -> bool
Returns true when self is Expr::Number(n) and n.abs() < f64::EPSILON.
use mathcore::types::Expr;

assert!(Expr::Number(0.0).is_zero());
assert!(!Expr::Number(1e-15).is_zero()); // above EPSILON
Only matches the Number variant. A Binary expression that would evaluate to zero is not considered zero by this method — use simplify first.

is_one(&self) -> bool

pub fn is_one(&self) -> bool
Returns true when self is Expr::Number(n) and (n - 1.0).abs() < f64::EPSILON.
use mathcore::types::Expr;

assert!(Expr::Number(1.0).is_one());
assert!(!Expr::Number(2.0).is_one());

is_constant(&self) -> bool

pub fn is_constant(&self) -> bool
Returns true when the expression contains no Symbol nodes — i.e. it can be evaluated without any variable bindings. Number and Complex leaves are always constant. Binary, Unary, and Function nodes are constant when all their sub-expressions are constant.
use mathcore::types::{Expr, BinaryOp};

assert!(Expr::Number(42.0).is_constant());

// (2 + 3) — all leaves are numbers
let sum = Expr::Binary {
    op: BinaryOp::Add,
    left:  Box::new(Expr::Number(2.0)),
    right: Box::new(Expr::Number(3.0)),
};
assert!(sum.is_constant());

// x is not constant
assert!(!Expr::Symbol("x".to_string()).is_constant());

contains_var(&self, var: &str) -> bool

pub fn contains_var(&self, var: &str) -> bool
Returns true when the expression tree contains a Symbol whose name equals var. Recursively checks Binary, Unary, Function, Derivative, and Integral nodes.
use mathcore::MathCore;

let expr = MathCore::parse("x^2 + y").unwrap();
assert!(expr.contains_var("x"));
assert!(expr.contains_var("y"));
assert!(!expr.contains_var("z"));

degree(&self, var: &str) -> u32

pub fn degree(&self, var: &str) -> u32
Returns the polynomial degree of the expression with respect to var:
  • A bare Symbol(var) has degree 1.
  • expr ^ Number(n) where expr contains var has degree n as u32.
  • For Multiply the degrees of both sides are summed.
  • For Add / Subtract the maximum of the two sides is returned.
  • All other cases (constants, unrelated symbols, functions) return 0.
use mathcore::MathCore;

let expr = MathCore::parse("x^3 + 2*x^2 + x + 1").unwrap();
assert_eq!(expr.degree("x"), 3);

let linear = MathCore::parse("3*x + 5").unwrap();
assert_eq!(linear.degree("x"), 1);

let constant = MathCore::parse("42").unwrap();
assert_eq!(constant.degree("x"), 0);

impl Display for Expr

Expr implements std::fmt::Display, so any expression can be formatted with {} or converted to a String via .to_string(). The formatting rules are:
VariantFormat
NumberRust’s default f64 format
Complexre+imi or re-|im|i
SymbolThe symbol name verbatim
Binary(left op right)
Unary-(expr), expr!, or |expr|
Functionname(arg0, arg1, …)
Derivatived^order/dvar^order(expr)
Integral∫ expr dvar or ∫[l,u] expr dvar
use mathcore::MathCore;

let expr = MathCore::parse("x^2 + 2*x + 1").unwrap();
println!("{}", expr);
// (((x ^ 2) + (2 * x)) + 1)

let d = MathCore::differentiate("sin(x)", "x").unwrap();
println!("{}", d);
// cos(x)  (after simplification by the calculus engine)

pub struct Context

Context provides a scoped environment for variable bindings and custom function definitions. It is used internally by the Engine and can be constructed directly for advanced use-cases.
#[derive(Clone)]
pub struct Context {
    variables: HashMap<String, Expr>,
    functions: HashMap<String, CustomFunction>,
}
CustomFunction is a type alias for Rc<dyn Fn(&[Expr]) -> Result<Expr, MathError>>.

Context::new

pub fn new() -> Context
Creates an empty context with no variables or custom functions.
use mathcore::types::Context;

let ctx = Context::new();
assert!(ctx.get_var("x").is_none());

Context::with_defaults

pub fn with_defaults() -> Context
Creates a context pre-populated with the three standard mathematical constants:
NameValue
pistd::f64::consts::PI (π)
estd::f64::consts::E (e)
taustd::f64::consts::TAU (2π)
use mathcore::types::{Context, Expr};

let ctx = Context::with_defaults();

if let Some(Expr::Number(pi)) = ctx.get_var("pi") {
    println!("π ≈ {:.10}", pi); // π ≈ 3.1415926536
}

set_var

pub fn set_var(&mut self, name: &str, value: Expr)
Inserts or updates a variable binding. The value can be any Expr, including symbolic expressions.
name
&str
required
The variable name. Must match the Symbol name used in expressions.
value
Expr
required
The value to bind. Typically Expr::Number(…) for a numeric constant or an Expr::Symbol / Expr::Binary for a symbolic alias.
use mathcore::types::{Context, Expr};

let mut ctx = Context::new();
ctx.set_var("r", Expr::Number(5.0));
ctx.set_var("pi", Expr::Number(std::f64::consts::PI));

// Now ctx can resolve "r" and "pi" during evaluation.

get_var

pub fn get_var(&self, name: &str) -> Option<&Expr>
Looks up a variable by name, returning a reference to its bound Expr or None if it is not defined.
name
&str
required
The variable name to look up.
Returns Some(&Expr) if the variable is bound, None otherwise.
use mathcore::types::{Context, Expr};

let mut ctx = Context::with_defaults();
ctx.set_var("n", Expr::Number(7.0));

match ctx.get_var("n") {
    Some(Expr::Number(v)) => println!("n = {}", v), // n = 7
    Some(other)           => println!("n = {}", other),
    None                  => println!("n is unbound"),
}

assert!(ctx.get_var("undefined").is_none());

Build docs developers (and LLMs) love