Skip to main content

Crate oximo_expr

Crate oximo_expr 

Source
Expand description

§oximo-expr

Arena-allocated expression tree for oximo.

All expressions in oximo are nodes in a single ExprArena owned by the Model through an ExprArenaCell. User code holds lightweight Expr handles, an (ExprId, &ExprArenaCell) pair. Copying an Expr copies an ID, not a subtree. Operator overloads collapse linear combinations into a single Linear node so LP/MILP construction never traverses an Add(Mul(Const, Var), ...) tree.

ExprArenaCell provides synchronized interior mutability, so expression handles can be shared by indexed-family callbacks. Large indexed builds use isolated worker-local arena forks and merge their nodes in set order before serial model registration. Ordinary scalar expression construction keeps the same arena-backed API.

ExprArenaCell::borrow() returns an ExprArenaSnapshot, a cheap immutable copy-on-write snapshot.

This crate is the fundamental layer. End users depend on oximo-core, which re-exports all types from here so a separate oximo-expr import is not needed.

§Key types

TypeDescription
ExprArenaContiguous backing store of ExprNode values
ExprArenaCellSynchronized owner used by expression handles
ExprIdNewtype u32 index into an arena
ExprNodeEnum of all node kinds (see below)
UnaryOpPublic enum of unary scalar operations
Expr<'a>Lightweight handle: id + borrow of the arena. Copy.
VarIdOpaque variable index
ParamIdOpaque parameter index
LinearTermsExtracted Vec<(VarId, f64)> + constant

§ExprNode variants

ⓘ
Const(f64)
Var(VarId)
Param(ParamId)
Add(Children) // generic n-ary add
Mul(Children) // generic n-ary mul
Unary(UnaryOp, ExprId)
Pow(ExprId, ExprId)
Div(ExprId, ExprId) // numerator / denominator
Atan2(ExprId, ExprId) // y, x order
Min(Children) / Max(Children)
Linear { coeffs: Vec<(VarId, f64)>, constant: f64 } // LP fast-path

Linear is produced automatically by operator overloads when all operands are linear. LP/MILP backends detect it and skip tree traversal entirely.

§Operator overloads

Expr implements Add, Sub, Mul, Div, Neg against other Expr values and against f64. All operations that stay linear produce a Linear node. For example:

ⓘ
// All of these produce a single Linear node, not an Add/Mul tree:
let e = 2.0 * x + 3.0 * y - 1.0;
let e = x + y;
let e = -x;
let e = x / 2.0; // constant denominator: stays linear (x*0.5)

§Nonlinear methods on Expr

ⓘ
expr.pow(exponent) // Expr ^ Expr
expr.powi(n: i32)  // integer exponent shorthand
expr.powf(n: f64)  // float exponent shorthand
expr.neg()         // explicit UnaryOp::Neg (the `-expr` operator keeps affine lowering)
expr.sin()
expr.cos()
expr.tan()
expr.exp()
expr.exp2()
expr.expm1() // alias: exp_m1()
expr.log()   // alias: ln()
expr.log1p() // alias: ln_1p()
expr.log2()
expr.log10()
expr.abs()
expr.sqrt()
expr.cbrt()
expr.asin() / expr.acos() / expr.atan()
expr.sinh() / expr.cosh() / expr.tanh()
expr.asinh() / expr.acosh() / expr.atanh()
expr.atan2(x) // self is y
expr.min(other) / expr.max(other) // flattened n-ary nodes
expr/expr

§Utilities

§Summing expressions

Expr implements std::iter::Sum, so any iterator of Expr (or &Expr) can be collapsed with the standard .sum(). The arena is taken from the first element, empty iterators panic.

ⓘ
let total: Expr = vars.iter().copied().sum();

For coefficient-weighted sums (sum_{i} c_i * e_i) use the dot helper:

ⓘ
use oximo_expr::dot;
let total = dot(&vars, &coeffs);

For sums indexed by an oximo-core Set, prefer the sum! macro (re-exported by oximo-core / oximo::prelude).

§extract_linear

ⓘ
use oximo_expr::extract_linear;
let terms: Option<LinearTerms> = extract_linear(&arena, expr_id);

