`BilevelJuMP.DUAL_OF_LOWER`

— ConstantIndicates and object that is part of the dual of the lower level problem, and is shared with the upper level.

`BilevelJuMP.LOWER_BOTH`

— ConstantIndicates and object that is part of the lower level problem, but is shared with the upper level.

`BilevelJuMP.LOWER_ONLY`

— ConstantIndicates and object that is part of the lower level problem, but is not shared with the upper level.

`BilevelJuMP.ONE_ONE`

— ConstantActivates the indicator constraint on the primal constraint if the auxiliaty binary is one and activates the indicator constraint on the dual variable if the auxiliary binary is one.

`BilevelJuMP.UPPER_BOTH`

— ConstantIndicates and object that is part of the upper level problem, but is shared with the lower level.

`BilevelJuMP.UPPER_ONLY`

— ConstantIndicates and object that is part of the upper level problem, but is not shared with the lower level.

`BilevelJuMP.ZERO_ONE`

— ConstantActivates the indicator constraint on the primal constraint if the auxiliaty binary is zero and activates the indicator constraint on the dual variable if the auxiliary binary is one.

`BilevelJuMP.ZERO_ZERO`

— ConstantActivates the indicator constraint on the primal constraint if the auxiliaty binary is zero and activates the indicator constraint on the dual variable if the auxiliary binary is zero.

`BilevelJuMP.BigMMode`

— Type`BigMMode(; with_slack = false, primal_big_M = Inf, dual_big_M = Inf)`

Used to solve a bilevel problem with the MPEC reformulation using Fortuny-Amat and McCarl's big-M method to convert complementarity constraints to a mixed integer formulation.

`with_slack`

indicates whether to use slack variables to convert the complementarity constraints to a mixed integer formulation. If`false`

, the reformulation of a constraint like`expr <= 0`

is`expr <= big_M * (1 - binary)`

and`var <= big_M * binary`

, where`var`

is the associated dual variable. If`true`

, the reformulation is`expr == slack`

,`slack <= big_M * (1 - binary)`

and`var <= big_M * binary`

.`primal_big_M`

is a big-M used to primal variables that have no bounds so we can compute the big-M for the primal constraint.`dual_big_M`

is a big-M used to dual variables that have no bounds so we can compute the big-M for the dual constraint.

Also known as `FortunyAmatMcCarlMode`

(which can be used interchangeably).

`BilevelJuMP.BilevelAffExpr`

— Type`BilevelVariableRef`

Alias for `GenericAffExpr{Float64,BilevelVariableRef}`

.

`BilevelJuMP.BilevelModel`

— Type`BilevelModel()`

Create an empty BilevelModel with default settings, no `solver`

and no solve `mode`

.

**Example**

`julia> model = BilevelModel()`

`BilevelModel(solver::Function; mode = BilevelJuMP.SOS1Mode(), add_bridges::Bool = true)`

Create a BilevelModel with the given `solver`

and solve `mode`

.

`solver`

: is a functions that takes no arguments and returns a JuMP solver object.`mode`

: is a solve mode object that defines how the model is solved.`add_bridges`

: if`true`

(default) then bridges are added to the model. If`false`

then bridges are not added and the model is not modified.

**Example**

```
julia> model = BilevelModel(
HiGHS.Optimizer,
mode = BilevelJuMP.FortunyAmatMcCarlMode(primal_big_M = 1e6, dual_big_M = 1e6))
```

which is equivalent to

```
julia> model = BilevelModel(
()->HiGHS.Optimizer(),
mode = BilevelJuMP.FortunyAmatMcCarlMode(primal_big_M = 1e6, dual_big_M = 1e6))
```

and equivalent to

```
julia> model = BilevelModel()
julia> BilevelJuMP.set_solver(model, HiGHS.Optimizer)
julia> BilevelJuMP.set_mode(model, BilevelJuMP.FortunyAmatMcCarlMode(primal_big_M = 1e6, dual_big_M = 1e6))
```

`BilevelJuMP.BilevelQuadExpr`

— Type`BilevelQuadExpr`

Alias for `GenericQuadExpr{Float64,BilevelVariableRef}`

