pub enum Expr {
Show 14 variants
Const(Number),
Var(usize),
Binary(BinOp, Box<Expr>, Box<Expr>),
Unary(UnaryOp, Box<Expr>),
Sum(Vec<Expr>),
Cse(Rc<Expr>),
Funcall {
id: usize,
args: Vec<FuncallArg>,
},
Compare(CmpOp, Box<Expr>, Box<Expr>),
And(Box<Expr>, Box<Expr>),
Or(Box<Expr>, Box<Expr>),
Not(Box<Expr>),
Cond {
cond: Box<Expr>,
then_: Box<Expr>,
else_: Box<Expr>,
},
MinList(Vec<Expr>),
MaxList(Vec<Expr>),
}Variants§
Const(Number)
Numeric constant.
Var(usize)
Variable reference (0-based index into x).
Binary(BinOp, Box<Expr>, Box<Expr>)
Binary op: args = [lhs, rhs].
Unary(UnaryOp, Box<Expr>)
Unary op.
Sum(Vec<Expr>)
n-ary sum (opcode o54 — variadic; we may emit it from o0
folding optimization, but the parser treats o0 as binary).
Cse(Rc<Expr>)
Reference to a common subexpression (.nl V segment). The
payload is a shared body; many references to the same CSE share
one Rc, so the parsed problem is a DAG. Walking through Cse
is mathematically equivalent to inlining the body at each
occurrence (every reference is an independent occurrence in the
chain rule), so eval/grad/collect_vars just recurse into the
inner Expr.
Funcall
AMPL imported (external) function call. id matches an entry in
NlProblem.imported_funcs; resolution to a live shared library
happens when the tape is built (see nl_external::ExternalResolver).
Compare(CmpOp, Box<Expr>, Box<Expr>)
Relational comparison (o22/o23/o24/o28/o29/o30).
Evaluates to 1.0 when the comparison holds, else 0.0. The
result is piecewise-constant, so it has zero derivative
everywhere (the kink at equality is ignored — standard
subgradient-free treatment, matching ASL).
And(Box<Expr>, Box<Expr>)
Logical AND (o21). 1.0 iff both operands are nonzero.
Zero derivative (piecewise constant).
Or(Box<Expr>, Box<Expr>)
Logical OR (o20). 1.0 iff either operand is nonzero.
Zero derivative (piecewise constant).
Not(Box<Expr>)
Logical NOT (o34). 1.0 iff the operand is zero.
Zero derivative (piecewise constant).
Cond
if-then-else (o35 OPIFnl). Evaluates cond; when it is
nonzero the value and all derivatives flow through then_,
otherwise through else_. The branch switch is a non-smooth
event the derivative ignores (it differentiates only the
active branch), exactly as ASL/IPOPT does for if.
MinList(Vec<Expr>)
n-ary minimum (o11 MINLIST). Value is the smallest operand.
Piecewise linear: the derivative flows through whichever operand
is currently smallest (a subgradient; ties resolve to the first
such operand), and the second derivative is identically zero —
the standard AD treatment for min/max, matching ASL/IPOPT.
MaxList(Vec<Expr>)
n-ary maximum (o12 MAXLIST). Value is the largest operand;
derivative routing mirrors Expr::MinList.