API Reference
This page lists the public API of MathOptAI.
This page is an unstructured list of the MathOptAI API. For a more structured overview, read the Manual or Tutorial parts of this documentation.
Load all of the public the API into the current scope with:
using MathOptAIAlternatively, load only the module with:
import MathOptAIand then prefix all calls with MathOptAI. to create MathOptAI.<NAME>.
AbstractPredictor
MathOptAI.AbstractPredictor — Type
abstract type AbstractPredictor endAn abstract type representing different types of prediction models.
Methods
All subtypes must implement:
add_predictor
MathOptAI.add_predictor — Function
MathOptAI.add_predictor(
model::JuMP.AbstractModel,
predictor::MathOptAI.Quantile{<:AbstractGPs.PosteriorGP},
x::Vector,
)Add the quantiles of a trained Gaussian Process from AbstractGPs.jl to model.
Example
julia> using JuMP, MathOptAI, AbstractGPs
julia> x_data = 2π .* (0.0:0.1:1.0);
julia> y_data = sin.(x_data);
julia> fx = AbstractGPs.GP(AbstractGPs.Matern32Kernel())(x_data, 0.1);
julia> p_fx = AbstractGPs.posterior(fx, y_data);
julia> model = Model();
julia> @variable(model, 1 <= x[1:1] <= 6, start = 3);
julia> predictor = MathOptAI.Quantile(p_fx, [0.1, 0.9]);
julia> y, _ = MathOptAI.add_predictor(model, predictor, x);
julia> y
2-element Vector{VariableRef}:
moai_quantile[1]
moai_quantile[2]
julia> @objective(model, Max, y[2] - y[1])
moai_quantile[2] - moai_quantile[1]MathOptAI.add_predictor(
model::JuMP.AbstractModel,
predictor::StatsModels.TableRegressionModel,
x::DataFrames.DataFrame;
kwargs...,
)Add a trained regression model from StatsModels.jl to model, using the DataFrame x as input.
In most cases, predictor should be a GLM.jl predictor supported by MathOptAI, but trained using @formula and a DataFrame instead of the raw matrix input.
In general, x may have some columns that are constant (Float64) and some columns that are JuMP decision variables.
Keyword arguments
All keyword arguments are passed to the corresponding add_predictor of the GLM extension.
Example
julia> using DataFrames, GLM, JuMP, MathOptAI
julia> train_df = DataFrames.DataFrame(x1 = rand(10), x2 = rand(10));
julia> train_df.y = 1.0 .* train_df.x1 + 2.0 .* train_df.x2 .+ rand(10);
julia> predictor = GLM.lm(GLM.@formula(y ~ x1 + x2), train_df);
julia> model = Model();
julia> test_df = DataFrames.DataFrame(
x1 = rand(6),
x2 = @variable(model, [1:6]),
);
julia> test_df.y, _ = MathOptAI.add_predictor(model, predictor, test_df);
julia> test_df.y
6-element Vector{VariableRef}:
moai_Affine[1]
moai_Affine[1]
moai_Affine[1]
moai_Affine[1]
moai_Affine[1]
moai_Affine[1]add_predictor(
model::JuMP.AbstractModel,
predictor::Any,
x::Vector;
reduced_space::Bool = false,
kwargs...,
)::Tuple{<:Vector,<:AbstractFormulation}Return a Vector representing y such that y = predictor(x) and an AbstractFormulation containing the variables and constraints that were added to the model.
The element type of x is deliberately unspecified. The vector x may contain any mix of scalar constants, JuMP decision variables, and scalar JuMP functions like AffExpr, QuadExpr, or NonlinearExpr.
Keyword arguments
reduced_space: iftrue, wrappredictorinReducedSpacebefore adding to the model.
All other keyword arguments are passed to build_predictor.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, x[1:2]);
julia> f = MathOptAI.Affine([2.0, 3.0])
Affine(A, b) [input: 2, output: 1]
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
1-element Vector{VariableRef}:
moai_Affine[1]
julia> formulation
Affine(A, b) [input: 2, output: 1]
├ variables [1]
│ └ moai_Affine[1]
└ constraints [1]
└ 2 x[1] + 3 x[2] - moai_Affine[1] = 0
julia> y, formulation = MathOptAI.add_predictor(model, f, x; reduced_space = true);
julia> y
1-element Vector{AffExpr}:
2 x[1] + 3 x[2]
julia> formulation
ReducedSpace(Affine(A, b) [input: 2, output: 1])
├ variables [0]
└ constraints [0]add_predictor(model::JuMP.AbstractModel, predictor, x::Matrix)Return a Matrix, representing y such that y[:, i] = predictor(x[:, i]) for each column i.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, x[1:2, 1:3]);
julia> f = MathOptAI.Affine([2.0, 3.0])
Affine(A, b) [input: 2, output: 1]
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
1×3 Matrix{VariableRef}:
moai_Affine[1] moai_Affine[1] moai_Affine[1]
julia> formulation
Affine(A, b) [input: 2, output: 1]
├ variables [1]
│ └ moai_Affine[1]
└ constraints [1]
└ 2 x[1,1] + 3 x[2,1] - moai_Affine[1] = 0
Affine(A, b) [input: 2, output: 1]
├ variables [1]
│ └ moai_Affine[1]
└ constraints [1]
└ 2 x[1,2] + 3 x[2,2] - moai_Affine[1] = 0
Affine(A, b) [input: 2, output: 1]
├ variables [1]
│ └ moai_Affine[1]
└ constraints [1]
└ 2 x[1,3] + 3 x[2,3] - moai_Affine[1] = 0build_predictor
MathOptAI.build_predictor — Method
build_predictor(extension; kwargs...)::AbstractPredictorA uniform interface to convert various extension types to an AbstractPredictor.
See the various extension docstrings for details.
Affine
MathOptAI.Affine — Type
Affine(
A::Matrix{T},
b::Vector{T} = zeros(T, size(A, 1)),
) where {T} <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = A x + b\]
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, 0 <= x[i in 1:2] <= i);
julia> f = MathOptAI.Affine([2.0 3.0], [4.0])
Affine(A, b) [input: 2, output: 1]
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
1-element Vector{VariableRef}:
moai_Affine[1]
julia> formulation
Affine(A, b) [input: 2, output: 1]
├ variables [1]
│ └ moai_Affine[1]
└ constraints [3]
├ moai_Affine[1] ≥ 4
├ moai_Affine[1] ≤ 12
└ 2 x[1] + 3 x[2] - moai_Affine[1] = -4
julia> y, formulation =
MathOptAI.add_predictor(model, MathOptAI.ReducedSpace(f), x);
julia> y
1-element Vector{AffExpr}:
2 x[1] + 3 x[2] + 4
julia> formulation
ReducedSpace(Affine(A, b) [input: 2, output: 1])
├ variables [0]
└ constraints [0]AffineCombination
MathOptAI.AffineCombination — Type
AffineCombination(
predictors::Vector{<:AbstractPredictor},
weights::Vector{Float64},
constant::Vector{Float64},
)An AbstractPredictor that represents the linear combination of other predictors.
The main purpose of this predictor is to model random forests and gradient boosted trees.
- A random forest is the mean a set of
BinaryDecisionTree - A gradient boosted tree is the sum of a set of
BinaryDecisionTree
Example
julia> using JuMP, MathOptAI
julia> rhs = MathOptAI.BinaryDecisionTree(1, 1.0, 0, 1)
BinaryDecisionTree{Float64,Int64} [leaves=2, depth=2]
julia> lhs = MathOptAI.BinaryDecisionTree(1, -0.1, -1, 0)
BinaryDecisionTree{Float64,Int64} [leaves=2, depth=2]
julia> tree_1 = MathOptAI.BinaryDecisionTree(1, 0.0, -1, rhs);
julia> tree_2 = MathOptAI.BinaryDecisionTree(1, 0.9, lhs, 1);
julia> random_forest = MathOptAI.AffineCombination(
[tree_1, tree_2],
[0.5, 0.5],
[0.0],
)
AffineCombination
├ 0.5 * BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]
├ 0.5 * BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]
└ 1.0 * [0.0]
julia> model = Model();
julia> @variable(model, -3 <= x[1:1] <= 5);
julia> y, formulation = MathOptAI.add_predictor(model, random_forest, x);
julia> y
1-element Vector{VariableRef}:
moai_AffineCombination[1]
julia> formulation
AffineCombination
├ 0.5 * BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]
├ 0.5 * BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]
└ 1.0 * [0.0]
├ variables [1]
│ └ moai_AffineCombination[1]
└ constraints [1]
└ 0.5 moai_BinaryDecisionTree_value[1] + 0.5 moai_BinaryDecisionTree_value[1] - moai_AffineCombination[1] = 0
BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]
├ variables [4]
│ ├ moai_BinaryDecisionTree_value[1]
│ ├ moai_BinaryDecisionTree_z[1]
│ ├ moai_BinaryDecisionTree_z[2]
│ └ moai_BinaryDecisionTree_z[3]
└ constraints [7]
├ moai_BinaryDecisionTree_z[1] + moai_BinaryDecisionTree_z[2] + moai_BinaryDecisionTree_z[3] = 1
├ moai_BinaryDecisionTree_z[1] --> {x[1] ≤ -1.0e-6}
├ moai_BinaryDecisionTree_z[2] --> {x[1] ≥ 0}
├ moai_BinaryDecisionTree_z[2] --> {x[1] ≤ 0.999999}
├ moai_BinaryDecisionTree_z[3] --> {x[1] ≥ 0}
├ moai_BinaryDecisionTree_z[3] --> {x[1] ≥ 1}
└ moai_BinaryDecisionTree_z[1] - moai_BinaryDecisionTree_z[3] + moai_BinaryDecisionTree_value[1] = 0
BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]
├ variables [4]
│ ├ moai_BinaryDecisionTree_value[1]
│ ├ moai_BinaryDecisionTree_z[1]
│ ├ moai_BinaryDecisionTree_z[2]
│ └ moai_BinaryDecisionTree_z[3]
└ constraints [7]
├ moai_BinaryDecisionTree_z[1] + moai_BinaryDecisionTree_z[2] + moai_BinaryDecisionTree_z[3] = 1
├ moai_BinaryDecisionTree_z[1] --> {x[1] ≤ 0.899999}
├ moai_BinaryDecisionTree_z[1] --> {x[1] ≤ -0.100001}
├ moai_BinaryDecisionTree_z[2] --> {x[1] ≤ 0.899999}
├ moai_BinaryDecisionTree_z[2] --> {x[1] ≥ -0.1}
├ moai_BinaryDecisionTree_z[3] --> {x[1] ≥ 0.9}
└ moai_BinaryDecisionTree_z[1] - moai_BinaryDecisionTree_z[3] + moai_BinaryDecisionTree_value[1] = 0BinaryDecisionTree
MathOptAI.BinaryDecisionTree — Type
BinaryDecisionTree{K,V}(
feat_id::Int,
feat_value::K,
lhs::Union{V,BinaryDecisionTree{K,V}},
rhs::Union{V,BinaryDecisionTree{K,V}},
atol::Float64 = 1e-6,
)An AbstractPredictor that represents a binary decision tree.
- If
x[feat_id] <= feat_value - atol, then returnlhs - If
x[feat_id] >= feat_value, then returnrhs
Example
To represent the tree x[1] <= 0.0 ? -1 : (x[1] <= 1.0 ? 0 : 1), do:
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, x[1:1]);
julia> f = MathOptAI.BinaryDecisionTree{Float64,Int}(
1,
0.0,
-1,
MathOptAI.BinaryDecisionTree{Float64,Int}(1, 1.0, 0, 1),
)
BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
1-element Vector{VariableRef}:
moai_BinaryDecisionTree_value[1]
julia> formulation
BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]
├ variables [4]
│ ├ moai_BinaryDecisionTree_value[1]
│ ├ moai_BinaryDecisionTree_z[1]
│ ├ moai_BinaryDecisionTree_z[2]
│ └ moai_BinaryDecisionTree_z[3]
└ constraints [7]
├ moai_BinaryDecisionTree_z[1] + moai_BinaryDecisionTree_z[2] + moai_BinaryDecisionTree_z[3] = 1
├ moai_BinaryDecisionTree_z[1] --> {x[1] ≤ -1.0e-6}
├ moai_BinaryDecisionTree_z[2] --> {x[1] ≥ 0}
├ moai_BinaryDecisionTree_z[2] --> {x[1] ≤ 0.999999}
├ moai_BinaryDecisionTree_z[3] --> {x[1] ≥ 0}
├ moai_BinaryDecisionTree_z[3] --> {x[1] ≥ 1}
└ moai_BinaryDecisionTree_z[1] - moai_BinaryDecisionTree_z[3] + moai_BinaryDecisionTree_value[1] = 0GELU
MathOptAI.GELU — Type
GeLU() <: AbstractPredictorAn AbstractPredictor representing the Gaussian Error Linear Units function:
\[y \approx x * (1 + \tanh(\sqrt(2 / \pi) * (x + 0.044715 x^3))) / 2\]
as a smooth nonlinear constraint.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, -1 <= x[i in 1:2] <= i);
julia> f = MathOptAI.GELU()
GELU()
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_GELU[1]
moai_GELU[2]
julia> formulation
GELU()
├ variables [2]
│ ├ moai_GELU[1]
│ └ moai_GELU[2]
└ constraints [6]
├ moai_GELU[1] ≥ -0.17
├ moai_GELU[1] ≤ 0.8411919906082768
├ moai_GELU[1] - ((0.5 x[1]) * (1.0 + tanh(0.7978845608028654 * (x[1] + (0.044715 * (x[1] ^ 3.0)))))) = 0
├ moai_GELU[2] ≥ -0.17
├ moai_GELU[2] ≤ 1.954597694087775
└ moai_GELU[2] - ((0.5 x[2]) * (1.0 + tanh(0.7978845608028654 * (x[2] + (0.044715 * (x[2] ^ 3.0)))))) = 0GrayBox
MathOptAI.GrayBox — Type
GrayBox(
output_size::Function,
callback::Function;
has_hessian::Bool = false,
) <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = f(x)\]
as a user-defined nonlinear operator.
Arguments
output_size(x::Vector):Int: given an input vectorx, return the dimension of the output vectorcallback(x::Vector)::NamedTuple -> (;value, jacobian[, hessian]): given an input vectorx, return aNamedTuplethat computes the primal value and Jacobian of the output value with respect to the input.jacobian[j, i]is the partial derivative ofvalue[j]with respect tox[i].has_hessian: iftrue, thecallbackadditionally contains a fieldhessian, which is anN × N × Mmatrix, wherehessian[i, j, k]is the partial derivative ofvalue[k]with respect tox[i]andx[j].
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, x[1:2]);
julia> f = MathOptAI.GrayBox(
x -> 2,
x -> (value = x.^2, jacobian = [2 * x[1] 0.0; 0.0 2 * x[2]]),
);
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_GrayBox[1]
moai_GrayBox[2]
julia> formulation
GrayBox
├ variables [2]
│ ├ moai_GrayBox[1]
│ └ moai_GrayBox[2]
└ constraints [2]
├ op_##330(x[1], x[2]) - moai_GrayBox[1] = 0
└ op_##331(x[1], x[2]) - moai_GrayBox[2] = 0
julia> y, formulation =
MathOptAI.add_predictor(model, MathOptAI.ReducedSpace(f), x);
julia> y
2-element Vector{NonlinearExpr}:
op_##332(x[1], x[2])
op_##333(x[1], x[2])
julia> formulation
ReducedSpace(GrayBox)
├ variables [0]
└ constraints [0]Pipeline
MathOptAI.Pipeline — Type
Pipeline(layers::Vector{AbstractPredictor}) <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = (l_1 \circ \ldots \circ l_N)(x)\]
where $l_i$ are a list of other AbstractPredictors.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, x[1:2]);
julia> f = MathOptAI.Pipeline(
MathOptAI.Affine([1.0 2.0], [0.0]),
MathOptAI.ReLUQuadratic(),
)
Pipeline with layers:
* Affine(A, b) [input: 2, output: 1]
* ReLUQuadratic(nothing)
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
1-element Vector{VariableRef}:
moai_ReLU[1]
julia> formulation
Affine(A, b) [input: 2, output: 1]
├ variables [1]
│ └ moai_Affine[1]
└ constraints [1]
└ x[1] + 2 x[2] - moai_Affine[1] = 0
ReLUQuadratic(nothing)
├ variables [2]
│ ├ moai_ReLU[1]
│ └ moai_z[1]
└ constraints [4]
├ moai_ReLU[1] ≥ 0
├ moai_z[1] ≥ 0
├ moai_Affine[1] - moai_ReLU[1] + moai_z[1] = 0
└ moai_ReLU[1]*moai_z[1] = 0PytorchModel
MathOptAI.PytorchModel — Type
PytorchModel(filename::String)A wrapper struct for loading a PyTorch model.
The only supported file extension is .pt, where the .pt file has been created using torch.save(model, filename).
To use PytorchModel, your code must load the PythonCall package:
import PythonCallExample
julia> using MathOptAI
julia> using PythonCall # This line is important!
julia> predictor = PytorchModel("model.pt");Quantile
MathOptAI.Quantile — Type
Quantile{D}(distribution::D, quantiles::Vector{Float64}) where {D}An AbstractPredictor that represents the quantiles of distribution.
Example
julia> using JuMP, Distributions, MathOptAI
julia> model = Model();
julia> @variable(model, 1 <= x <= 2);
julia> predictor = MathOptAI.Quantile([0.1, 0.9]) do x
return Distributions.Normal(x, 3 - x)
end
Quantile(_, [0.1, 0.9])
julia> y, formulation = MathOptAI.add_predictor(model, predictor, [x]);
julia> y
2-element Vector{VariableRef}:
moai_quantile[1]
moai_quantile[2]
julia> formulation
Quantile(_, [0.1, 0.9])
├ variables [2]
│ ├ moai_quantile[1]
│ └ moai_quantile[2]
└ constraints [2]
├ moai_quantile[1] - op_quantile_0.1(x) = 0
└ moai_quantile[2] - op_quantile_0.9(x) = 0ReducedSpace
MathOptAI.ReducedSpace — Type
ReducedSpace(predictor::AbstractPredictor)A wrapper type for other predictors that implement a reduced-space formulation.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, x[1:2]);
julia> predictor = MathOptAI.ReducedSpace(MathOptAI.ReLU());
julia> y, formulation = MathOptAI.add_predictor(model, predictor, x);
julia> y
2-element Vector{NonlinearExpr}:
max(0.0, x[1])
max(0.0, x[2])ReLU
MathOptAI.ReLU — Type
ReLU() <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = \max\{0, x\}\]
as a non-smooth nonlinear constraint.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, -1 <= x[i in 1:2] <= i);
julia> f = MathOptAI.ReLU()
ReLU()
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_ReLU[1]
moai_ReLU[2]
julia> formulation
ReLU()
├ variables [2]
│ ├ moai_ReLU[1]
│ └ moai_ReLU[2]
└ constraints [6]
├ moai_ReLU[1] ≥ 0
├ moai_ReLU[1] ≤ 1
├ moai_ReLU[1] - max(0.0, x[1]) = 0
├ moai_ReLU[2] ≥ 0
├ moai_ReLU[2] ≤ 2
└ moai_ReLU[2] - max(0.0, x[2]) = 0
julia> y, formulation =
MathOptAI.add_predictor(model, MathOptAI.ReducedSpace(f), x);
julia> y
2-element Vector{NonlinearExpr}:
max(0.0, x[1])
max(0.0, x[2])
julia> formulation
ReducedSpace(ReLU())
├ variables [0]
└ constraints [0]ReLUBigM
MathOptAI.ReLUBigM — Type
ReLUBigM(M::Float64) <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = \max\{0, x\}\]
via the big-M MIP reformulation:
\[\begin{aligned} y \ge 0 \\ y \ge x \\ y \le M z \\ y \le x + M(1 - z) \\ z \in\{0, 1\} \end{aligned}\]
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, -3 <= x[i in 1:2] <= i);
julia> f = MathOptAI.ReLUBigM(100.0)
ReLUBigM(100.0)
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_ReLU[1]
moai_ReLU[2]
julia> formulation
ReLUBigM(100.0)
├ variables [4]
│ ├ moai_ReLU[1]
│ ├ moai_ReLU[2]
│ ├ moai_z[1]
│ └ moai_z[2]
└ constraints [12]
├ moai_ReLU[1] ≥ 0
├ moai_ReLU[1] ≤ 1
├ moai_z[1] binary
├ -x[1] + moai_ReLU[1] ≥ 0
├ moai_ReLU[1] - moai_z[1] ≤ 0
├ -x[1] + moai_ReLU[1] + 3 moai_z[1] ≤ 3
├ moai_ReLU[2] ≥ 0
├ moai_ReLU[2] ≤ 2
├ moai_z[2] binary
├ -x[2] + moai_ReLU[2] ≥ 0
├ moai_ReLU[2] - 2 moai_z[2] ≤ 0
└ -x[2] + moai_ReLU[2] + 3 moai_z[2] ≤ 3ReLUQuadratic
MathOptAI.ReLUQuadratic — Type
ReLUQuadratic(; relaxation_parameter = nothing) <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = \max\{0, x\}\]
by the reformulation:
\[\begin{aligned} x = y - z \\ y \cdot z = 0 \\ y, z \ge 0 \end{aligned}\]
If relaxation_parameter is set to a value ϵ, the constraints become:
\[\begin{aligned} x = y - z \\ y \cdot z \leq \epsilon \\ y, z \ge 0 \end{aligned}\]
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, -1 <= x[i in 1:2] <= i);
julia> f = MathOptAI.ReLUQuadratic()
ReLUQuadratic(nothing)
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_ReLU[1]
moai_ReLU[2]
julia> formulation
ReLUQuadratic(nothing)
├ variables [4]
│ ├ moai_ReLU[1]
│ ├ moai_ReLU[2]
│ ├ moai_z[1]
│ └ moai_z[2]
└ constraints [12]
├ moai_ReLU[1] ≥ 0
├ moai_ReLU[1] ≤ 1
├ moai_z[1] ≥ 0
├ moai_z[1] ≤ 1
├ x[1] - moai_ReLU[1] + moai_z[1] = 0
├ moai_ReLU[1]*moai_z[1] = 0
├ moai_ReLU[2] ≥ 0
├ moai_ReLU[2] ≤ 2
├ moai_z[2] ≥ 0
├ moai_z[2] ≤ 1
├ x[2] - moai_ReLU[2] + moai_z[2] = 0
└ moai_ReLU[2]*moai_z[2] = 0ReLUSOS1
MathOptAI.ReLUSOS1 — Type
ReLUSOS1() <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = \max\{0, x\}\]
by the reformulation:
\[\begin{aligned} x = y - z \\ [y, z] \in SOS1 \\ y, z \ge 0 \end{aligned}\]
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, -1 <= x[i in 1:2] <= i);
julia> f = MathOptAI.ReLUSOS1()
ReLUSOS1()
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_ReLU[1]
moai_ReLU[2]
julia> formulation
ReLUSOS1()
├ variables [4]
│ ├ moai_ReLU[1]
│ ├ moai_ReLU[2]
│ ├ moai_z[1]
│ └ moai_z[2]
└ constraints [12]
├ moai_ReLU[1] ≥ 0
├ moai_ReLU[1] ≤ 1
├ moai_z[1] ≥ 0
├ moai_z[1] ≤ 1
├ x[1] - moai_ReLU[1] + moai_z[1] = 0
├ [moai_ReLU[1], moai_z[1]] ∈ MathOptInterface.SOS1{Float64}([1.0, 2.0])
├ moai_ReLU[2] ≥ 0
├ moai_ReLU[2] ≤ 2
├ moai_z[2] ≥ 0
├ moai_z[2] ≤ 1
├ x[2] - moai_ReLU[2] + moai_z[2] = 0
└ [moai_ReLU[2], moai_z[2]] ∈ MathOptInterface.SOS1{Float64}([1.0, 2.0])Scale
MathOptAI.Scale — Type
Scale(
scale::Vector{T},
bias::Vector{T},
) where {T} <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = Diag(scale)x + bias\]
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, 0 <= x[i in 1:2] <= i);
julia> f = MathOptAI.Scale([2.0, 3.0], [4.0, 5.0])
Scale(scale, bias)
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_Scale[1]
moai_Scale[2]
julia> formulation
Scale(scale, bias)
├ variables [2]
│ ├ moai_Scale[1]
│ └ moai_Scale[2]
└ constraints [6]
├ moai_Scale[1] ≥ 4
├ moai_Scale[1] ≤ 6
├ moai_Scale[2] ≥ 5
├ moai_Scale[2] ≤ 11
├ 2 x[1] - moai_Scale[1] = -4
└ 3 x[2] - moai_Scale[2] = -5
julia> y, formulation =
MathOptAI.add_predictor(model, MathOptAI.ReducedSpace(f), x);
julia> y
2-element Vector{AffExpr}:
2 x[1] + 4
3 x[2] + 5
julia> formulation
ReducedSpace(Scale(scale, bias))
├ variables [0]
└ constraints [0]Sigmoid
MathOptAI.Sigmoid — Type
Sigmoid() <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = \frac{1}{1 + e^{-x}}\]
as a smooth nonlinear constraint.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, -1 <= x[i in 1:2] <= i);
julia> f = MathOptAI.Sigmoid()
Sigmoid()
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_Sigmoid[1]
moai_Sigmoid[2]
julia> formulation
Sigmoid()
├ variables [2]
│ ├ moai_Sigmoid[1]
│ └ moai_Sigmoid[2]
└ constraints [6]
├ moai_Sigmoid[1] ≥ 0.2689414213699951
├ moai_Sigmoid[1] ≤ 0.7310585786300049
├ moai_Sigmoid[1] - (1.0 / (1.0 + exp(-x[1]))) = 0
├ moai_Sigmoid[2] ≥ 0.2689414213699951
├ moai_Sigmoid[2] ≤ 0.8807970779778823
└ moai_Sigmoid[2] - (1.0 / (1.0 + exp(-x[2]))) = 0
julia> y, formulation =
MathOptAI.add_predictor(model, MathOptAI.ReducedSpace(f), x);
julia> y
2-element Vector{NonlinearExpr}:
1.0 / (1.0 + exp(-x[1]))
1.0 / (1.0 + exp(-x[2]))
julia> formulation
ReducedSpace(Sigmoid())
├ variables [0]
└ constraints [0]SoftMax
MathOptAI.SoftMax — Type
SoftMax() <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = \frac{e^{x}}{||e^{x}||_1}\]
as a smooth nonlinear constraint.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, x[1:2]);
julia> f = MathOptAI.SoftMax()
SoftMax()
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_SoftMax[1]
moai_SoftMax[2]
julia> formulation
SoftMax()
├ variables [3]
│ ├ moai_SoftMax_denom[1]
│ ├ moai_SoftMax[1]
│ └ moai_SoftMax[2]
└ constraints [8]
├ moai_SoftMax_denom[1] ≥ 0
├ moai_SoftMax_denom[1] - (0.0 + exp(x[2]) + exp(x[1])) = 0
├ moai_SoftMax[1] ≥ 0
├ moai_SoftMax[1] ≤ 1
├ moai_SoftMax[1] - (exp(x[1]) / moai_SoftMax_denom[1]) = 0
├ moai_SoftMax[2] ≥ 0
├ moai_SoftMax[2] ≤ 1
└ moai_SoftMax[2] - (exp(x[2]) / moai_SoftMax_denom[1]) = 0
julia> y, formulation =
MathOptAI.add_predictor(model, MathOptAI.ReducedSpace(f), x);
julia> y
2-element Vector{NonlinearExpr}:
exp(x[1]) / moai_SoftMax_denom[1]
exp(x[2]) / moai_SoftMax_denom[1]
julia> formulation
ReducedSpace(SoftMax())
├ variables [1]
│ └ moai_SoftMax_denom[1]
└ constraints [2]
├ moai_SoftMax_denom[1] ≥ 0
└ moai_SoftMax_denom[1] - (0.0 + exp(x[2]) + exp(x[1])) = 0SoftPlus
MathOptAI.SoftPlus — Type
SoftPlus(; beta = 1.0) <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = \frac{1}{\beta} \log(1 + e^{\beta x})\]
as a smooth nonlinear constraint.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, -1 <= x[i in 1:2] <= i);
julia> f = MathOptAI.SoftPlus(; beta = 2.0)
SoftPlus(2.0)
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_SoftPlus[1]
moai_SoftPlus[2]
julia> formulation
SoftPlus(2.0)
├ variables [2]
│ ├ moai_SoftPlus[1]
│ └ moai_SoftPlus[2]
└ constraints [6]
├ moai_SoftPlus[1] ≥ 0.0634640055214863
├ moai_SoftPlus[1] ≤ 1.0634640055214863
├ moai_SoftPlus[1] - (log(1.0 + exp(2 x[1])) / 2.0) = 0
├ moai_SoftPlus[2] ≥ 0.0634640055214863
├ moai_SoftPlus[2] ≤ 2.0090749639589047
└ moai_SoftPlus[2] - (log(1.0 + exp(2 x[2])) / 2.0) = 0
julia> y, formulation =
MathOptAI.add_predictor(model, MathOptAI.ReducedSpace(f), x);
julia> y
2-element Vector{NonlinearExpr}:
log(1.0 + exp(2 x[1])) / 2.0
log(1.0 + exp(2 x[2])) / 2.0
julia> formulation
ReducedSpace(SoftPlus(2.0))
├ variables [0]
└ constraints [0]Tanh
MathOptAI.Tanh — Type
Tanh() <: AbstractPredictorAn AbstractPredictor that represents the relationship:
\[y = \tanh(x)\]
as a smooth nonlinear constraint.
Example
julia> using JuMP, MathOptAI
julia> model = Model();
julia> @variable(model, -1 <= x[i in 1:2] <= i);
julia> f = MathOptAI.Tanh()
Tanh()
julia> y, formulation = MathOptAI.add_predictor(model, f, x);
julia> y
2-element Vector{VariableRef}:
moai_Tanh[1]
moai_Tanh[2]
julia> formulation
Tanh()
├ variables [2]
│ ├ moai_Tanh[1]
│ └ moai_Tanh[2]
└ constraints [6]
├ moai_Tanh[1] ≥ -0.7615941559557649
├ moai_Tanh[1] ≤ 0.7615941559557649
├ moai_Tanh[1] - tanh(x[1]) = 0
├ moai_Tanh[2] ≥ -0.7615941559557649
├ moai_Tanh[2] ≤ 0.9640275800758169
└ moai_Tanh[2] - tanh(x[2]) = 0
julia> y, formulation =
MathOptAI.add_predictor(model, MathOptAI.ReducedSpace(f), x);
julia> y
2-element Vector{NonlinearExpr}:
tanh(x[1])
tanh(x[2])
julia> formulation
ReducedSpace(Tanh())
├ variables [0]
└ constraints [0]VectorNonlinearOracle
MathOptAI.VectorNonlinearOracle — Type
VectorNonlinearOracle(x)A wrapper struct for creating an MOI.VectorNonlinearOracle.
AbstractFormulation
MathOptAI.AbstractFormulation — Type
abstract type AbstractFormulation endAn abstract type representing different formulations.
Formulation
MathOptAI.Formulation — Type
struct Formulation{P<:AbstractPredictor} <: AbstractFormulation
predictor::P
variables::Vector{Any}
constraints::Vector{Any}
endFields
predictor: the predictor object used to build the formulationvariables: a vector of new decision variables added to the modelconstraints: a vector of new constraints added to the model
Check the docstring of the predictor for an explanation of the formulation and the order of the elements in .variables and .constraints.
PipelineFormulation
MathOptAI.PipelineFormulation — Type
struct PipelineFormulation{P<:AbstractPredictor} <: AbstractFormulation
predictor::P
layers::Vector{Any}
endFields
predictor: the predictor object used to build the formulationlayers: the formulation associated with each of the layers in the pipeline
AbstractGPs
MathOptAI.add_predictor — Method
MathOptAI.add_predictor(
model::JuMP.AbstractModel,
predictor::MathOptAI.Quantile{<:AbstractGPs.PosteriorGP},
x::Vector,
)Add the quantiles of a trained Gaussian Process from AbstractGPs.jl to model.
Example
julia> using JuMP, MathOptAI, AbstractGPs
julia> x_data = 2π .* (0.0:0.1:1.0);
julia> y_data = sin.(x_data);
julia> fx = AbstractGPs.GP(AbstractGPs.Matern32Kernel())(x_data, 0.1);
julia> p_fx = AbstractGPs.posterior(fx, y_data);
julia> model = Model();
julia> @variable(model, 1 <= x[1:1] <= 6, start = 3);
julia> predictor = MathOptAI.Quantile(p_fx, [0.1, 0.9]);
julia> y, _ = MathOptAI.add_predictor(model, predictor, x);
julia> y
2-element Vector{VariableRef}:
moai_quantile[1]
moai_quantile[2]
julia> @objective(model, Max, y[2] - y[1])
moai_quantile[2] - moai_quantile[1]DecisionTree
MathOptAI.build_predictor — Method
MathOptAI.build_predictor(
predictor::Union{
DecisionTree.Ensemble,
DecisionTree.DecisionTreeClassifier,
DecisionTree.Leaf,
DecisionTree.Node,
DecisionTree.Root,
},
)Convert a binary decision tree from DecisionTree.jl to a BinaryDecisionTree.
Example
julia> using JuMP, MathOptAI, DecisionTree
julia> truth(x::Vector) = x[1] <= 0.5 ? -2 : (x[2] <= 0.3 ? 3 : 4)
truth (generic function with 1 method)
julia> features = abs.(sin.((1:10) .* (3:4)'));
julia> size(features)
(10, 2)
julia> labels = truth.(Vector.(eachrow(features)));
julia> tree = DecisionTree.build_tree(labels, features)
Decision Tree
Leaves: 3
Depth: 2
julia> model = Model();
julia> @variable(model, 0 <= x[1:2] <= 1);
julia> y, _ = MathOptAI.add_predictor(model, tree, x);
julia> y
1-element Vector{VariableRef}:
moai_BinaryDecisionTree_value[1]
julia> MathOptAI.build_predictor(tree)
BinaryDecisionTree{Float64,Int64} [leaves=3, depth=2]EvoTrees
MathOptAI.build_predictor — Method
MathOptAI.build_predictor(predictor::EvoTrees.EvoTree{L,1}) where {L}Convert a boosted tree from EvoTrees.jl to an AffineCombination of BinaryDecisionTree.
Example
julia> using JuMP, MathOptAI, EvoTrees
julia> truth(x::Vector) = x[1] <= 0.5 ? -2 : (x[2] <= 0.3 ? 3 : 4)
truth (generic function with 1 method)
julia> x_train = abs.(sin.((1:10) .* (3:4)'));
julia> size(x_train)
(10, 2)
julia> y_train = truth.(Vector.(eachrow(x_train)));
julia> config = EvoTrees.EvoTreeRegressor(; nrounds = 3);
julia> tree = EvoTrees.fit(config; x_train, y_train);
julia> model = Model();
julia> @variable(model, 0 <= x[1:2] <= 1);
julia> y, _ = MathOptAI.add_predictor(model, tree, x);
julia> y
1-element Vector{VariableRef}:
moai_AffineCombination[1]
julia> MathOptAI.build_predictor(tree)
AffineCombination
├ 1.0 * BinaryDecisionTree{Float64,Float64} [leaves=3, depth=2]
├ 1.0 * BinaryDecisionTree{Float64,Float64} [leaves=3, depth=2]
├ 1.0 * BinaryDecisionTree{Float64,Float64} [leaves=3, depth=2]
└ 1.0 * [2.0]Flux
MathOptAI.build_predictor — Method
MathOptAI.build_predictor(
predictor::Flux.Chain;
config::Dict = Dict{Any,Any}(),
gray_box::Bool = false,
vector_nonlinear_oracle::Bool = false,
hessian::Bool = vector_nonlinear_oracle,
)Convert a trained neural network from Flux.jl to a Pipeline.
Supported layers
Flux.DenseFlux.ScaleFlux.softmax
Supported activation functions
Flux.reluFlux.sigmoidFlux.softplusFlux.tanh
Keyword arguments
config: a dictionary that maps supportedFluxactivation functions toAbstractPredictors that control how the activation functions are reformulated. For example,Flux.sigmoid => MathOptAI.Sigmoid()orFlux.relu => MathOptAI.QuadraticReLU().gray_box: iftrue, the neural network is added using aGrayBoxformulation.vector_nonlinear_oracle: iftrue, the neural network is added using aVectorNonlinearOracleformulation.hessian: iftrue, thegray_boxandvector_nonlinear_oracleformulations compute the Hessian of the output usingFlux.hessian. The default forhessianisfalseifgray_boxis used, andtrueifvector_nonlinear_oracleis used.
Compatibility
The vector_nonlinear_oracle feature is experimental. It relies on a private API feature of Ipopt.jl that will change in a future release.
If you use this feature, you must pin the version of Ipopt.jl in your Project.toml to ensure that future updates to Ipopt.jl do not break your existing code.
A known good version of Ipopt.jl is v1.8.0. Pin the version using:
[compat]
Ipopt = "=1.8.0"Example
julia> using JuMP, MathOptAI, Flux
julia> chain = Flux.Chain(Flux.Dense(1 => 16, Flux.relu), Flux.Dense(16 => 1));
julia> model = Model();
julia> @variable(model, x[1:1]);
julia> y, _ = MathOptAI.add_predictor(
model,
chain,
x;
config = Dict(Flux.relu => MathOptAI.ReLU()),
);
julia> y
1-element Vector{VariableRef}:
moai_Affine[1]
julia> MathOptAI.build_predictor(
chain;
config = Dict(Flux.relu => MathOptAI.ReLU()),
)
Pipeline with layers:
* Affine(A, b) [input: 1, output: 16]
* ReLU()
* Affine(A, b) [input: 16, output: 1]
julia> MathOptAI.build_predictor(
chain;
config = Dict(Flux.relu => MathOptAI.ReLUQuadratic()),
)
Pipeline with layers:
* Affine(A, b) [input: 1, output: 16]
* ReLUQuadratic(nothing)
* Affine(A, b) [input: 16, output: 1]GLM
MathOptAI.build_predictor — Method
MathOptAI.build_predictor(
predictor::GLM.GeneralizedLinearModel{
GLM.GlmResp{Vector{Float64},GLM.Bernoulli{Float64},GLM.LogitLink},
};
sigmoid::MathOptAI.AbstractPredictor = MathOptAI.Sigmoid(),
)Convert a trained logistic model from GLM.jl to a Pipeline layer.
Keyword arguments
sigmoid: the predictor to use for the sigmoid layer.
Example
julia> using JuMP, MathOptAI, GLM
julia> X, Y = rand(10, 2), rand(Bool, 10);
julia> predictor = GLM.glm(X, Y, GLM.Bernoulli());
julia> model = Model();
julia> @variable(model, x[1:2]);
julia> y, _ = MathOptAI.add_predictor(
model,
predictor,
x;
sigmoid = MathOptAI.Sigmoid(),
);
julia> y
1-element Vector{VariableRef}:
moai_Sigmoid[1]
julia> MathOptAI.build_predictor(predictor)
Pipeline with layers:
* Affine(A, b) [input: 2, output: 1]
* Sigmoid()MathOptAI.build_predictor — Method
MathOptAI.build_predictor(predictor::GLM.LinearModel)Convert a trained linear model from GLM.jl to an Affine layer.
Example
julia> using JuMP, MathOptAI, GLM
julia> X, Y = rand(10, 2), rand(10);
julia> predictor = GLM.lm(X, Y);
julia> model = Model();
julia> @variable(model, x[1:2]);
julia> y, _ = MathOptAI.add_predictor(model, predictor, x);
julia> y
1-element Vector{VariableRef}:
moai_Affine[1]
julia> MathOptAI.build_predictor(predictor)
Affine(A, b) [input: 2, output: 1]Lux
MathOptAI.build_predictor — Method
MathOptAI.build_predictor(
predictor::Tuple{<:Lux.Chain,<:NamedTuple,<:NamedTuple};
config::Dict = Dict{Any,Any}(),
)Convert a trained neural network from Lux.jl to a Pipeline.
Supported layers
Lux.DenseLux.Scale
Supported activation functions
Lux.reluLux.sigmoidLux.softplusLux.softmaxLux.tanh
Keyword arguments
config: a dictionary that maps supportedLuxactivation functions toAbstractPredictors that control how the activation functions are reformulated. For example,Lux.sigmoid => MathOptAI.Sigmoid()orLux.relu => MathOptAI.QuadraticReLU().
Example
julia> using JuMP, MathOptAI, Lux, Random
julia> rng = Random.MersenneTwister();
julia> chain = Lux.Chain(Lux.Dense(1 => 16, Lux.relu), Lux.Dense(16 => 1))
Chain(
layer_1 = Dense(1 => 16, relu), # 32 parameters
layer_2 = Dense(16 => 1), # 17 parameters
) # Total: 49 parameters,
# plus 0 states.
julia> parameters, state = Lux.setup(rng, chain);
julia> model = Model();
julia> @variable(model, x[1:1]);
julia> y, _ = MathOptAI.add_predictor(
model,
(chain, parameters, state),
x;
config = Dict(Lux.relu => MathOptAI.ReLU()),
);
julia> y
1-element Vector{VariableRef}:
moai_Affine[1]
julia> MathOptAI.build_predictor(
(chain, parameters, state);
config = Dict(Lux.relu => MathOptAI.ReLU()),
)
Pipeline with layers:
* Affine(A, b) [input: 1, output: 16]
* ReLU()
* Affine(A, b) [input: 16, output: 1]
julia> MathOptAI.build_predictor(
(chain, parameters, state);
config = Dict(Lux.relu => MathOptAI.ReLUQuadratic()),
)
Pipeline with layers:
* Affine(A, b) [input: 1, output: 16]
* ReLUQuadratic(nothing)
* Affine(A, b) [input: 16, output: 1]PythonCall
MathOptAI.build_predictor — Method
MathOptAI.build_predictor(
predictor::MathOptAI.PytorchModel;
config::Dict = Dict{Any,Any}(),
gray_box::Bool = false,
vector_nonlinear_oracle::Bool = false,
hessian::Bool = vector_nonlinear_oracle,
device::String = "cpu",
)Convert a trained neural network from PyTorch via PythonCall.jl to a Pipeline.
Supported layers
nn.GELUnn.Linearnn.ReLUnn.Sequentialnn.Sigmoidnn.Softmaxnn.Softplusnn.Tanh
Keyword arguments
config: a dictionary that mapsSymbols toAbstractPredictors that control how the activation functions are reformulated. For example,:Sigmoid => MathOptAI.Sigmoid()or:ReLU => MathOptAI.QuadraticReLU(). The supported Symbols are:ReLU,:Sigmoid,:SoftMax,:SoftPlus, and:Tanh.gray_box: iftrue, the neural network is added using aGrayBoxformulation.vector_nonlinear_oracle: iftrue, the neural network is added using aVectorNonlinearOracleformulation.hessian: iftrue, thegray_boxandvector_nonlinear_oracleformulations compute the Hessian of the output usingtorch.func.hessian. The default forhessianisfalseifgray_boxis used, andtrueifvector_nonlinear_oracleis used.device: device used to construct PyTorch tensors, for example,"cuda"to run on an Nvidia GPU.
Compatibility
The vector_nonlinear_oracle feature is experimental. It relies on a private API feature of Ipopt.jl that will change in a future release.
If you use this feature, you must pin the version of Ipopt.jl in your Project.toml to ensure that future updates to Ipopt.jl do not break your existing code.
A known good version of Ipopt.jl is v1.8.0. Pin the version using:
[compat]
Ipopt = "=1.8.0"StatsModels
MathOptAI.add_predictor — Method
MathOptAI.add_predictor(
model::JuMP.AbstractModel,
predictor::StatsModels.TableRegressionModel,
x::DataFrames.DataFrame;
kwargs...,
)Add a trained regression model from StatsModels.jl to model, using the DataFrame x as input.
In most cases, predictor should be a GLM.jl predictor supported by MathOptAI, but trained using @formula and a DataFrame instead of the raw matrix input.
In general, x may have some columns that are constant (Float64) and some columns that are JuMP decision variables.
Keyword arguments
All keyword arguments are passed to the corresponding add_predictor of the GLM extension.
Example
julia> using DataFrames, GLM, JuMP, MathOptAI
julia> train_df = DataFrames.DataFrame(x1 = rand(10), x2 = rand(10));
julia> train_df.y = 1.0 .* train_df.x1 + 2.0 .* train_df.x2 .+ rand(10);
julia> predictor = GLM.lm(GLM.@formula(y ~ x1 + x2), train_df);
julia> model = Model();
julia> test_df = DataFrames.DataFrame(
x1 = rand(6),
x2 = @variable(model, [1:6]),
);
julia> test_df.y, _ = MathOptAI.add_predictor(model, predictor, test_df);
julia> test_df.y
6-element Vector{VariableRef}:
moai_Affine[1]
moai_Affine[1]
moai_Affine[1]
moai_Affine[1]
moai_Affine[1]
moai_Affine[1]Extensions
MathOptAI.add_variables — Function
add_variables(
model::JuMP.AbstractModel,
x::Vector,
n::Int,
base_name::String,
)::VectorAdd a vector of n variables to model with the base name base_name.
Extensions
This function is a hook for JuMP extensions to interact with MathOptAI.
Implement this method for subtypes of model and x as needed.
The default method is:
function add_variables(
model::JuMP.AbstractModel,
x::Vector,
n::Int,
base_name::String,
)
return JuMP.@variable(model, [1:n], base_name = base_name)
endMathOptAI.get_variable_bounds — Function
get_variable_bounds(x::JuMP.AbstractVariableRef)Return a tuple corresponding to the (lower, upper) variable bounds of x.
If there is no bound, the value returned is missing.
Extensions
This function is a hook for JuMP extensions to interact with MathOptAI.
Implement this method for subtypes of x as needed.
MathOptAI.set_variable_bounds — Function
set_variable_bounds(
cons::Vector{Any},
x::JuMP.AbstractVariableRef,
l::Any,
u::Any;
optional::Bool,
)Set the bounds on x to l and u, and push! their corresponding constraint references to cons.
If l or u are missing, do not set the bound.
If optional = true, you may choose to silently skip setting the bounds because they are not required for correctness.
The type of l and u depends on get_variable_bounds.
Extensions
This function is a hook for JuMP extensions to interact with MathOptAI.
Implement this method for subtypes of x as needed.
MathOptAI.get_variable_start — Function
get_variable_start(x::JuMP.AbstractVariableRef)Get the primal starting value of x, or return missing if one is not set.
The return value of this function is propogated through the various AbstractPredictors, and the primal start of new output variables is set using set_variable_start.
Extensions
This function is a hook for JuMP extensions to interact with MathOptAI.
Implement this method for subtypes of x as needed.
MathOptAI.set_variable_start — Function
set_variable_start(x::JuMP.AbstractVariableRef, start::Any)Set the primal starting value of x to start, or do nothing if start is missing.
The input value start of this function is computed by propogating the primal start of the input variables (obtained with get_variable_start) through the various AbstractPredictors.
Extensions
This function is a hook for JuMP extensions to interact with MathOptAI.
Implement this method for subtypes of x and start as needed.
replace_weights_with_variables
MathOptAI.replace_weights_with_variables — Function
replace_weights_with_variables(
model::JuMP.AbstractModel,
predictor::AbstractPredictor,
)Convert predictor with trained weights into a predictor in which the weights are JuMP decision variables.
This function is useful when you wish to use constrained optimization to train small to moderate neural networks.
This function is experimental and it may change in any future release. If you use this feature, please open a GitHub issue and let us know your thoughts.
Example
julia> using JuMP, Flux, MathOptAI
julia> chain = Flux.Chain(Flux.Dense(2 => 3), Flux.softmax);
julia> model = Model();
julia> @variable(model, x[i in 1:2] == i);
julia> predictor = MathOptAI.build_predictor(chain)
Pipeline with layers:
* Affine(A, b) [input: 2, output: 3]
* SoftMax()
julia> predictor = MathOptAI.replace_weights_with_variables(model, predictor)
Pipeline with layers:
* Affine(A, b) [input: 2, output: 3]
* SoftMax()
julia> y, _ = MathOptAI.add_predictor(model, predictor, x);