.

`BilevelJuMP.BilevelVariableRef`

— Type`BilevelVariableRef`

Holds a reference to a variable in a bilevel model.

`BilevelJuMP.ComplementMode`

— Type`ComplementMode(; with_slack = false)`

Used to solve a bilevel problem with the MPEC reformulation using actual complementarity constraints. A limited number of solvers support this mode. One example is Knitro.

`with_slack`

indicates whether to use slack variables to reformulate the complementarity constraints. Given a pair`expr`

and`var`

, the reformulation is`expr == slack`

and`var ⟂ slack`

instead of`expr ⟂ slack`

.

`BilevelJuMP.DualOf`

— Type`DualOf(constraint::ConstraintRef)`

Get the dual variable associated with a constraint. This is only valid for constraints in the upper level of a bilevel model.

**Examples**

```
julia> m = BilevelModel();
julia> @variable(Lower(m), x >= 0);
julia> @constraint(Lower(m), c, x <= 1);
julia> @variable(Upper(m), y, DualOf(c));
```

`BilevelJuMP.FortunyAmatMcCarlMode`

— Type`FortunyAmatMcCarlMode`

See `BigMMode`

for more details.

`BilevelJuMP.IndicatorMode`

— Type`IndicatorMode(method::IndicatorSetting = BilevelJuMP.ONE_ONE)`

Used to solve a bilevel problem with the MPEC reformulation using indicator constaints to convert complementarity constraints to a mixed integer formulation.

`method`

indicates how the indicator constraints are activated for primal cosntraints and dual variables. See`IndicatorSetting`

for more details.

`BilevelJuMP.IndicatorSetting`

— Type`IndicatorSetting`

The type of indicator function to use in the `IndicatorMode`

mode.

`BilevelJuMP.Level`

— Type`Level`

The level of a variable in a bilevel problem.

`BilevelJuMP.MixedMode`

— Type`MixedMode(; default = SOS1Mode())`

A mode that allows to mix different modes for different constraints and variables.

`default`

is the default mode to use for all constraints and variables that are not explicitly mapped to a mode.

`BilevelJuMP.ProductMode`

— Type`ProductMode(epsilon = 0.0; with_slack = false, aggregation_group = nothing)`

Used to solve a bilevel problem with the MPEC reformulation using products to convert complementarity constraints into non-convex quadratic constraints.

`with_slack`

indicates whether to use slack variables to reformulate the complementarity constraints. Given a pair`expr`

and`var`

, the reformulation is`expr == slack`

and`var * slack == 0`

instead of`expr * slack == 0`

.`aggregation_group`

indicates whether to aggregate the products into a single quadratic constraint. If`aggregation_group`

is`nothing`

, then each product is converted into a quadratic constraint. If`aggregation_group`

is a positive integer, then products with the same`aggregation_group`

are aggregated into a single quadratic constraint.

`BilevelJuMP.SOS1Mode`

— Type`SOS1Mode()`

Used to solve a bilevel problem with the MPEC reformulation using SOS1 constraints to convert complementarity constraints into mixed-integer constraints.

`BilevelJuMP.StrongDualityMode`

— Type`StrongDualityMode(eps = 0.0, inequality = true)`

A mode that adds a strong duality constraint of the lower level problem instead of reformulating the complementarity constraints.

`eps`

: The tolerance for the strong duality constraint. Defaults to`0.0`

.`inequality`

: If`true`

the strong duality constraint is added as two inequality constraints. If`false`

the strong duality constraint is added as an equality constraint. Defaults to`true`

.

`BilevelJuMP.Lower`

— Method`Lower(model::BilevelModel)`

Create a reference to the lower level of a bilevel model.

**Example**

```
julia> model = BilevelModel();
julia> @variable(Lower(model), x >= 0)
```

`BilevelJuMP.LowerOnly`

— Method`LowerOnly(model::BilevelModel)`

Create a special reference to the lower level of a bilevel model. Variables created with this reference will not be shared with the upper level.

`BilevelJuMP.Upper`

— Method`Upper(model::BilevelModel)`

Create a reference to the upper level of a bilevel model.

