@@ -82,6 +82,46 @@ struct _LazyData{F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet}
8282 end
8383end
8484
85+ # ## Algorithm
86+
87+ """
88+ Algorithm() <: MOI.AbstractOptimizerAttribute
89+
90+ An `MOI.AbstractOptimizerAttribute` to control which algorithm we use to solve
91+ the lazy constraints.
92+
93+ Supported values are
94+
95+ * `Iterative()` [default]
96+ * `Callback()`
97+ """
98+ struct Algorithm <: MOI.AbstractOptimizerAttribute end
99+
100+ abstract type AbstractAlgorithm end
101+
102+ """
103+ Iterative()
104+
105+ This algorithm iteratively solves a sequence of problems that iteratively add
106+ violated lazy constraints to the main problem.
107+
108+ This algorithm works for all problem types, including continuous problems with
109+ no discrete variables. The downside is that it may not re-use information
110+ between solves.
111+ """
112+ struct Iterative <: AbstractAlgorithm end
113+
114+ """
115+ Callback()
116+
117+ This algorithm uses a `MOI.LazyConstraintCallback` to add violated laz
118+ constraints to the main problem.
119+
120+ This algorithm works only for problems with discrete variables and only if the
121+ solver supports `MOI.LazyConstraintCallback`.
122+ """
123+ struct Callback <: AbstractAlgorithm end
124+
85125# ## Optimizer
86126
87127"""
@@ -112,17 +152,34 @@ MathOptLazy.Optimizer{Float64, MOIB.LazyBridgeOptimizer{HiGHS.Optimizer}}
112152└ NumberOfConstraints: 0
113153```
114154"""
115- struct Optimizer{OT} <: MOI.AbstractOptimizer
155+ mutable struct Optimizer{OT<: MOI.ModelLike } <: MOI.AbstractOptimizer
116156 inner:: OT
117-
157+ algorithm :: AbstractAlgorithm
118158 lazy:: Dict{Tuple{Type,Type},_LazyData}
119159
120160 function Optimizer (inner_fn; kwargs... )
121161 inner = MOI. instantiate (inner_fn; kwargs... )
122- return new {typeof(inner)} (inner, Dict {Tuple{Type,Type},_LazyData} ())
162+ return new {typeof(inner)} (
163+ inner,
164+ Iterative (),
165+ Dict {Tuple{Type,Type},_LazyData} (),
166+ )
123167 end
124168end
125169
170+ # ## Algorithm
171+
172+ MOI. supports (:: Optimizer , :: Algorithm ) = true
173+
174+ MOI. get (model:: Optimizer , :: Algorithm ) = model. algorithm
175+
176+ function MOI. set (model:: Optimizer , :: Algorithm , value:: AbstractAlgorithm )
177+ model. algorithm = value
178+ return
179+ end
180+
181+ MOI. Utilities. map_indices (:: Function , algorithm:: AbstractAlgorithm ) = algorithm
182+
126183# ## Fallbacks
127184
128185function MOI. empty! (model:: Optimizer )
407464
408465# ## MOI.optimize!
409466
410- function MOI. optimize! (model:: Optimizer )
467+ MOI. optimize! (model:: Optimizer ) = _optimize! (model, model. algorithm)
468+
469+ function _optimize! (model:: Optimizer , :: Iterative )
411470 needs_solve = true
412471 x = MOI. get (model, MOI. ListOfVariableIndices ())
413472 # TODO (odow): if the solver supports VariablePrimalStart, we will update the
@@ -481,4 +540,34 @@ function _add_if_feasible(
481540 return needs_solve
482541end
483542
543+ function _optimize! (model:: Optimizer , :: Callback )
544+ function callback (cb_data)
545+ x = MOI. get (model, MOI. ListOfVariableIndices ())
546+ X = Dict (
547+ xi => MOI. get (model. inner, MOI. CallbackVariablePrimal (cb_data), xi) for xi in x
548+ )
549+ # We don't check `.is_active` in this loop because callbacks are weird.
550+ # In some solvers, callbacks may be called at a point that was
551+ # previously cut off because the added cut was later removed. The only
552+ # guarantee is that the solver won't terminate until this loop produces
553+ # no new cuts.
554+ for data in values (model. lazy)
555+ for (i, (f, s)) in enumerate (data. data)
556+ y = MOI. Utilities. eval_variables (
557+ Base. Fix1 (getindex, X),
558+ model. inner,
559+ f,
560+ )
561+ if MOI. Utilities. distance_to_set (y, s) > 0
562+ MOI. submit (model. inner, MOI. LazyConstraint (cb_data), f, s)
563+ end
564+ end
565+ end
566+ return
567+ end
568+ MOI. set (model. inner, MOI. LazyConstraintCallback (), callback)
569+ MOI. optimize! (model. inner)
570+ return
571+ end
572+
484573end # module MathOptLazy
0 commit comments