ExaModels
ExaModels.ExaModels — Module
ExaModelsAn algebraic modeling and automatic differentiation tool in Julia, specialized for SIMD-parallel evaluation of nonlinear programs on CPUs and GPUs.
Computation graph
Expressions are represented as trees of AbstractNode subtypes:
Var/DataIndexed— decision variables and data fieldsNode1/Node2— unary / binary operationsConstant{T}— compile-time scalar constant; the valueTis stored as a type parameter so it is visible to the compiler and tojuliac --trim=safewithout any runtime storage.SumNode/ProdNode— reduction over a tuple of nodes
Algebraic simplification
Operations involving Constant{T} are simplified at model-construction time: x * Constant(1) → x, x ^ Constant(2) → abs2(x), etc. (see specialization.jl). Combined Constant OP Constant expressions are folded to a new Constant via the rules in register.jl.
For more information, please visit https://github.com/exanauts/ExaModels.jl
ExaModels.AbstractAdjointNode — Type
AbstractAdjointNodeAbstract type for nodes in the first-order (gradient) forward-pass tree.
ExaModels.AbstractExaModel — Type
AbstractExaModelAn abstract type for ExaModel, which is a subtype of NLPModels.AbstractNLPModel.
ExaModels.AbstractNode — Type
AbstractNodeRoot abstract type for all nodes in the ExaModels symbolic computation graph. Every node is callable as node(i, x, θ) and returns the scalar value of the expression at the current evaluation point, where i is the iteration index, x the primal variable vector, and θ the parameter vector.
ExaModels.AbstractSecondAdjointNode — Type
AbstractSecondAdjointNodeAbstract type for nodes in the second-order (Hessian) reverse-pass tree.
ExaModels.AdjointNode1 — Type
AdjointNode1{F, T, I} <: AbstractAdjointNodeGradient-pass node for a unary operation F. Stores the primal value and the partial derivative alongside the child so a single forward sweep simultaneously computes both.
Fields
x::T: primal valueF(inner.x)y::T: derivativeF'(inner.x)inner::I: child node
ExaModels.AdjointNode2 — Type
AdjointNode2{F, T, I1, I2} <: AbstractAdjointNodeGradient-pass node for a binary operation F. Stores the primal value and both partial derivatives.
Fields
x::T: primal valueF(inner1.x, inner2.x)y1::T: partial derivative w.r.t. first argumenty2::T: partial derivative w.r.t. second argumentinner1::I1: left childinner2::I2: right child
ExaModels.AdjointNodeSource — Type
AdjointNodeSource{VT}Factory for AdjointNodeVar leaves. Indexing with i returns AdjointNodeVar(i, inner[i]), seeding the gradient-pass tree with the current primal value.
Fields
inner::VT: primal variable vector (ornothingfor a zero-valued seed)
ExaModels.AdjointNodeVar — Type
AdjointNodeVar{I, T} <: AbstractAdjointNodeLeaf node in the gradient-pass tree corresponding to a decision variable.
Fields
i::I: variable indexx::T: primal valuex[i]at the current evaluation point
ExaModels.AdjointNull — Type
AdjointNull{V} <: AbstractAdjointNodeLeaf node in the first-order adjoint tree representing a constant (zero contribution to the gradient). Carries the primal value x so that upstream nodes can read it without recomputation.
ExaModels.CompressedNLPModel — Type
CompressedNLPModelA wrapper around an AbstractNLPModel that sums duplicate (row, col) entries in the sparse Jacobian and Hessian.
Duplicates arise when multiple constraint or objective patterns contribute to the same matrix position (e.g. after augmentation via add_con!). CompressedNLPModel detects them once at construction and accumulates them on every subsequent jac_coord! / hess_coord! call, so callers receive a matrix with no repeated coordinates.
Construct via CompressedNLPModel(m).
ExaModels.CompressedNLPModel — Method
CompressedNLPModel(m)Wraps m in a CompressedNLPModel.
Queries the full Jacobian and Hessian sparsity patterns from m, identifies duplicate (row, col) pairs, builds pointer arrays for O(nnz) accumulation on subsequent jac_coord! / hess_coord! calls.
ExaModels.Compressor — Type
Compressor{I}Data structure for the sparse index
Fields:
inner::I: stores the sparse index as a tuple form
ExaModels.ConAugPair — Type
ConAugPair{C, P}Carries a constraint reference (con) alongside its Pair(idx, expr) during the probe phase of add_con!(core, g[i] += expr for ...). The replace_T method unwraps to the inner Pair, so SIMDFunction stores a plain Pair and all existing offset0 dispatches remain unchanged.
ExaModels.Constant — Type
Constant{T} <: AbstractNodeA compile-time constant node whose value T is embedded as a type parameter.
Design rationale
Because T is a type parameter rather than a struct field, the Julia compiler (and juliac --trim=safe) can propagate T concretely through every downstream Node1 / Node2 type, making the entire computation graph type-stable with no runtime storage for the constant.
Construction
Constant(2) # → Constant{2}()
Constant(3.14) # → Constant{3.14}()Evaluation
c = Constant(42)
c(i, x, θ) # → 42Algebraic simplification
specialization.jl registers identities for Constant combined with AbstractNode operands:
| expression | simplification |
|---|---|
x + Constant(0) | x |
x * Constant(1) | x |
x / Constant(1) | x |
x ^ Constant(0) | Constant(1) |
x ^ Constant(1) | x |
x ^ Constant(2) | Node1(abs2, x) |
x ^ Constant(-1) | inv(x) |
Constant(0) * x | Constant(0) |
Constant(0) / x | Constant(0) |
These rules fire at model-construction time (when the ExaCore is being built), collapsing trivial branches before the graph is finalized.
ExaModels.Constraint — Type
ConstraintA block of constraints added to an ExaCore via add_con / @add_con. Each element of the iterator corresponds to one constraint row. Row k of this block maps to global constraint index offset + k. Dual solution values can be retrieved with multipliers. An optional tag field carries user-defined metadata.
ExaModels.ConstraintAugmentation — Type
ConstraintAugmentationAn augmentation layer added to an existing Constraint via add_con! / @add_con!. Each element of the iterator yields an idx => expr pair: expr is accumulated into the constraint row identified by idx at evaluation time. Multiple ConstraintAugmentation objects can be stacked on the same base constraint to aggregate contributions from several data sources (e.g. summing arc flows into nodal balance constraints). An optional tag field carries user-defined metadata.
ExaModels.ConstraintSlot — Type
ConstraintSlot{C, I}A lightweight handle returned by getindex on a Constraint or ConstraintAugmentation. When added to an expression node via +, it produces a Pair(idx, expr) suitable for constraint augmentation.
This enables the g[idx] += expr for ... syntactic sugar:
c, _ = add_con!(c, g[i] += sin(x[i]) for i in 1:N)ExaModels.DataIndexed — Type
DataIndexed{I, J} <: AbstractNodeA node representing the lookup inner.J (or inner[J]) where inner is a DataSource or another DataIndexed. The field/index J is encoded as a type parameter so that getfield / getindex can be resolved at compile time.
Constructed implicitly via getproperty / getindex on a DataSource.
ExaModels.DataSource — Type
DataSource <: AbstractNodeSentinel node used as the root of a parameter (data) array. Indexing or accessing fields on a DataSource returns a DataIndexed node that encodes the access path as nested type parameters for zero-overhead data lookup.
ExaModels.EachScenario — Type
EachScenarioMarker type used with add_var, add_par, and add_con to indicate that the declaration is replicated for each scenario in a two-stage stochastic program.
Pass EachScenario() as the second positional argument (before dimensions) to create per-scenario (recourse) variables, parameters, or constraints. Omitting it creates first-stage (design) components shared across all scenarios.
Example
core = TwoStageExaCore(3) # 3 scenarios
c, d = add_var(core, 2) # 2 design variables (shared)
c, v = add_var(core, EachScenario(), 4) # 4 recourse variables per scenario
c, g = add_con(core, EachScenario(), v[i] for i in 1:4) # per-scenario constraintsExaModels.ExaCore — Type
ExaCore([array_eltype::Type; backend = nothing, minimize = true, name = :Generic])Creates an intermediate data object ExaCore, which later can be used for creating an ExaModel
Example
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true))
An ExaCore
Float type: ...................... Float64
Array type: ...................... Vector{Float64}
Backend: ......................... Nothing
number of objective patterns: .... 0
number of constraint patterns: ... 0
julia> c = ExaCore(Float32; concrete = Val(true))
An ExaCore
Float type: ...................... Float32
Array type: ...................... Vector{Float32}
Backend: ......................... Nothing
number of objective patterns: .... 0
number of constraint patterns: ... 0
julia> using CUDA
julia> c = ExaCore(Float32; backend = CUDABackend(), concrete = Val(true))
An ExaCore
Float type: ...................... Float32
Array type: ...................... CUDA.CuArray{Float32, 1, CUDA.DeviceMemory}
Backend: ......................... CUDA.CUDAKernels.CUDABackend
number of objective patterns: .... 0
number of constraint patterns: ... 0ExaModels.ExaModel — Method
ExaModel(core)Returns an ExaModel object, which can be solved by nonlinear optimization solvers within JuliaSmoothOptimizer ecosystem, such as NLPModelsIpopt or MadNLP.
Example
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true)); # create an ExaCore object
julia> c, x = add_var(c, 1:10); # create variables
julia> c, _ = add_obj(c, x[i]^2 for i in 1:10); # set objective function
julia> m = ExaModel(c) # create an ExaModel object
An ExaModel{Float64, Vector{Float64}, ...}
Problem name: Generic
All variables: ████████████████████ 10 All constraints: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
free: ████████████████████ 10 free: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
lower: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 lower: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
upper: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 upper: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
low/upp: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 low/upp: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
fixed: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 fixed: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
infeas: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 infeas: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
nnzh: ( 81.82% sparsity) 10 linear: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
nonlinear: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
nnzj: (------% sparsity)
lin_nnzj: (------% sparsity)
nln_nnzj: (------% sparsity)
julia> using NLPModelsIpopt
julia> result = ipopt(m; print_level=0) # solve the problem
"Execution stats: first-order stationary"
ExaModels.Expression — Type
ExpressionA subexpression created by add_expr / @add_expr. When indexed (e.g. s[i]), the expression is substituted directly into the enclosing objective or constraint — no auxiliary variables or equality constraints are introduced. Use Expression to share common sub-expressions across multiple objectives or constraints without duplicating the expression tree. An optional tag field carries user-defined metadata.
ExaModels.LegacyExaCore — Type
LegacyExaCore{T,VT,B,S}A mutable wrapper around an immutable ExaCore that provides the legacy mutating API (variable, constraint, etc.).
ExaCore() returns a LegacyExaCore by default. Use ExaCore(concrete = Val(true)) to obtain the bare immutable ExaCore required for AOT compilation.
ExaModels.Node1 — Type
Node1{F, I} <: AbstractNodeAn interior node representing a unary operation F applied to one child node.
Evaluated as F(inner(i, x, θ)).
Fields
inner::I: child node
ExaModels.Node2 — Type
Node2{F, I1, I2} <: AbstractNodeAn interior node representing a binary operation F applied to two children. Either child can be a node or a plain scalar (e.g. Real), allowing numeric coefficients to be stored directly without wrapping in Constant.
Evaluated as F(inner1(i, x, θ), inner2(i, x, θ)).
Fields
inner1::I1: left childinner2::I2: right child
ExaModels.Null — Type
Null{T} <: AbstractNodeA leaf node that always evaluates to a fixed scalar. The value is stored in a field (as opposed to Constant, which encodes the value as a type parameter). Used when the constant is not known at compile time.
Null() creates a zero-valued node; Null(v) creates a node that returns T(v) where T is the element type of the primal vector.
ExaModels.Objective — Type
ObjectiveAn objective term group added to an ExaCore via add_obj / @add_obj. All Objective objects in a core are summed at evaluation time to form the total objective value.
ExaModels.Parameter — Type
ParameterA handle to a block of model parameters added to an ExaCore via add_par / @add_par. Parameter values can be updated at any time with set_parameter! without rebuilding the model. Use indexing (e.g. θ[i]) to embed parameter values in expressions. An optional tag field carries user-defined metadata.
ExaModels.ProdNode — Type
ProdNode{I} <: AbstractNodeA node representing the product of a tuple of child nodes.
ExaModels.SIMDFunction — Type
SIMDFunction(gen::Base.Generator, o0 = 0, o1 = 0, o2 = 0)Returns a SIMDFunction using the gen.
Arguments:
gen: an iterable function specified inBase.Generatorformato0: offset for the function evaluationo1: offset for the derivative evalutiono2: offset for the second-order derivative evalution
ExaModels.SecondAdjointNode1 — Type
SecondAdjointNode1{F, T, I} <: AbstractSecondAdjointNodeHessian-pass node for a unary operation F. A single forward sweep stores the primal value, first derivative, and second derivative needed for the reverse Hessian accumulation.
Fields
x::T: primal valueF(inner.x)y::T: first derivativeF'(inner.x)h::T: second derivativeF''(inner.x)inner::I: child node
ExaModels.SecondAdjointNode2 — Type
SecondAdjointNode2{F, T, I1, I2} <: AbstractSecondAdjointNodeHessian-pass node for a binary operation F.
Fields
x::T: primal valueF(inner1.x, inner2.x)y1::T: partial derivative w.r.t. first argumenty2::T: partial derivative w.r.t. second argumenth11::T: second partial w.r.t. first argumenth12::T: mixed second partialh22::T: second partial w.r.t. second argumentinner1::I1: left childinner2::I2: right child
ExaModels.SecondAdjointNodeSource — Type
SecondAdjointNodeSource{VT}Factory for SecondAdjointNodeVar leaves. Indexing with i returns SecondAdjointNodeVar(i, inner[i]), seeding the Hessian-pass tree.
Fields
inner::VT: primal variable vector (ornothingfor a zero-valued seed)
ExaModels.SecondAdjointNodeVar — Type
SecondAdjointNodeVar{I, T} <: AbstractSecondAdjointNodeLeaf node in the Hessian-pass tree corresponding to a decision variable.
Fields
i::I: variable indexx::T: primal valuex[i]at the current evaluation point
ExaModels.SecondAdjointNull — Type
SecondAdjointNull{V} <: AbstractSecondAdjointNodeLeaf node in the second-order adjoint tree representing a constant (zero contribution to both the gradient and the Hessian). Carries the primal value x for upstream consumption.
ExaModels.SumNode — Type
SumNode{I} <: AbstractNodeA node representing the sum of a tuple of child nodes.
Constructed by exa_sum. Within @add_obj, @add_con, and @add_expr macros, sum(body for k in range) is automatically rewritten to exa_sum(k -> body, Val(range)) with the Val hoisted outside the generator closure for type stability under juliac --trim=safe.
In adjoint / second-adjoint mode the children are evaluated and folded via reduce(+, …) (or reduce(*, …) for ProdNode), reusing the existing registered + / * dispatch. No dedicated adjoint node types are needed.
ExaModels.TimedNLPModel — Type
TimedNLPModelA transparent wrapper around any AbstractNLPModel that records wall-clock timings and call counts for each NLP callback (obj, cons!, grad!, jac_coord!, hess_coord!, jac_structure!, hess_structure!).
Statistics accumulate in the stats field and can be printed with print(m). Construct via TimedNLPModel(m).
ExaModels.TimedNLPModel — Method
TimedNLPModel(m)Wraps m in a TimedNLPModel with all counters and timers reset to zero.
ExaModels.TimedNLPModel — Method
TimedNLPModel(core::ExaCore; kwargs...)Builds an ExaModel from core (forwarding kwargs...) and wraps it in a TimedNLPModel.
ExaModels.TwoStageExaCore — Type
TwoStageExaCore{T,VT,B}Type alias for an ExaCore whose tag is a [TwoStageExaModelTag]. Create one with TwoStageExaCore(nscen).
ExaModels.TwoStageExaCore — Method
TwoStageExaCore(nscen; backend = nothing, concrete = Val(false), kwargs...)Create an ExaCore for building two-stage stochastic programs with nscen scenarios.
Use add_var, add_par, and add_con with EachScenario() to declare per-scenario components, or without it for first-stage (design) components.
Example
core = TwoStageExaCore(5) # 5 scenarios
c, d = add_var(core, 3) # 3 design variables
c, v = add_var(c, EachScenario(), 2) # 2 recourse variables per scenario
model = ExaModel(c)ExaModels.TwoStageExaModel — Type
TwoStageExaModel{T,VT,E,V,P,O,C,R}Type alias for an ExaModel built from a TwoStageExaCore. Use get_nscen, get_var_scen, and get_con_scen to query the scenario structure after building the model.
ExaModels.Var — Type
Var{I} <: AbstractNodeA leaf node representing the i-th decision variable.
When evaluated as v(i, x, θ), returns x[v.i] (or x[v.i(i,x,θ)] when the index is itself a node).
ExaModels.VarSource — Type
VarSource <: AbstractNodeSentinel node used as the root of a variable array. Indexing a VarSource with an integer i returns Var(i), building the leaf node that refers to the i-th decision variable.
ExaModels.Variable — Type
VariableA handle to a block of optimization variables added to an ExaCore via add_var / @add_var. Use indexing (e.g. x[i]) to reference individual entries in objective and constraint expressions. Retrieve solution values with solution. An optional tag field carries user-defined metadata (e.g. scenario identifiers for two-stage models).
ExaModels.WrapperNLPModel — Type
WrapperNLPModelAn NLPModels.AbstractNLPModel wrapper that bridges a model whose internal array type differs from the host array type (e.g. a GPU-backed ExaModel wrapped for a CPU-only solver). All NLP callbacks are forwarded to the inner model through intermediate copy buffers.
Use WrapperNLPModel(m) or WrapperNLPModel(VT, m) rather than constructing this struct directly.
ExaModels.WrapperNLPModel — Method
WrapperNLPModel(VT, m)Returns a WrapperModel{T,VT} wrapping m <: AbstractNLPModel{T}
ExaModels.WrapperNLPModel — Method
WrapperNLPModel(m)Returns a WrapperNLPModel{Float64,Vector{Float64}} wrapping m, forwarding all NLP callbacks through Float64 CPU copy buffers.
ExaModels._needs_overload — Method
_needs_overload(f, types)Return true when ExaModels should add a method for f with the given argument types.
Plain hasmethod is too conservative for Base generics such as max(x,y) = ifelse(isless(x,y),y,x): those definitions match any AbstractNode argument, so hasmethod returns true and would prevent the ExaModels-specific overload from being added. We instead check the owner module of the matching method and only skip when ExaModels already owns it.
ExaModels.add_con! — Method
add_con!(core, c1, generator; tag = nothing)Augments the existing constraint c1 by adding extra expression terms to a subset of its rows, and returns (core, ConstraintAugmentation).
This is the primary mechanism for building constraints that aggregate contributions from multiple data sources — for example, nodal power-balance constraints that sum flows over all arcs incident to each bus. Each call to add_con! appends one new "augmentation layer"; multiple layers for the same base constraint are summed at evaluation time.
The bounds (lcon/ucon) remain those set on the original c1 and cannot be changed via add_con!.
Arguments
core: TheExaCoreto modify.c1: The baseConstraint(or a previousConstraintAugmentation) whose rows are being augmented.generator: ABase.Generatoryieldingidx => exprpairs, whereidxis an index (or tuple of indices) intoc1identifying which constraint row receives the term, andexpris the scalar expression to add to that row.
Notes
- The index
idxmust be a valid index ofc1's iterator (e.g. an integer for a 1-D constraint, or a tuple(i, j)for a multi-dimensional one). - One generator element maps to one non-zero Jacobian row; elements with the same
idxare accumulated. - The iterator of the generator becomes the SIMD work set, so performance is best when it is a contiguous collection (array, range, or product iterator).
Example
Single-index augmentation — add sin(x[i+1]) to constraint rows 4, 5, 6:
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 10);
julia> c, c1 = add_con(c, x[i] + x[i+1] for i=1:9; lcon = -1, ucon = (1+i for i=1:9));
julia> c, c2 = add_con!(c, c1, i => sin(x[i+1]) for i=4:6);
julia> c2
Constraint Augmentation
g♭ ≤ (...) + ∑_{i ∈ I} h(x,i) ≤ g♯
h(x,i) = sin(x[i.1 + 1])
where |I| = 3Multi-source augmentation (typical power-flow use case) — accumulate arc flows into bus balance constraints:
c, bus = add_con(c, pd[b.i] + gs[b.i]*vm[b.i]^2 for b in data.bus) # one row per bus
add_con!(c, bus, arc.bus => p[arc.i] for arc in data.arc) # add arc flows
add_con!(c, bus, gen.bus => -pg[gen.i] for gen in data.gen) # subtract generationExaModels.add_con! — Method
add_con!(core::ExaCore, gen::Base.Generator; tag = nothing)Two-argument form of add_con! supporting the constraint[idx] += expr sugar. The generator must use the pattern g[idx] += expr for ... in itr, where g is an existing Constraint or ConstraintAugmentation.
Equivalent to add_con!(core, g, idx => expr for ... in itr).
Example
c = ExaCore(concrete = Val(true))
c, x = add_var(c, 10)
c, g = add_con(c, 9; lcon = -1.0, ucon = 1.0)
c, _ = add_con!(c, g[i] += x[i] + x[i+1] for i = 1:9)ExaModels.add_con — Method
add_con(core::TwoStageExaCore, ::EachScenario, dims_or_gen...; start = 0, lcon = 0, ucon = 0, name = nothing)Add second-stage (per-scenario) constraints to a two-stage core. The constraint expression is replicated for each scenario. The iterator element is wrapped so that DataSource()[1] accesses the original data and DataSource()[2] gives the scenario index.
ExaModels.add_con — Method
add_con(core::TwoStageExaCore, dims_or_gen...; start = 0, lcon = 0, ucon = 0, name = nothing)Add first-stage constraints to a two-stage core. Accepts the same forms as the base add_con (generator or dims). Tagged with FirstStageTag().
ExaModels.add_con — Method
add_con(core, generator; start = 0, lcon = 0, ucon = 0, name = nothing, tag = nothing)
add_con(core, dims...; start = 0, lcon = 0, ucon = 0, name = nothing, tag = nothing)Adds constraints to core and returns (core, Constraint).
Generator form: pass a generator that yields one expression per constraint row.
Dims form: pass integer or UnitRange dimensions to create empty constraints, then use add_con! / @add_con! to accumulate terms afterwards. dims can be a single integer (add_con(c, 9)), multiple integers (add_con(c, 3, 4) for a 3×4 grid), or AbstractUnitRange values (add_con(c, 1:3, 2:5)) — matching the convention used by add_var.
Keyword Arguments
start: The initial guess of the dual solution. Can either beNumber,AbstractArray, orGenerator.lcon: The constraint lower bound. Can either beNumber,AbstractArray, orGenerator.ucon: The constraint upper bound. Can either beNumber,AbstractArray, orGenerator.name: When given asVal(:name), registers the constraint incorefor later retrieval ascore.nameormodel.name. See@add_confor the idiomatic named interface.tag: User-defined metadata attached to the constraint block.
Example
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 10);
julia> c, con = add_con(c, x[i] + x[i+1] for i=1:9; lcon = -1, ucon = (1+i for i=1:9));
julia> con
Constraint
g♭ ≤ [g(x,i)]_{i ∈ I} ≤ g♯
g(x,i) = x[i] + x[i + 1]
where |I| = 9Empty constraint with augmentation:
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 10);
julia> c, g = add_con(c, 9; lcon = -1.0, ucon = 1.0);
julia> c, _ = add_con!(c, g, i => x[i] + x[i+1] for i = 1:9);
julia> g
Constraint
g♭ ≤ [g(x,i)]_{i ∈ I} ≤ g♯
g(x,i) = 0
where |I| = 9ExaModels.add_expr — Method
add_expr(core, generator; name = nothing, tag = nothing)Creates a subexpression from a generator and returns (core, Expression). The expression is stored for direct substitution (inlining) when indexed — no auxiliary variables or constraints are added to the problem.
Keyword Arguments
name: When given asVal(:name), registers the subexpression incorefor later retrieval ascore.nameormodel.name. See@add_exprfor the idiomatic named interface.tag: User-defined metadata attached to the expression.
Example
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 10);
julia> c, s = add_expr(c, x[i]^2 for i in 1:10);
julia> s
Subexpression (reduced)
s ∈ R^{10}
s(x,i) = x[i]^2
julia> c, _ = add_obj(c, s[i] + s[i+1] for i in 1:9);Multi-dimensional example
c = ExaCore(concrete = Val(true))
c, x = add_var(c, 1:N, 1:K)
itr = [(i, k) for i in 1:N, k in 1:K]
c, s = add_expr(c, x[i, k]^2 for (i, k) in itr)
# s[i, k] substitutes x[i,k]^2 directlyExaModels.add_obj — Method
add_obj(core::ExaCore, generator; name = nothing)Adds objective terms specified by a generator to core, and returns (core, Objective). The terms are summed.
Keyword Arguments
name: When given asVal(:name), registers the objective incorefor later retrieval ascore.nameormodel.name. See@add_objfor the idiomatic named interface.
Example
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 10);
julia> c, obj = add_obj(c, x[i]^2 for i=1:10);
julia> obj
Objective
∑_{i ∈ I} f(x,i)
f(x,i) = x[i]^2
where |I| = 10ExaModels.add_obj — Method
add_obj(core::ExaCore, expr [, pars]; name = nothing)Low-level form of add_obj that accepts a pre-built AbstractNode expression expr evaluated over pars, and returns (core, Objective).
When name is given as Val(:name), the objective is also accessible as core.name or model.name.
Prefer the generator form (add_obj(core, gen)) for typical use; this form is intended for code that builds expression trees programmatically.
ExaModels.add_par — Method
add_par(core::TwoStageExaCore, value::AbstractArray; name = nothing)
add_par(core::TwoStageExaCore, n::AbstractRange; name = nothing, value = 0)
add_par(core::TwoStageExaCore, dims...; name = nothing, value = 0)Add first-stage parameters to a two-stage core, tagged with FirstStageTag().
Mirrors the add_par convention from ExaCore:
- Pass
value::AbstractArrayas the first positional argument to use its values and infer dimensions fromsize(value). - Pass dimensions (
IntegerorAbstractRange) as positional arguments and supply the uniform initial value via thevaluekeyword.
ExaModels.add_par — Method
add_par(core::TwoStageExaCore, ::EachScenario, value::AbstractVector; name = nothing)Add second-stage parameters to a two-stage core. The parameter vector value is replicated for each scenario, tagged with SecondStageTag().
ExaModels.add_par — Method
add_par(core, dims...; value = 0, name = nothing, tag = nothing)
add_par(core, value::AbstractArray; name = nothing, tag = nothing)Adds parameters to core and returns (core, Parameter).
The first form specifies dimensions with dims (each an Integer or UnitRange) and initial values via the value keyword. The second form is a convenience that uses size(value) as the dimensions.
Keyword Arguments
value: Initial parameter values. Can be aNumber,AbstractArray, orGenerator.name: When given asVal(:name), registers the parameter incorefor later retrieval ascore.nameormodel.name. See@add_parfor the idiomatic named interface.tag: User-defined metadata attached to the parameter block.
Example
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true));
julia> c, θ = add_par(c, ones(10));
julia> θ
Parameter
θ ∈ R^{10}ExaModels.add_var — Method
add_var(core::TwoStageExaCore, ::EachScenario, dims...; start = 0, lvar = -Inf, uvar = Inf, name = nothing)Add second-stage (recourse) variables to a two-stage core. Creates prod(dims) * nscen variables total — one copy of the block per scenario — tagged with SecondStageTag(). The last dimension of the resulting variable indexes the scenario.
ExaModels.add_var — Method
add_var(core::TwoStageExaCore, dims...; start = 0, lvar = -Inf, uvar = Inf, name = nothing)Add first-stage (design) variables to a two-stage core. These are shared across all scenarios and tagged with FirstStageTag().
ExaModels.add_var — Method
add_var(core, gen::Base.Generator; kwargs...)Create variables constrained to equal the expressions produced by gen. Equivalent to creating length(gen.iter) variables with equality constraints tying each to the corresponding generator expression. Returns (core, Variable).
ExaModels.add_var — Method
add_var(core, dims...; start = 0, lvar = -Inf, uvar = Inf, name = nothing, tag = nothing)Adds variables with dimensions specified by dims to core. dims can be either Integer or UnitRange. Returns (core, Variable).
Keyword Arguments
start: The initial guess of the solution. Can either beNumber,AbstractArray, orGenerator.lvar: The variable lower bound. Can either beNumber,AbstractArray, orGenerator.uvar: The variable upper bound. Can either beNumber,AbstractArray, orGenerator.name: When given asVal(:name), registers the variable incorefor later retrieval ascore.nameormodel.name. See@add_varfor the idiomatic named interface.tag: User-defined metadata attached to the variable block (e.g., scenario identifier for two-stage models).
Example
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 10; start = (sin(i) for i=1:10));
julia> x
Variable
x ∈ R^{10}
julia> c, y = add_var(c, 2:10, 3:5; lvar = zeros(9,3), uvar = ones(9,3));
julia> y
Variable
x ∈ R^{9 × 3}
ExaModels.constraint! — Method
constraint!(core, c1, generator)Deprecated. Use add_con! instead.
ExaModels.constraint — Method
constraint(core, generator; start = 0, lcon = 0, ucon = 0, kwargs...)Deprecated. Use add_con instead.
ExaModels.drpass — Method
drpass(d::D, y, adj)Performs dense gradient evaluation via the reverse pass on the computation (sub)graph formed by forward pass
Arguments:
d: first-order computation (sub)graphy: result vectoradj: adjoint propagated up to the current node
ExaModels.exa_prod — Method
exa_prod(f, itr)
exa_prod(f, ::Val{range})
exa_prod(gen::Base.Generator)Build a ProdNode representing ∏ f(k) for k ∈ itr. Inside @add_obj, @add_con, and @add_expr macros, prod(body for k in range) is automatically rewritten to exa_prod(k -> body, Val(range)) with the Val hoisted outside the generator closure.
See exa_sum for supported iterators and juliac usage notes.
ExaModels.exa_sum — Method
exa_sum(f, itr)
exa_sum(f, ::Val{range})
exa_sum(gen::Base.Generator)Build a SumNode representing ∑ f(k) for k ∈ itr. Inside @add_obj, @add_con, and @add_expr macros, sum(body for k in range) is automatically rewritten to exa_sum(k -> body, Val(range)) with the Val hoisted outside the generator closure.
Supported iterators
Tuple: type-stable via tail recursion.UnitRange{Int}: type-stable when the length is a compile-time constant.Val{range}(preferred for juliac):exa_sum(f, Val(1:nc))embeds the range in the type parameter, ensuringjuliac --trim=safecan resolveVal{N}.
juliac / AOT usage
Julia's inference cannot propagate constants like nc = 3 through a generator closure boundary. When calling add_con/add_obj programmatically (not via macro), hoist Val(range) outside the generator:
v = Val(1:nc) # outside generator
c, con = add_con(c, (exa_sum(j -> x[j], v) for i in 1:nh)) # v capturedExaModels.fulltype — Method
fulltype(node)
fulltype(io::IO, node)Print the full unabbreviated type of a node.
By default, show for ExaModels node types abbreviates inner graph-structure parameters with … to keep output readable (e.g. Node2{+,…} instead of Node2{typeof(+),Var{Int64},Var{Int64}}). fulltype bypasses this by passing the IOContext key :fulltype => true, which all show(::IO, ::Type{...}) overloads in this file respect.
Examples
node = Var(1) + Var(2) # Node2{typeof(+),Var{Int64},Var{Int64}}
show(stdout, typeof(node)) # → Node2{+,…} (default)
fulltype(node) # → Node2{+,Var{Int64},Var{Int64}}
# Equivalent manual form:
show(IOContext(stdout, :fulltype => true), typeof(node))IOContext flag
Any show call that passes :fulltype => true in its IOContext will render the complete parametric type. This is useful when you need full type output programmatically without calling fulltype directly:
io = IOContext(stderr, :fulltype => true)
show(io, typeof(node))ExaModels.fulltype_display! — Method
fulltype_display!(enabled::Bool)Globally enable or disable full-type display for ExaModels node types.
When enabled, typeof(node) and error messages (MethodErrors, stacktraces) show the complete parametric type instead of the abbreviated … form.
ExaModels.fulltype_display!(true) # enable — e.g. typeof(x) → Node2{+,Var{Int64},Var{Int64}}
ExaModels.fulltype_display!(false) # disable — e.g. typeof(x) → Node2{+,…}For one-off inspection without changing the global setting, use fulltype.
ExaModels.get_con_scen — Method
get_con_scen(model::TwoStageExaModel)Return the scenario-index vector for constraints. Entry k holds the scenario number of the k-th constraint (0 = shared).
findall(==(s), get_con_scen(model)) # constraint indices for scenario sExaModels.get_lcon — Method
get_lcon(model, con::Constraint)Return a view of the lower bounds for con.
ExaModels.get_lvar — Method
get_lvar(model, var::Variable)Return a view of the lower bounds for var.
ExaModels.get_nscen — Method
get_nscen(model::TwoStageExaModel)Return the total number of scenarios.
ExaModels.get_start — Method
get_start(model, var::Variable)
get_start(model, con::Constraint)Return a view of the initial-point values (x0 for variables, y0 for constraints).
ExaModels.get_start — Method
get_start(model::TwoStageExaModel, con::SecondStageConstraint, scen)
get_lcon(model::TwoStageExaModel, con::SecondStageConstraint, scen)
get_ucon(model::TwoStageExaModel, con::SecondStageConstraint, scen)Return a view of y0, lcon, or ucon for con restricted to scenario scen.
ExaModels.get_start — Method
get_start(model::TwoStageExaModel, var::SecondStageVariable, scen)
get_lvar(model::TwoStageExaModel, var::SecondStageVariable, scen)
get_uvar(model::TwoStageExaModel, var::SecondStageVariable, scen)Return a view of x0, lvar, or uvar for var restricted to scenario scen.
ExaModels.get_ucon — Method
get_ucon(model, con::Constraint)Return a view of the upper bounds for con.
ExaModels.get_uvar — Method
get_uvar(model, var::Variable)Return a view of the upper bounds for var.
ExaModels.get_value — Method
get_value(model, param)Return a view of all values for param in model.θ.
For second-stage parameters in a two-stage model, use get_value(model, param, scen) to extract a single scenario's slice.
ExaModels.get_value — Method
get_value(model::TwoStageExaModel, param::SecondStageParameter, scen)Return a view of the values for param in scenario scen.
The parameter must have been added with EachScenario. scen must be an integer in 1:get_nscen(model).
ExaModels.get_var_scen — Method
get_var_scen(model::TwoStageExaModel)Return the scenario-index vector for variables. Entry k holds the scenario number of the k-th variable (0 = design variable shared across all scenarios).
findall(==(0), get_var_scen(model)) # design variable indices
findall(==(s), get_var_scen(model)) # indices for scenario sExaModels.gradient! — Method
gradient!(y, f, x, adj)Performs dense gradient evalution
Arguments:
y: result vectorf: the function to be differentiated inSIMDFunctionformatx: variable vectoradj: initial adjoint
ExaModels.grpass — Method
grpass(d::D, comp, y, o1, cnt, adj)Performs dsparse gradient evaluation via the reverse pass on the computation (sub)graph formed by forward pass
Arguments:
d: first-order computation (sub)graphcomp: aCompressor, which helps map counter to sparse vector indexy: result vectoro1: index offsetcnt: counteradj: adjoint propagated up to the current node
ExaModels.hdrpass — Method
hdrpass(t1::T1, t2::T2, comp, y1, y2, o2, cnt, adj)Performs sparse hessian evaluation ((df1/dx)(df2/dx)' portion) via the reverse pass on the computation (sub)graph formed by second-order forward pass
Arguments:
t1: second-order computation (sub)graph regarding f1t2: second-order computation (sub)graph regarding f2comp: aCompressor, which helps map counter to sparse vector indexy1: result vector #1y2: result vector #2 (only used when evaluating sparsity)o2: index offsetcnt: counteradj: second adjoint propagated up to the current node
ExaModels.jrpass — Method
jrpass(d::D, comp, i, y1, y2, o1, cnt, adj)Performs sparse jacobian evaluation via the reverse pass on the computation (sub)graph formed by forward pass
Arguments:
d: first-order computation (sub)graphcomp: aCompressor, which helps map counter to sparse vector indexi: constraint index (this isi-th constraint)y1: result vector #1y2: result vector #2 (only used when evaluating sparsity)o1: index offsetcnt: counteradj: adjoint propagated up to the current node
ExaModels.multipliers — Method
multipliers(result, y)Returns the multipliers for constraints y associated with result, obtained by solving the model.
Example
julia> using ExaModels, NLPModelsIpopt
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 1:10; lvar = -1, uvar = 1);
julia> c, _ = add_obj(c, (x[i]-2)^2 for i in 1:10);
julia> c, y = add_con(c, x[i] + x[i+1] for i=1:9; lcon = -1, ucon = (1+i for i=1:9));
julia> m = ExaModel(c);
julia> result = ipopt(m; print_level=0);
julia> val = multipliers(result, y);
julia> val[1] ≈ 0.81933930
trueExaModels.multipliers_L — Method
multipliers_L(result, x)Returns the lower-bound dual variables for variable block x associated with result, obtained by solving the model.
multipliers_L[i] ≥ 0 is the dual variable for the bound constraint x[i] ≥ lvar[i]. A nonzero value indicates that the lower bound is active at the solution; the magnitude measures how much the objective would improve if that bound were relaxed.
Example
julia> using ExaModels, NLPModelsIpopt
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 1:10; lvar = -1, uvar = 1);
julia> c, _ = add_obj(c, (x[i]-2)^2 for i in 1:10);
julia> m = ExaModel(c);
julia> result = ipopt(m; print_level=0);
julia> val = multipliers_L(result, x);
julia> isapprox(val, fill(0, 10), atol=sqrt(eps(Float64)), rtol=Inf)
trueExaModels.multipliers_U — Method
multipliers_U(result, x)Returns the upper-bound dual variables for variable block x associated with result, obtained by solving the model.
multipliers_U[i] ≥ 0 is the dual variable for the bound constraint x[i] ≤ uvar[i]. A nonzero value indicates that the upper bound is active at the solution; the magnitude measures how much the objective would improve if that bound were relaxed.
Example
julia> using ExaModels, NLPModelsIpopt
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 1:10; lvar = -1, uvar = 1);
julia> c, _ = add_obj(c, (x[i]-2)^2 for i in 1:10);
julia> m = ExaModel(c);
julia> result = ipopt(m; print_level=0);
julia> val = multipliers_U(result, x);
julia> isapprox(val, fill(2, 10), atol=sqrt(eps(Float64)), rtol=Inf)
trueExaModels.objective — Method
objective(core, generator)Deprecated. Use add_obj instead.
ExaModels.parameter — Method
parameter(core, start::AbstractArray)Deprecated. Use add_par instead.
ExaModels.set_lcon! — Method
set_lcon!(model, con::Constraint, values)Update the lower bounds for con in-place.
ExaModels.set_lvar! — Method
set_lvar!(model, var::Variable, values)Update the lower bounds for var in-place.
ExaModels.set_parameter! — Method
set_parameter!(core, param, values)Updates the values of parameters in the core.
Example
julia> using ExaModels
julia> c = ExaCore(concrete = Val(true));
julia> c, p = add_par(c, ones(5));
julia> set_parameter!(c, p, ones(5))ExaModels.set_start! — Method
set_start!(model, var::Variable, values)
set_start!(model, con::Constraint, values)Update the initial-point values in-place (x0 for variables, y0 for constraints).
ExaModels.set_start! — Method
set_start!(model::TwoStageExaModel, con::SecondStageConstraint, scen, values)
set_lcon!(model::TwoStageExaModel, con::SecondStageConstraint, scen, values)
set_ucon!(model::TwoStageExaModel, con::SecondStageConstraint, scen, values)Update y0, lcon, or ucon for con in scenario scen in-place.
ExaModels.set_start! — Method
set_start!(model::TwoStageExaModel, var::SecondStageVariable, scen, values)
set_lvar!(model::TwoStageExaModel, var::SecondStageVariable, scen, values)
set_uvar!(model::TwoStageExaModel, var::SecondStageVariable, scen, values)Update x0, lvar, or uvar for var in scenario scen in-place.
ExaModels.set_ucon! — Method
set_ucon!(model, con::Constraint, values)Update the upper bounds for con in-place.
ExaModels.set_uvar! — Method
set_uvar!(model, var::Variable, values)Update the upper bounds for var in-place.
ExaModels.set_value! — Method
set_value!(model, param, values)Update all values for param in model.θ to values.
ExaModels.set_value! — Method
set_value!(model::TwoStageExaModel, param::SecondStageParameter, scen, values)Update the values for param in scenario scen to values.
The parameter must have been added with EachScenario. values must have param.length ÷ get_nscen(model) elements.
ExaModels.sgradient! — Method
sgradient!(y, f, x, adj)
Performs sparse gradient evalution
Arguments:
y: result vectorf: the function to be differentiated inSIMDFunctionformatx: variable vectoradj: initial adjoint
ExaModels.shessian! — Method
shessian!(y1, y2, f, x, adj1, adj2)Performs sparse jacobian evalution
Arguments:
y1: result vector #1y2: result vector #2 (only used when evaluating sparsity)f: the function to be differentiated inSIMDFunctionformatx: variable vectoradj1: initial first adjointadj2: initial second adjoint
ExaModels.sjacobian! — Method
sjacobian!(y1, y2, f, x, adj)Performs sparse jacobian evalution
Arguments:
y1: result vector #1y2: result vector #2 (only used when evaluating sparsity)f: the function to be differentiated inSIMDFunctionformatx: variable vectoradj: initial adjoint
ExaModels.solution — Method
solution(result, x)Returns the primal solution values for variable block x associated with result, obtained by solving the model. The returned array has the same shape as x.
Example
julia> using ExaModels, NLPModelsIpopt
julia> c = ExaCore(concrete = Val(true));
julia> c, x = add_var(c, 1:10; lvar = -1, uvar = 1);
julia> c, _ = add_obj(c, (x[i]-2)^2 for i in 1:10);
julia> m = ExaModel(c);
julia> result = ipopt(m; print_level=0);
julia> val = solution(result, x);
julia> isapprox(val, fill(1, 10), atol=sqrt(eps(Float64)), rtol=Inf)
trueExaModels.subexpr — Method
subexpr(core, generator; kwargs...)Deprecated. Use add_expr instead.
ExaModels.variable — Method
variable(core, dims...; start = 0, lvar = -Inf, uvar = Inf, kwargs...)Deprecated. Use add_var instead.
ExaModels.@add_con! — Macro
@add_con!(core, c1, generator; kwargs...)
@add_con!(core, c1[idx] += expr for ...; kwargs...)Macro interface for add_con!. Updates core in the calling scope and returns the new ConstraintAugmentation.
Two calling conventions are supported:
- Three-argument (
@add_con!(core, c1, idx => expr for ...)): the constraintc1is passed explicitly and the generator yieldsidx => exprpairs. - Two-argument (
@add_con!(core, c1[idx] += expr for ...)): the constraint and index are embedded in the generator via+=syntax. This form delegates to the function-leveladd_con!(core, gen), which extracts the target constraint automatically.
See add_con! for full semantics and usage notes.
Example
c = ExaCore(concrete = Val(true))
@add_var(c, x, 10)
@add_con(c, g, x[i] + x[i+1] for i in 1:9; lcon = -1, ucon = 1)
## Three-argument form:
aug = @add_con!(c, g, i => sin(x[i+1]) for i in 4:6)
## Two-argument form (equivalent):
aug = @add_con!(c, g[i] += sin(x[i+1]) for i in 4:6)ExaModels.@add_con — Macro
@add_con(core, [name,] generator; kwargs...)Macro interface for add_con. Updates core in the calling scope.
- Named (
@add_con(core, g, generator)): bindsgto the newConstraintin the local scope and registers it incorefor later retrieval ascore.gormodel.g. - Anonymous (
@add_con(core, generator)): equivalent toc, g = add_con(c, generator).
Accepts the same keyword arguments as add_con (lcon, ucon, start, etc.).
Example
c = ExaCore(concrete = Val(true))
@add_var(c, x, 10)
@add_con(c, g, x[i] + x[i+1] for i in 1:9; lcon = -1, ucon = 1) # g in scope; c.g also worksExaModels.@add_expr — Macro
@add_expr(core, [name,] generator; kwargs...)Macro interface for add_expr. Updates core in the calling scope.
- Named (
@add_expr(core, s, generator)): bindssto the newExpressionin the local scope and registers it incorefor later retrieval ascore.sormodel.s. - Anonymous (
@add_expr(core, generator)): equivalent toc, s = add_expr(c, generator).
Example
c = ExaCore(concrete = Val(true))
@add_var(c, x, 10)
@add_expr(c, s, x[i]^2 for i in 1:10) # s in scope; c.s also works
@add_obj(c, s[i] + s[i+1] for i in 1:9)ExaModels.@add_obj — Macro
@add_obj(core, [name,] generator; kwargs...)Macro interface for add_obj. Updates core in the calling scope.
- Named (
@add_obj(core, f, generator)): bindsfto the newObjectivein the local scope and registers it incorefor later retrieval ascore.formodel.f. - Anonymous (
@add_obj(core, generator)): equivalent toc, o = add_obj(c, generator).
Example
c = ExaCore(concrete = Val(true))
@add_var(c, x, 10)
@add_obj(c, x[i]^2 for i in 1:10)ExaModels.@add_par — Macro
@add_par(core, [name,] start; kwargs...)Macro interface for add_par. Updates core in the calling scope.
- Named (
@add_par(core, θ, start)): bindsθto the newParameterin the local scope and registers it incorefor later retrieval ascore.θormodel.θ. - Anonymous (
@add_par(core, start)): equivalent toc, p = add_par(c, start).
Example
c = ExaCore(concrete = Val(true))
@add_par(c, θ, ones(10)) # θ is now in scope; c.θ also worksExaModels.@add_var — Macro
@add_var(core, [name,] dims...; kwargs...)Macro interface for add_var. Updates core in the calling scope.
- Named (
@add_var(core, x, dims...)): bindsxto the newVariablein the local scope and registers it incorefor later retrieval ascore.xormodel.x. - Anonymous (
@add_var(core, dims...)): equivalent toc, v = add_var(c, dims...).
Accepts the same keyword arguments as add_var.
Example
c = ExaCore(concrete = Val(true))
@add_var(c, x, 10; lvar = -1, uvar = 1) # x is now in scope; c.x also works
@add_var(c, y, 1:5) # y is in scope; c.y also worksExaModels.@register_bivariate — Macro
@register_bivariate(f, df1, df2, ddf11, ddf12, ddf22)Register a bivariate function f so it can be used inside @add_obj / @add_con expressions. The macro adds four method groups:
- Node OP Node —
f(d1::AbstractNode, d2::AbstractNode) → Node2(f, d1, d2). - Node OP Real —
f(d1::AbstractNode, d2::Real) → Node2(f, d1, d2). Numeric scalars (including iterator-derived values likefactorial(j)) are stored directly inNode2without wrapping inConstant. - Real OP Node — symmetric counterpart of the above.
- Constant folding —
f(Constant{I1}(), Constant{I2}()) → Constant(f(I1, I2)). Both-constant expressions are evaluated immediately.
Arguments
f: the function to registerdf1: partial derivative w.r.t. the first argumentdf2: partial derivative w.r.t. the second argumentddf11: second partial w.r.t. the first argumentddf12: mixed second partialddf22: second partial w.r.t. the second argument
Example
julia> using ExaModels
julia> relu23(x,y) = (x > 0 || y > 0) ? (x + y)^3 : zero(x)
relu23 (generic function with 1 method)
julia> drelu231(x,y) = (x > 0 || y > 0) ? 3 * (x + y)^2 : zero(x)
drelu231 (generic function with 1 method)
julia> drelu232(x,y) = (x > 0 || y > 0) ? 3 * (x + y)^2 : zero(x)
drelu232 (generic function with 1 method)
julia> ddrelu2311(x,y) = (x > 0 || y > 0) ? 6 * (x + y) : zero(x)
ddrelu2311 (generic function with 1 method)
julia> ddrelu2312(x,y) = (x > 0 || y > 0) ? 6 * (x + y) : zero(x)
ddrelu2312 (generic function with 1 method)
julia> ddrelu2322(x,y) = (x > 0 || y > 0) ? 6 * (x + y) : zero(x)
ddrelu2322 (generic function with 1 method)
julia> @register_bivariate(relu23, drelu231, drelu232, ddrelu2311, ddrelu2312, ddrelu2322)ExaModels.@register_univariate — Macro
@register_univariate(f, df, ddf)Register a univariate function f so it can be used inside @add_obj / @add_con expressions. The macro adds three method groups:
Primal graph node —
f(n::AbstractNode) → Node1(f, n). Applied at model-construction time to build the symbolic graph.Constant folding —
f(::Constant{T}) → Constant(f(T)). When the argument is aConstant(value encoded as a type parameter), the result is evaluated immediately and stored as a newConstant, avoiding aNode1allocation entirely.Adjoint / second-adjoint nodes — forward-pass nodes for gradient and Hessian computation, using
dfandddfas the derivative functions.
Arguments
f: the function to registerdf: first derivativef'(x)ddf: second derivativef''(x)
Example
julia> using ExaModels
julia> relu3(x) = x > 0 ? x^3 : zero(x)
relu3 (generic function with 1 method)
julia> drelu3(x) = x > 0 ? 3*x^2 : zero(x)
drelu3 (generic function with 1 method)
julia> ddrelu3(x) = x > 0 ? 6*x : zero(x)
ddrelu3 (generic function with 1 method)
julia> @register_univariate(relu3, drelu3, ddrelu3)