**Example**

```
julia> model = BilevelModel();
julia> @variable(Upper(model), x >= 0)
```

`BilevelJuMP.UpperOnly`

— Method`UpperOnly(model::BilevelModel)`

Create a special reference to the upper level of a bilevel model. Variables created with this reference will not be shared with the lower level.

`BilevelJuMP.build_time`

— Method`build_time(model::BilevelModel)`

Return the time it took to build the model.

`BilevelJuMP.get_copy_names`

— Method`get_copy_names(model::BilevelModel)`

Return the value of the `copy_names`

attribute of the solver.

`BilevelJuMP.get_dual_lower_bound_hint`

— Method`get_dual_lower_bound_hint(cref)`

Get the lower bound to the dual variable of the constraint `cref`

that was set with `set_dual_lower_bound_hint`

.

`BilevelJuMP.get_dual_upper_bound_hint`

— Method`get_dual_upper_bound_hint(cref)`

Get the upper bound to the dual variable of the constraint `cref`

that was set with `set_dual_upper_bound_hint`

.

`BilevelJuMP.get_mode`

— Method`get_mode(vi::BilevelVariableRef)`

Get the mode of the bounds of a variable. This is used in `MixedMode`

reformulations.

`BilevelJuMP.get_mode`

— Method`get_mode(ci::BilevelConstraintRef)`

Get the mode of a constraint. This is used in `MixedMode`

reformulations.

`BilevelJuMP.get_pass_start`

— Method`get_pass_start(model::BilevelModel)`

Checks if passing start values (both primal and dual) to the solver is activated.

`BilevelJuMP.get_primal_lower_bound_hint`

— Method`get_primal_lower_bound_hint(cref)`

Get the lower bound to the primal variable of the constraint `cref`

that was set with `set_primal_lower_bound_hint`

.

`BilevelJuMP.get_primal_upper_bound_hint`

— Method`get_primal_upper_bound_hint(cref)`

Get the upper bound to the primal variable of the constraint `cref`

that was set with `set_primal_upper_bound_hint`

.

`BilevelJuMP.lower_objective_value`

— Method`lower_objective_value(model::BilevelModel; result::Int = 1)`

Return the value of the objective function of the lower level problem.

`BilevelJuMP.set_copy_names`

— Method`set_copy_names(model::BilevelModel)`

Set the `copy_names`

attribute of the solver to `true`

.

`BilevelJuMP.set_dual_lower_bound_hint`

— Method`set_dual_lower_bound_hint(cref, value)`

Set a lower bound to the dual variable of the constraint `cref`

to `value`

. This bound will not be dualized. The dual lower bound hint is used to help the solution method.

Solution `mode`

s can be benefitted from this hint:

`BigMMode`

will use this information to compute a tighter bound for the dual variable.Other modes will be stabilized by the existence of the bounds on variables that would otherwise no be bounded.

Bounds that are not dualized are also useful for binary expansions of products of variables that can be done with

`QuadraticToBinary.jl`

.

`BilevelJuMP.set_dual_upper_bound_hint`

— Method`set_dual_upper_bound_hint(cref, value)`

Set a upper bound to the dual variable of the constraint `cref`

to `value`

. This bound will not be dualized. The dual upper bound hint is used to help the solution method.

Solution `mode`

s can be benefitted from this hint:

`BigMMode`

will use this information to compute a tighter bound for the dual variable.Other modes will be stabilized by the existence of the bounds on variables that would otherwise no be bounded.

Bounds that are not dualized are also useful for binary expansions of products of variables that can be done with

`QuadraticToBinary.jl`

.

`BilevelJuMP.set_mode`

— Method`set_mode(bm::BilevelModel, mode::AbstractBilevelSolverMode)`

Set the mode of a bilevel model.

`BilevelJuMP.set_mode`

— Method`set_mode(vi::BilevelVariableRef, mode::AbstractBilevelSolverMode)`

Set the mode of the bounds of a variable. This is used in `MixedMode`

reformulations.

`BilevelJuMP.set_mode`

— Method`set_mode(ci::BilevelVariableRef, mode::AbstractBilevelSolverMode)`

