Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
- version: '1'
os: ubuntu-latest
arch: x64
- version: '1.6'
- version: '1.9'
os: ubuntu-latest
arch: x64
- version: '1.6'
- version: '1.9'
os: ubuntu-latest
arch: x86
steps:
Expand Down
9 changes: 7 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ authors = ["guilhermebodin <guilherme.b.moraes@gmail.com>"]
version = "0.5.9"

[deps]
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"

[weakdeps]
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"

[extensions]
DualizationJuMPExt = "JuMP"

[compat]
JuMP = "0.23, 1"
MathOptInterface = "1"
julia = "1.6"
julia = "1.9"
4 changes: 2 additions & 2 deletions docs/src/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Dualization.supported_constraints
Dualization.supported_objective
Dualization.DualNames
Dualization.VariableData
Dualization.ConstraintData
Dualization.PrimalVariableData
Dualization.PrimalConstraintData
Dualization.PrimalDualMap
```
149 changes: 149 additions & 0 deletions ext/DualizationJuMPExt/DualizationJuMPExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Copyright (c) 2017: Guilherme Bodin, and contributors
#
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

module DualizationJuMPExt

import Dualization
import JuMP
import MathOptInterface as MOI

function Dualization.dualize(
model::JuMP.Model,
optimizer_constructor = nothing;
kwargs...,
)
mode = JuMP.mode(model)
if mode != JuMP.AUTOMATIC
error("Dualization does not support solvers in $(mode) mode")
end
dual_model = JuMP.Model()
dual_problem = Dualization.DualProblem(JuMP.backend(dual_model))
Dualization.dualize(JuMP.backend(model), dual_problem; kwargs...)
_fill_obj_dict_with_variables!(dual_model)
_fill_obj_dict_with_constraints!(dual_model)
if optimizer_constructor !== nothing
JuMP.set_optimizer(dual_model, optimizer_constructor)
end
dual_model.ext[:_Dualization_jl_PrimalDualMap] =
dual_problem.primal_dual_map
return dual_model
end

function _fill_obj_dict_with_variables!(model::JuMP.Model)
list = MOI.get(model, MOI.ListOfVariableAttributesSet())
if !(MOI.VariableName() in list)
return
end
for vi in MOI.get(model, MOI.ListOfVariableIndices())
name = MOI.get(JuMP.backend(model), MOI.VariableName(), vi)
if !isempty(name)
model[Symbol(name)] = JuMP.VariableRef(model, vi)
end
end
return
end

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

function _fill_obj_dict_with_constraints!(
model::JuMP.Model,
::Type{F},
::Type{S},
) where {F,S}
list = MOI.get(model, MOI.ListOfConstraintAttributesSet{F,S}())
if !(MOI.ConstraintName() in list)
return
end
for ci in MOI.get(JuMP.backend(model), MOI.ListOfConstraintIndices{F,S}())
name = MOI.get(JuMP.backend(model), MOI.ConstraintName(), ci)
if !isempty(name)
model[Symbol(name)] = JuMP.constraint_ref_with_index(model, ci)
end
end
return
end

function _get_primal_dual_map(model::JuMP.Model)
return model.ext[:_Dualization_jl_PrimalDualMap]
end

function Dualization._get_dual_constraint(
dual_model,
primal_ref::JuMP.VariableRef,
)
map = _get_primal_dual_map(dual_model)
moi_primal_vi = JuMP.index(primal_ref)
moi_dual_ci, idx = Dualization._get_dual_constraint(map, moi_primal_vi)
# dual_model = nothing # TODO
if idx === nothing
# variables fixed at zero
return nothing, idx
end
return JuMP.constraint_ref_with_index(dual_model, moi_dual_ci), idx
end

function Dualization._get_primal_constraint(
dual_model::JuMP.Model,
primal_vi::JuMP.VariableRef,
)
primal_model = JuMP.owner_model(primal_vi)
map = _get_primal_dual_map(dual_model)
moi_primal_vi = JuMP.index(primal_vi)
primal_ci, idx = Dualization._get_primal_constraint(map, moi_primal_vi)
if primal_ci === nothing
return nothing, idx
end
return JuMP.constraint_ref_with_index(primal_model, primal_ci), idx
end

function Dualization._get_dual_variables(
dual_model::JuMP.Model,
primal_ref::JuMP.ConstraintRef,
)
map = _get_primal_dual_map(dual_model)
moi_primal_ci = JuMP.index(primal_ref)
moi_dual_vis = Dualization._get_dual_variables(map, moi_primal_ci)
if moi_dual_vis === nothing
# main constraint of a constrained variable
return nothing
end
return [JuMP.VariableRef(dual_model, vi) for vi in moi_dual_vis]
end

# this is a constrained variable constraint
function Dualization._get_dual_constraint(
dual_model::JuMP.Model,
primal_ref::JuMP.ConstraintRef,
)
map = _get_primal_dual_map(dual_model)
moi_primal_ci = JuMP.index(primal_ref)
moi_dual_ci = Dualization._get_dual_constraint(map, moi_primal_ci)
if moi_dual_ci === nothing
# main constraint of a constrained variable
# or
# primal constraint is equality
return nothing
end
return JuMP.constraint_ref_with_index(dual_model, moi_dual_ci)
end

function Dualization._get_dual_parameter(
dual_model::JuMP.Model,
primal_ref::JuMP.VariableRef,
)
map = _get_primal_dual_map(dual_model)
moi_primal_vi = JuMP.index(primal_ref)
moi_dual_vi = Dualization._get_dual_parameter(map, moi_primal_vi)
# the above line might error
return JuMP.VariableRef(dual_model, moi_dual_vi)
end

end # module DualizationJuMPExt
5 changes: 1 addition & 4 deletions src/Dualization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@

module Dualization

import JuMP
import LinearAlgebra
import MathOptInterface

const MOI = MathOptInterface
import MathOptInterface as MOI

include("structures.jl")
include("utils.jl")
Expand Down
10 changes: 5 additions & 5 deletions src/dual_equality_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ function _add_dual_equality_constraints(
end
# Add primal variable to dual contraint to the link dictionary
primal_dual_map.primal_variable_data[primal_vi] =
VariableData{T}(nothing, -1, dual_ci, nothing)
PrimalVariableData{T}(nothing, -1, dual_ci, nothing)
end
return scalar_affine_terms
end
Expand All @@ -139,7 +139,7 @@ function _add_constrained_variable_constraint(
sense_change * get(scalar_terms, vi, zero(T)),
)
primal_dual_map.primal_variable_data[vi] =
VariableData{T}(ci, i, nothing, dual_function)
PrimalVariableData{T}(ci, i, nothing, dual_function)
end
return
end
Expand Down Expand Up @@ -172,7 +172,7 @@ function _add_constrained_variable_constraint(
dual_ci = MOI.add_constraint(dual_model, func_dual, set_dual)
for (i, vi) in enumerate(vis)
primal_dual_map.primal_variable_data[vi] =
VariableData{T}(ci, i, dual_ci, nothing)
PrimalVariableData{T}(ci, i, dual_ci, nothing)
end
if !is_empty(dual_names)
@warn(
Expand All @@ -199,7 +199,7 @@ function _add_constrained_variable_constraint(
sense_change * get(scalar_terms, vi, zero(T)),
)
primal_dual_map.primal_variable_data[vi] =
VariableData{T}(ci, 0, nothing, dual_function)
PrimalVariableData{T}(ci, 0, nothing, dual_function)
return
end

Expand All @@ -226,7 +226,7 @@ function _add_constrained_variable_constraint(
set_dual,
)
primal_dual_map.primal_variable_data[vi] =
VariableData{T}(ci, 0, dual_ci, nothing)
PrimalVariableData{T}(ci, 0, dual_ci, nothing)
if !is_empty(dual_names)
_set_dual_constraint_name(
dual_model,
Expand Down
2 changes: 1 addition & 1 deletion src/dual_model_variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function _add_dual_variable(
T[]
end
primal_dual_map.primal_constraint_data[ci] =
ConstraintData(set_constant, vis, con_index)
PrimalConstraintData(set_constant, vis, con_index)
# Get constraint name
ci_name = MOI.get(primal_model, MOI.ConstraintName(), ci)
# Add each vi to the dictionary
Expand Down
59 changes: 0 additions & 59 deletions src/dualize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -207,62 +207,3 @@ function dualize(
end
return dual_problem
end

function dualize(model::JuMP.Model, optimizer_constructor = nothing; kwargs...)
mode = JuMP.mode(model)
if mode != JuMP.AUTOMATIC
error("Dualization does not support solvers in $(mode) mode")
end
dual_model = JuMP.Model()
dualize(
JuMP.backend(model),
DualProblem(JuMP.backend(dual_model));
kwargs...,
)
_fill_obj_dict_with_variables!(dual_model)
_fill_obj_dict_with_constraints!(dual_model)
if optimizer_constructor !== nothing
JuMP.set_optimizer(dual_model, optimizer_constructor)
end
return dual_model
end

function _fill_obj_dict_with_variables!(model::JuMP.Model)
list = MOI.get(model, MOI.ListOfVariableAttributesSet())
if !(MOI.VariableName() in list)
return
end
for vi in MOI.get(model, MOI.ListOfVariableIndices())
name = MOI.get(JuMP.backend(model), MOI.VariableName(), vi)
if !isempty(name)
model[Symbol(name)] = JuMP.VariableRef(model, vi)
end
end
return
end

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

function _fill_obj_dict_with_constraints!(
model::JuMP.Model,
::Type{F},
::Type{S},
) where {F,S}
list = MOI.get(model, MOI.ListOfConstraintAttributesSet{F,S}())
if !(MOI.ConstraintName() in list)
return
end
for ci in MOI.get(JuMP.backend(model), MOI.ListOfConstraintIndices{F,S}())
name = MOI.get(JuMP.backend(model), MOI.ConstraintName(), ci)
if !isempty(name)
model[Symbol(name)] = JuMP.constraint_ref_with_index(model, ci)
end
end
return
end
Loading
Loading