Returns Some(LinearTerms) if the subtree is affine, None if it contains nonlinear nodes. Used by backends and oximo-io to validate and serialize models.

§evaluate

ⓘ
use oximo_expr::{evaluate, EvalContext};
let mut ctx = EvalContext::new();
ctx.set_var(var_id, 3.0);
let val: f64 = evaluate(&arena, expr_id, &ctx)?;

Numerically evaluates an expression subtree given variable assignments.

§simplify

ⓘ
use oximo_expr::simplify;
let simplified_id = simplify(&mut arena, expr_id);

Constant-folds and simplifies the subtree in place.

§Visitor / walk

ⓘ
use oximo_expr::{Visitor, walk};
struct MyVisitor;
impl Visitor for MyVisitor {
    fn visit(&mut self, arena: &ExprArena, id: ExprId) { /* ... */ }
}
walk(&arena, root_id, &mut MyVisitor);

Depth-first traversal for custom analysis passes.

§Usage

End users do not need to depend on this crate directly. Depend on oximo-core instead, it re-exports all types from oximo-expr.

To use this crate directly (e.g. for a custom backend):

[dependencies]
oximo-expr = "0.7.0"

§License

MIT OR Apache-2.0

Structs§

Expr
Lightweight handle to a node in an ExprArenaCell.
ExprArena
ExprArenaCell
Parallel-safe owner used by crate::Expr handles.
ExprArenaSnapshot
Immutable copy-on-write snapshot of an ExprArenaCell.
ExprArenaWriteGuard
ExprId
LinearTerms
Coefficients of a linear expression: sum(coeff * var) + constant.
ModelId
Stable identity shared by a model, its expression handles, and its results.
ModelMismatchError
An expression, indexed family, model, or result came from another model.
ParamId
QuadraticTerms
Quadratic decomposition of an expression: its Hessian, gradient-linear part, and constant.
SignedExpr
A nonlinear residual summand: the existing arena node id, taken with a leading negation when neg is set. Carrying the sign as a flag lets split_linear run without a mutable arena.
VarId

Enums§

EvalError
ExprClass
Highest-degree polynomial class an expression belongs to, ignoring constant folding. Used by backends to pick between linear, quadratic, and general nonlinear translation paths.
ExprNode
Here we use a linear fast-path: sum(coeff * var) + constant. Built by the operator overloads when all children are linear, so LP/MILP construction never walks an Add(Mul(Const, Var), ...) tree.
UnaryOp
Unary scalar functions represented by ExprNode::Unary.

Traits§

EvalContext
Source of variable and parameter values during expression evaluation.
Visitor
Pre-order visitor over an arena. Backends implement this to translate the expression tree into solver-specific representations without copying.

Functions§

classify
Classify an expression as Linear, Quadratic (polynomial degree <= 2 with at least one degree-2 term), or Nonlinear (transcendentals, non-integer powers, or polynomial degree > 2).
describe_nonlinear_term
Render the first nonlinear summand of id as a short infix string, resolving each VarId to a display name via resolve. Returns None when id is fully affine (no nonlinear residual).
dot
Dot product of expressions with scalar coefficients: sum_{i} c_i * e_i.
evaluate
Evaluate id to an f64, pulling variable / parameter values from ctx.
extract_linear
Extract the linear terms of id, if any. Used by solver backends to extract LP coefficients without walking the tree themselves.
extract_quadratic
Snapshot the quadratic structure of id, if it is a polynomial of degree <= 2. Returns the Hessian (lower triangle), the linear coefficients, and the constant (see QuadraticTerms).
render_expr
Render id as a canonical infix string, resolving each VarId to a display name via resolve. The linear part first, then any nonlinear residual summands. Signs are folded into the joins, and a value-less expression is rendered as 0.
render_linear_terms
Render a LinearTerms snapshot by:
simplify
Apply local algebraic simplifications to the subtree rooted at id, returning a (possibly fresh) ExprId that is observationally equivalent.
split_linear
Split an expression into its linear part and a nonlinear residual. The returned (LinearTerms, Vec<SignedExpr>) satisfies
walk
Walk the subtree rooted at id in pre-order.
walk_shared
Walk the distinct nodes reachable from id in pre-order, visiting each shared subexpression exactly once.

Type Aliases§

Children