Set the mode of a constraint. This is used in `MixedMode`

reformulations.

`BilevelJuMP.set_pass_start`

— Method`set_pass_start(model::BilevelModel)`

Activate passing start values (both primal and dual) to the solver.

`BilevelJuMP.set_primal_lower_bound_hint`

— Method`set_primal_lower_bound_hint(vref, value)`

Set a lower bound to the prima variable `vref`

to `value`

. This bound will not be dualized. The lower bound hint is used to help the solution method.

Solution `mode`

s can be benefitted from this hint:

`BigMMode`

will use this information to compute a tighter bound for the primal constraint variable.Other modes will be stabilized by the existence of the bounds on variables that would otherwise no be bounded.

Bounds that are not dualized are also useful for binary expansions of products of variables that can be done with

`QuadraticToBinary.jl`

.

`BilevelJuMP.set_primal_upper_bound_hint`

— Method`set_primal_upper_bound_hint(vref, value)`

Set a upper bound to the prima variable `vref`

to `value`

. This bound will not be dualized. The upper bound hint is used to help the solution method.

Solution `mode`

s can be benefitted from this hint:

`BigMMode`

will use this information to compute a tighter bound for the primal constraint variable.`QuadraticToBinary.jl`

.

`BilevelJuMP.solve_with_MibS`

— Method`solve_with_MibS(model::BilevelModel, mibs_call; kwargs...)`

**Inputs**

`model::BilevelModel`

: the model to optimize`mibs_call`

: shoul be`MibS_jll.mibs`

remember to`import MibS_jll`

before.`verbose_results::Bool = false`

: controls the verbosity of the solver output.

If `verbose_results=false`

, nothing is printed. Set to `true`

to display the MibS output.

`verbose_file::Bool = false`

: Writes MibS input files to screen.`keep_files::Bool = false`

: Saves MibS input files to pwd().

**Outputs**

This function returns a `NamedTuple`

with fields:

`status::Bool`

:`true`

if the problem is feasible and has an optimal solution.`false`

otherwise.`objective::Float64`

: objective value (cost) of the upper problem`nonzero_upper::Dict{Int, Float64}`

: it returns`Dict{index => value}`

, in which the`index`

refers to the index of upper variables with non zero values and the index starts from`0`

. Here, the order of the variables is based on their order of appearance in the MPS file.`nonzero_lower::Dict{Int, Float64}`

: it has the same structure as`nonzero_upper`

, but it represents the index of non-zero variables in the lower problem.`all_upper::Dict{String, Float64}`

: it returns`Dict{name => value}`

which contains all upper variables values (zero and non-zero). For recalling the variables, you need to use the same name as you used to define the variables, e.g., for`@variable(Upper(model), y, Int)`

, we need to use`all_upper["y"]`

to get the value of the variable`y`

.`all_lower::Dict{String, Float64}`

: it has the same structure as the`all_upper`

but is defined for lower variables.`all_var::Dict{MOI.VariableIndex, Float64}`

: it contains information on all variables (upper and lower) in the format of`MOI.VariableIndex`

and their output values.

Currently, `MibS`

is designed to solve MIP-MIP problems only. Thus, if you define LP-MIP, MIP-LP, or LP-LP, it will throw an error.

`BilevelJuMP.split_variable`

— MethodSplit variable because actual owner of the variable should be the one holding the bounds.

`BilevelJuMP.unset_copy_names`

— Method`unset_copy_names(model::BilevelModel)`

Set the `copy_names`

attribute of the solver to `false`

.

`BilevelJuMP.unset_mode`

— Method`unset_mode(vi::BilevelVariableRef)`

Unset the mode of the bounds of a variable. This will use the default mode for the bounds. This is used in `MixedMode`

reformulations.

`BilevelJuMP.unset_mode`

— Method`unset_mode(ci::BilevelConstraintRef)`

Unset the mode of a constraint. This will use the default mode for the constraint. This is used in `MixedMode`

reformulations.

`BilevelJuMP.unset_pass_start`

— Method`unset_pass_start(model::BilevelModel)`

Deactivate passing start values (both primal and dual) to the solver.