Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for JuMP 0.22 and MOI 0.10 #127

Merged
merged 7 commits into from
Jan 7, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
name = "Dualization"
uuid = "191a621a-6537-11e9-281d-650236a99e60"
authors = ["guilhermebodin <guilherme.b.moraes@gmail.com>"]
version = "0.3.5"
version = "0.4.0"

[deps]
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"

[compat]
JuMP = "0.21"
MathOptInterface = "0.9"
JuMP = "0.22"
MathOptInterface = "0.10"
julia = "1"

[extras]
8 changes: 4 additions & 4 deletions docs/src/manual.md
Original file line number Diff line number Diff line change
@@ -110,9 +110,9 @@ a constraint not listed here, it will return an unsupported error.

| MOI Function | MOI Set |
|:-------|:---------------|
| `SingleVariable` | `GreaterThan` |
| `SingleVariable` | `LessThan` |
| `SingleVariable` | `EqualTo` |
| `VariableIndex` | `GreaterThan` |
| `VariableIndex` | `LessThan` |
| `VariableIndex` | `EqualTo` |
| `ScalarAffineFunction` | `GreaterThan` |
| `ScalarAffineFunction` | `LessThan` |
| `ScalarAffineFunction` | `EqualTo` |
@@ -143,7 +143,7 @@ Note that some of MOI constraints can be bridged, see [Bridges](http://jump.dev/

| MOI Function |
|:-------:|
| `SingleVariable` |
| `VariableIndex` |
| `ScalarAffineFunction` |

## Dualize a model
6 changes: 2 additions & 4 deletions src/Dualization.jl
Original file line number Diff line number Diff line change
@@ -5,16 +5,14 @@ const MOI = MathOptInterface
const MOIU = MathOptInterface.Utilities
const MOIB = MathOptInterface.Bridges

const SVF = MOI.SingleVariable
const VI = MOI.VariableIndex
const CI = MOI.ConstraintIndex
const VVF = MOI.VectorOfVariables
const SAF{T} = MOI.ScalarAffineFunction{T}
const VAF{T} = MOI.VectorAffineFunction{T}
const SQF{T} = MOI.ScalarQuadraticFunction{T}
const VQF{T} = MOI.VectorQuadraticFunction{T}

const VI = MOI.VariableIndex
const CI = MOI.ConstraintIndex

include("structures.jl")
include("utils.jl")
include("dual_sets.jl")
10 changes: 5 additions & 5 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ function MOI.supports(
optimizer::DualOptimizer{T},
::MOI.ObjectiveFunction{F},
) where {T,F}
# If the objective function is `MOI.SingleVariable` or `MOI.ScalarAffineFunction`,
# If the objective function is `MOI.VariableIndex` or `MOI.ScalarAffineFunction`,
# a `MOI.ScalarAffineFunction` is set as objective function for the dual problem.
# If it is `MOI.ScalarQuadraticFunction` , a `MOI.ScalarQuadraticFunction` is set as objective function for the dual problem.
G =
@@ -83,7 +83,7 @@ end

function MOI.supports_constraint(
optimizer::DualOptimizer{T},
F::Type{<:Union{MOI.SingleVariable,MOI.ScalarAffineFunction{T}}},
F::Type{<:Union{MOI.VariableIndex,MOI.ScalarAffineFunction{T}}},
S::Type{<:MOI.AbstractScalarSet},
) where {T}
D = _dual_set_type(S)
@@ -210,7 +210,7 @@ function MOI.copy_to(dest::DualOptimizer, src::MOI.ModelLike; kwargs...)
setindex!(idx_map, vi, vi)
end

for (F, S) in MOI.get(src, MOI.ListOfConstraints())
for (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent())
for con in MOI.get(src, MOI.ListOfConstraintIndices{F,S}())
setindex!(idx_map, con, con)
end
@@ -267,7 +267,7 @@ end
function _get(
::DualOptimizer{T},
::MOI.AbstractConstraintAttribute,
::MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{T}},
::MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{T}},
::MOI.ConstraintIndex{Nothing,Nothing},
) where {T}
return zero(T)
@@ -295,7 +295,7 @@ end
function _get_at_index(
optimizer::DualOptimizer,
attr::MOI.AbstractConstraintAttribute,
ci_primal::MOI.ConstraintIndex{MOI.SingleVariable},
ci_primal::MOI.ConstraintIndex{MOI.VariableIndex},
ci_dual::MOI.ConstraintIndex,
idx,
)
12 changes: 6 additions & 6 deletions src/constrained_variables.jl
Original file line number Diff line number Diff line change
@@ -6,15 +6,15 @@ function add_constrained_variables(
single_or_vector_variables_types =
MOIU.sorted_variable_sets_by_cost(dual_problem.dual_model, primal_model)
params = Set(variable_parameters)
for (F, S) in single_or_vector_variables_types
if F === MOI.VectorOfVariables
for S in single_or_vector_variables_types
if S <: MOI.AbstractVectorSet
_add_constrained_variables(
dual_problem.primal_dual_map,
primal_model,
S,
params,
)
elseif F === MOI.SingleVariable
elseif S <: MOI.AbstractScalarSet
_add_constrained_variable(
dual_problem.primal_dual_map,
primal_model,
@@ -59,16 +59,16 @@ function _add_constrained_variable(
) where {S<:MOI.AbstractScalarSet}
cis = MOI.get(
primal_model,
MOI.ListOfConstraintIndices{MOI.SingleVariable,S}(),
MOI.ListOfConstraintIndices{MOI.VariableIndex,S}(),
)
for ci in cis
f = MOI.get(primal_model, MOI.ConstraintFunction(), ci)
if !haskey(m.constrained_var_idx, f.variable) && !(f.variable in params)
if !haskey(m.constrained_var_idx, f) && !(f in params)
set = MOI.get(primal_model, MOI.ConstraintSet(), ci)
if !iszero(MOI.constant(set))
continue
end
m.constrained_var_idx[f.variable] = (ci, 1)
m.constrained_var_idx[f] = (ci, 1)
# Placeholder to indicate this constraint is part of constrained variables,
# it will be replaced later with a dual constraints
m.constrained_var_dual[ci] = CI{Nothing,Nothing}(0)
42 changes: 21 additions & 21 deletions src/dual_equality_constraints.jl
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ function add_dual_equality_constraints(
primal_dual_map::PrimalDualMap,
dual_names::DualNames,
primal_objective::PrimalObjective{T},
con_types::Vector{Tuple{DataType,DataType}},
con_types::Vector{Tuple{Type,Type}},
variable_parameters::Vector{VI},
) where {T}
sense_change =
@@ -141,15 +141,15 @@ function _add_constrained_variable_constraint(
primal_model,
zero_map,
ci_map,
ci::MOI.ConstraintIndex{MOI.SingleVariable,<:MOI.EqualTo},
ci::MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.EqualTo},
scalar_affine_terms,
scalar_terms,
sense_change,
::Type{T},
) where {T}
# Nothing to add as the set is `EqualTo`.
func_primal = MOI.get(primal_model, MOI.ConstraintFunction(), ci)
primal_vi = func_primal.variable
primal_vi = func_primal
return zero_map[ci] = MOI.ScalarAffineFunction(
MOIU.operate_terms(-, scalar_affine_terms[primal_vi]),
sense_change * get(scalar_terms, primal_vi, zero(T)),
@@ -160,14 +160,14 @@ function _add_constrained_variable_constraint(
primal_model,
zero_map,
ci_map,
ci::MOI.ConstraintIndex{MOI.SingleVariable},
ci::MOI.ConstraintIndex{MOI.VariableIndex},
scalar_affine_terms,
scalar_terms,
sense_change,
::Type{T},
) where {T}
func_primal = MOI.get(primal_model, MOI.ConstraintFunction(), ci)
primal_vi = func_primal.variable
primal_vi = func_primal
func_dual = MOI.ScalarAffineFunction(
MOIU.operate_terms(-, scalar_affine_terms[primal_vi]),
sense_change * get(scalar_terms, primal_vi, zero(T)),
@@ -185,23 +185,23 @@ function add_scalar_affine_terms_from_quad_obj(
primal_objective::PrimalObjective{T},
) where {T}
for term in primal_objective.obj.quadratic_terms
if term.variable_index_1 == term.variable_index_2
dual_vi = primal_var_dual_quad_slack[term.variable_index_1]
if term.variable_1 == term.variable_2
dual_vi = primal_var_dual_quad_slack[term.variable_1]
push_to_scalar_affine_terms!(
scalar_affine_terms[term.variable_index_1],
scalar_affine_terms[term.variable_1],
-MOI.coefficient(term),
dual_vi,
)
else
dual_vi_1 = primal_var_dual_quad_slack[term.variable_index_1]
dual_vi_1 = primal_var_dual_quad_slack[term.variable_1]
push_to_scalar_affine_terms!(
scalar_affine_terms[term.variable_index_2],
scalar_affine_terms[term.variable_2],
-MOI.coefficient(term),
dual_vi_1,
)
dual_vi_2 = primal_var_dual_quad_slack[term.variable_index_2]
dual_vi_2 = primal_var_dual_quad_slack[term.variable_2]
push_to_scalar_affine_terms!(
scalar_affine_terms[term.variable_index_1],
scalar_affine_terms[term.variable_1],
-MOI.coefficient(term),
dual_vi_2,
)
@@ -216,7 +216,7 @@ function add_scalar_affine_terms_from_quad_params(
) where {T}
for (key, val) in primal_objective.quad_cross_parameters
for term in val
dual_vi = primal_parameter[term.variable_index]
dual_vi = primal_parameter[term.variable]
push_to_scalar_affine_terms!(
scalar_affine_terms[key],
-MOI.coefficient(term),
@@ -245,10 +245,10 @@ end
function get_scalar_terms(primal_objective::PrimalObjective{T}) where {T}
scalar_terms = Dict{VI,T}()
for term in get_affine_terms(primal_objective)
if haskey(scalar_terms, term.variable_index)
scalar_terms[term.variable_index] += MOI.coefficient(term)
if haskey(scalar_terms, term.variable)
scalar_terms[term.variable] += MOI.coefficient(term)
else
scalar_terms[term.variable_index] = MOI.coefficient(term)
scalar_terms[term.variable] = MOI.coefficient(term)
end
end
return scalar_terms
@@ -276,7 +276,7 @@ function get_scalar_affine_terms(
primal_model::MOI.ModelLike,
primal_con_dual_var::Dict{CI,Vector{VI}},
variables::Vector{VI},
con_types::Vector{Tuple{DataType,DataType}},
con_types::Vector{Tuple{Type,Type}},
::Type{T},
) where {T}
scalar_affine_terms = Dict{VI,Vector{MOI.ScalarAffineTerm{T}}}(
@@ -315,7 +315,7 @@ function fill_scalar_affine_terms!(
for term in moi_function.terms
dual_vi = primal_con_dual_var[ci][1] # In this case we only have one vi
push_to_scalar_affine_terms!(
scalar_affine_terms[term.variable_index],
scalar_affine_terms[term.variable],
MOI.coefficient(term),
dual_vi,
)
@@ -327,7 +327,7 @@ function fill_scalar_affine_terms!(
scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}},
primal_con_dual_var::Dict{CI,Vector{VI}},
primal_model::MOI.ModelLike,
ci::CI{SVF,S},
ci::CI{VI,S},
) where {T,S<:Union{MOI.GreaterThan{T},MOI.LessThan{T},MOI.EqualTo{T}}}
dual_var = get(primal_con_dual_var, ci, nothing)
if dual_var === nothing
@@ -336,7 +336,7 @@ function fill_scalar_affine_terms!(
moi_function = get_function(primal_model, ci)
dual_vi = dual_var[1] # In this case we only have one vi
push_to_scalar_affine_terms!(
scalar_affine_terms[moi_function.variable],
scalar_affine_terms[moi_function],
one(T),
dual_vi,
)
@@ -356,7 +356,7 @@ function fill_scalar_affine_terms!(
# term.output_index is the row of the VAF,
# it corresponds to the dual variable associated with this constraint
push_to_scalar_affine_terms!(
scalar_affine_terms[term.scalar_term.variable_index],
scalar_affine_terms[term.scalar_term.variable],
set_dot(term.output_index, set, T) * MOI.coefficient(term),
dual_vi,
)
8 changes: 4 additions & 4 deletions src/dual_model_variables.jl
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ function add_dual_vars_in_dual_cones(
) where {T,F,S}
for ci in MOI.get(primal_model, MOI.ListOfConstraintIndices{F,S}()) # Constraints of type {F, S}
# If `F` not one of these two, we can skip the `in` check.
if (F === MOI.VectorOfVariables || F === MOI.SingleVariable) &&
if (F === MOI.VectorOfVariables || F === MOI.VariableIndex) &&
haskey(primal_dual_map.constrained_var_dual, ci)
continue
end
@@ -43,7 +43,7 @@ function add_dual_vars_in_dual_cones(
primal_model::MOI.ModelLike,
primal_dual_map::PrimalDualMap{T},
dual_names::DualNames,
con_types::Vector{Tuple{DataType,DataType}},
con_types::Vector{Tuple{Type,Type}},
) where {T}
dual_obj_affine_terms = Dict{VI,T}()
for (F, S) in con_types
@@ -184,7 +184,7 @@ function add_primal_parameter_vars(
added = Set{VI}()
for vec in values(primal_objective.quad_cross_parameters)
for term in vec
ind = term.variable_index
ind = term.variable
if ind in added
# do nothing
else
@@ -271,7 +271,7 @@ function add_quadratic_slack_vars(
# are required
added = Set{VI}()
for term in primal_objective.obj.quadratic_terms
for ind in [term.variable_index_1, term.variable_index_2]
for ind in [term.variable_1, term.variable_2]
if ind in added
#do nothing
else
14 changes: 7 additions & 7 deletions src/dualize.jl
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ function dualize(
ignore_objective::Bool = false,
)
# Creates an empty dual problem
dual_problem = DualProblem{Float64}()
dual_problem = Dualization.DualProblem{Float64}()
return dualize(
primal_model,
dual_problem,
@@ -43,18 +43,18 @@ function dualize(
ignore_objective::Bool,
) where {T}
# Throws an error if objective function cannot be dualized
supported_objective(primal_model)
Dualization.supported_objective(primal_model)

# Query all constraint types of the model
con_types = MOI.get(primal_model, MOI.ListOfConstraints())
supported_constraints(con_types) # Throws an error if constraint cannot be dualized
con_types = MOI.get(primal_model, MOI.ListOfConstraintTypesPresent())
Dualization.supported_constraints(con_types) # Throws an error if constraint cannot be dualized

# Set the dual model objective sense
set_dual_model_sense(dual_problem.dual_model, primal_model)
Dualization.set_dual_model_sense(dual_problem.dual_model, primal_model)

# Get Primal Objective Coefficients
primal_objective =
get_primal_objective(primal_model, variable_parameters, T)
Dualization.get_primal_objective(primal_model, variable_parameters, T)

add_constrained_variables(dual_problem, primal_model, variable_parameters)

@@ -204,7 +204,7 @@ function fill_obj_dict_with_variables!(model::JuMP.Model)
end

function fill_obj_dict_with_constraints!(model::JuMP.Model)
con_types = MOI.get(model, JuMP.MOI.ListOfConstraints())
con_types = MOI.get(model, JuMP.MOI.ListOfConstraintTypesPresent())
for (F, S) in con_types
fill_obj_dict_with_constraints!(model, F, S)
end
Loading