Optex.Model (Optex v0.1.0)

Copy Markdown View Source

The neutral model. Immutable; builder calls return a new struct.

Constraints and the objective accept either a ready-made Optex.Aff or a terms list of {reference, coefficient} tuples, where a reference is a %Optex.Var{} or the name the variable was created with. The list form keeps programmatic model building pipeable:

m
|> Optex.Model.add_constraint([{:x, 1.0}, {{:y, 1}, 2.0}], :le, 4.0)
|> Optex.Model.set_objective([{:x, 1.0}], :max)

Name resolution is last-wins when the same name is registered twice (matching how solution values are keyed); variables created without a name can only be referenced by their %Optex.Var{} struct.

Summary

Functions

Define a variable equal to the absolute value of an affine expression and return {var, model}. Solved natively by capable backends (Gurobi, CPLEX); backends without abs support reject the model at solve time.

Append the second-order cone head >= sqrt(sum member^2) and return the model. head and each member are variable references (%Optex.Var{} or registered names); the head must carry a nonnegative lower bound (raise otherwise: the bound is part of the cone's meaning and is never set silently). Solved natively by capable backends (Gurobi, CPLEX, COPT); backends without cone support reject the model at solve time. Options: :name.

Append the constraint aff SENSE rhs (sense :le, :ge, or :eq) and return the model.

Append the indicator constraint bin = active -> aff SENSE rhs and return the model. Solved natively by capable backends (Gurobi, CPLEX); backends without indicator support reject the model at solve time.

Define a variable equal to the minimum or maximum (op) of the given arguments and return {var, model}. Solved natively by capable backends (Gurobi only); backends without min/max support reject the model at solve time.

Append the cone constraint rhs >= sqrt(sum member_aff^2) (the DSL's constraint norm(exprs...) <= rhs) and return the model. Non-bare member expressions get aux variables named {name, {:arg, i}} pinned by {name, {:def, i}} rows. When rhs is not already a bare variable with a nonnegative lower bound, a head aux named {name, :head} with lb 0.0 is pinned to it by a {name, :head_def} row; this is exact, since the cone forces its head nonnegative anyway.

Define a variable as a piecewise-linear function of an affine expression and return {var, model}. Solved natively by capable backends (Gurobi, CPLEX); backends without pwl support reject the model at solve time.

Append the rotated second-order cone 2 * head1 * head2 >= sum member^2 and return the model. Both heads must carry nonnegative lower bounds (raise otherwise). Same reference rules and backend support as add_cone/4. Options: :name.

Append a special ordered set and return the model. type is :sos1 (at most one member nonzero) or :sos2 (at most two nonzero, adjacent in weight order). members is a list of {variable_or_name, weight} pairs: at least two, distinct variables, distinct numeric weights (weights define the set's order, which is what SOS2 adjacency means). Solved natively by capable backends (Gurobi, CPLEX, COPT); backends without SOS support reject the model at solve time. Options: :name.

Register a variable and return {var, model}.

An empty model.

Set the objective (an Optex.Aff or a terms list) and the optimization sense (:min or :max), returning the model.

Types

t()

@type t() :: %Optex.Model{
  abs_defs: term(),
  con_counter: non_neg_integer(),
  cone_counter: term(),
  cones: term(),
  constraints: [Optex.Constraint.t()],
  ind_counter: term(),
  indicators: term(),
  minmax_defs: term(),
  name_index: %{required(term()) => non_neg_integer()},
  objective: Optex.Aff.t(),
  pwl_defs: term(),
  qcon_counter: term(),
  qconstraints: term(),
  sense: :min | :max,
  sos_counter: term(),
  soss: term(),
  var_counter: non_neg_integer(),
  vars: %{required(non_neg_integer()) => Optex.Var.t()}
}

terms()

@type terms() :: [{var_ref(), number()}]

var_ref()

@type var_ref() :: Optex.Var.t() | term()

Functions

add_abs(m, arg, opts \\ [])

Define a variable equal to the absolute value of an affine expression and return {var, model}. Solved natively by capable backends (Gurobi, CPLEX); backends without abs support reject the model at solve time.

The argument is a %Optex.Var{}, an Optex.Aff, or a terms list. When it is not already a bare variable, a free auxiliary variable pinned to the expression by an equality row is introduced (named {name, :arg}). Options: :name, plus variable options for the result (:ub; :lb defaults to 0.0 since the result is nonnegative).

add_cone(m, head, members, opts \\ [])

Append the second-order cone head >= sqrt(sum member^2) and return the model. head and each member are variable references (%Optex.Var{} or registered names); the head must carry a nonnegative lower bound (raise otherwise: the bound is part of the cone's meaning and is never set silently). Solved natively by capable backends (Gurobi, CPLEX, COPT); backends without cone support reject the model at solve time. Options: :name.

add_constraint(m, aff_or_terms, sense, rhs, opts \\ [])

Append the constraint aff SENSE rhs (sense :le, :ge, or :eq) and return the model.

The left side is an Optex.Aff or a {reference, coefficient} terms list (see the module docs). Any affine constant folds into the right-hand side. Options: :name (any term; keys the constraint's dual value in solutions).

add_indicator_constraint(m, bin_ref, aff_or_terms, sense, rhs, opts \\ [])

Append the indicator constraint bin = active -> aff SENSE rhs and return the model. Solved natively by capable backends (Gurobi, CPLEX); backends without indicator support reject the model at solve time.

bin_ref is a %Optex.Var{} or variable name and must refer to a :bin variable. Options: :active_when (1 default, or 0 for "when the binary is off"), :name.

add_minmax(m, op, args, opts \\ [])

Define a variable equal to the minimum or maximum (op) of the given arguments and return {var, model}. Solved natively by capable backends (Gurobi only); backends without min/max support reject the model at solve time.

Each argument is a %Optex.Var{}, an Optex.Aff, a terms list, or a number. Numeric arguments (and constant expressions) fold into a single constant operand; at least one variable argument is required. Non-bare expression arguments get free auxiliary variables pinned by equality rows, named {name, {:arg, i}} / {name, {:def, i}} by 0-based position among the expression arguments. Options: :name, plus variable options for the result (:lb/:ub default unbounded).

add_norm_constraint(m, member_affs, rhs, opts \\ [])

Append the cone constraint rhs >= sqrt(sum member_aff^2) (the DSL's constraint norm(exprs...) <= rhs) and return the model. Non-bare member expressions get aux variables named {name, {:arg, i}} pinned by {name, {:def, i}} rows. When rhs is not already a bare variable with a nonnegative lower bound, a head aux named {name, :head} with lb 0.0 is pinned to it by a {name, :head_def} row; this is exact, since the cone forces its head nonnegative anyway.

add_pwl(m, arg, points, opts \\ [])

Define a variable as a piecewise-linear function of an affine expression and return {var, model}. Solved natively by capable backends (Gurobi, CPLEX); backends without pwl support reject the model at solve time.

points is a list of at least two {x, y} number pairs with non-decreasing x; consecutive points are joined by segments and the first and last segments extend beyond the breakpoint range. Exactly two consecutive points may share an x with different y values, defining a jump discontinuity; at the jump the function may take either y (the solver chooses, so an optimizer picks the favorable one). Jumps must be interior: the first and last point pairs need distinct x, since those segments define the extension slopes. The argument follows the same rules as add_abs/3 (aux variable for non-bare expressions). Options: :name, plus variable options for the result (:lb/:ub default unbounded).

add_rotated_cone(m, head1, head2, members, opts \\ [])

Append the rotated second-order cone 2 * head1 * head2 >= sum member^2 and return the model. Both heads must carry nonnegative lower bounds (raise otherwise). Same reference rules and backend support as add_cone/4. Options: :name.

add_sos(m, type, members, opts \\ [])

Append a special ordered set and return the model. type is :sos1 (at most one member nonzero) or :sos2 (at most two nonzero, adjacent in weight order). members is a list of {variable_or_name, weight} pairs: at least two, distinct variables, distinct numeric weights (weights define the set's order, which is what SOS2 adjacency means). Solved natively by capable backends (Gurobi, CPLEX, COPT); backends without SOS support reject the model at solve time. Options: :name.

add_variable(m, opts \\ [])

Register a variable and return {var, model}.

Options: :name (any term; keys the solution values and enables name-based term references), :type (:cont default, :int, :bin), :lb/:ub (number or :infinity/:neg_infinity). A :bin variable gets [0, 1] bounds regardless of the given ones.

new()

An empty model.

set_objective(m, aff, sense)

Set the objective (an Optex.Aff or a terms list) and the optimization sense (:min or :max), returning the model.