diff --git a/Project.toml b/Project.toml index 1a65e91..e77f558 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Dualization" uuid = "191a621a-6537-11e9-281d-650236a99e60" authors = ["guilhermebodin "] -version = "0.3.3" +version = "0.3.4" [deps] JuMP = "4076af6c-e467-56ae-b986-b466b2749572" diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 1d3e57e..a9bdf5e 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -80,7 +80,7 @@ end function MOI.supports_constraint( optimizer::DualOptimizer{T}, - F::Type{<:Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T}}}, + ::Type{<:Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T}}}, S::Type{<:MOI.AbstractVectorSet}) where T D = _dual_set_type(S) if D === nothing @@ -89,6 +89,21 @@ function MOI.supports_constraint( return MOI.supports_add_constrained_variables(optimizer.dual_problem.dual_model, D) end +function MOI.modify(optimizer::DualOptimizer{T}, + ::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}, + obj_change::MOI.ScalarCoefficientChange{T}) where T + # We must find the constraint corresponding to the variable in the objective + # function and change its coefficient on the constraint. + ci_to_change = optimizer.dual_problem.primal_dual_map.primal_var_dual_con[obj_change.variable] + sense_change = MOI.get(optimizer.dual_problem.dual_model, + MOI.ObjectiveSense()) == MOI.MAX_SENSE ? one(T) : -one(T) + MOI.set(optimizer.dual_problem.dual_model, + MOI.ConstraintSet(), + ci_to_change, + MOI.EqualTo(sense_change * obj_change.new_coefficient)) + return +end + # TODO add this when constrained variables are implemented #function MOI.supports_add_constrained_variables( # optimizer::DualOptimizer{T}, S::Type{MOI.Reals}) where T diff --git a/src/dual_equality_constraints.jl b/src/dual_equality_constraints.jl index 6f21fb4..f206341 100644 --- a/src/dual_equality_constraints.jl +++ b/src/dual_equality_constraints.jl @@ -15,15 +15,14 @@ function add_dual_equality_constraints(dual_model::MOI.ModelLike, primal_model:: all_variables, con_types, T) # get RHS from objective coeficients - scalar_terms = get_scalar_terms(primal_model, - all_variables, primal_objective) + scalar_terms = get_scalar_terms(primal_objective) # Add terms from objective: # Terms from quadratic part - add_scalar_affine_terms_from_quad_obj(scalar_affine_terms, primal_model, + add_scalar_affine_terms_from_quad_obj(scalar_affine_terms, primal_dual_map.primal_var_dual_quad_slack, primal_objective) # terms from mixing variables and parameters - add_scalar_affine_terms_from_quad_params(scalar_affine_terms, primal_model, + add_scalar_affine_terms_from_quad_params(scalar_affine_terms, primal_dual_map.primal_parameter, primal_objective) for primal_vi in restricted_variables @@ -44,7 +43,6 @@ end function add_scalar_affine_terms_from_quad_obj( scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}}, - primal_model::MOI.ModelLike, primal_var_dual_quad_slack::Dict{VI, VI}, primal_objective::PrimalObjective{T}) where T for term in primal_objective.obj.quadratic_terms @@ -68,7 +66,6 @@ end function add_scalar_affine_terms_from_quad_params( scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}}, - primal_model::MOI.ModelLike, primal_parameter::Dict{VI, VI}, primal_objective::PrimalObjective{T}) where T for (key,val) in primal_objective.quad_cross_parameters @@ -86,9 +83,7 @@ function set_dual_constraint_name(dual_model::MOI.ModelLike, primal_model::MOI.M return end -function get_scalar_terms(primal_model::MOI.ModelLike, - variables::Vector{VI}, - primal_objective::PrimalObjective{T}) where T +function get_scalar_terms(primal_objective::PrimalObjective{T}) where T scalar_terms = Dict{VI,T}() for term in get_affine_terms(primal_objective) @@ -196,6 +191,6 @@ function set_dot(i::Integer, s::MOI.AbstractVectorSet, T::Type) vec[i] = one(T) return MOIU.set_dot(vec, vec, s) end -function set_dot(i::Integer, s::MOI.AbstractScalarSet, T::Type) +function set_dot(::Integer, ::MOI.AbstractScalarSet, T::Type) return one(T) end diff --git a/test/Tests/test_modify.jl b/test/Tests/test_modify.jl new file mode 100644 index 0000000..cd98eb5 --- /dev/null +++ b/test/Tests/test_modify.jl @@ -0,0 +1,59 @@ +@testset "modify" begin + model = Model(GLPK_DUAL_FACTORY) + @variable(model, x[1:2] >= 0) + @constraint(model, 2x[1] + x[2] <= 4) + @constraint(model, x[1] + 2x[2] <= 4) + @objective(model, Max, 4x[1] + 3x[2]) + optimize!(model) + @test objective_value(model) ≈ 28/3 + set_objective_coefficient(model, x[1], 5.0) + optimize!(model) + @test objective_value(model) ≈ 10.6666666666 + + model = Model(GLPK_DUAL_FACTORY) + @variable(model, x[1:2] >= 0) + @constraint(model, 2x[1] + x[2] <= 4) + @constraint(model, x[1] + 2x[2] <= 4) + @objective(model, Min, -4x[1] + -3x[2]) + optimize!(model) + @test objective_value(model) ≈ -28/3 + set_objective_coefficient(model, x[1], -5.0) + optimize!(model) + @test objective_value(model) ≈ -10.6666666666 + + model = Model(SCS_DUAL_FACTORY) + @variable(model, x[1:2] >= 0) + @constraint(model, 2x[1] + x[2] <= 4) + @constraint(model, x[1] + 2x[2] <= 4) + @objective(model, Max, 4x[1] + 3x[2]) + optimize!(model) + @test objective_value(model) ≈ 28/3 atol=1e-3 + set_objective_coefficient(model, x[1], 5.0) + optimize!(model) + @test objective_value(model) ≈ 10.6666666666 atol=1e-3 + + model = Model(SCS_DUAL_FACTORY) + @variable(model, x[1:2] >= 0) + @constraint(model, 2x[1] + x[2] <= 4) + @constraint(model, x[1] + 2x[2] <= 4) + @objective(model, Min, -4x[1] + -3x[2]) + optimize!(model) + @test objective_value(model) ≈ -28/3 atol=1e-3 + set_objective_coefficient(model, x[1], -5.0) + optimize!(model) + @test objective_value(model) ≈ -10.6666666666 atol=1e-3 + + model = Model(SCS_DUAL_FACTORY) + @variable(model, x) + @variable(model, y) + @variable(model, z) + @constraint(model, x + 2y + 3z >= 4) + @constraint(model, x + y >= 1) + @objective(model, Min, x^2 + x*y + y^2 + y*z + z^2) + optimize!(model) + @test objective_value(model) ≈ 1.8571 atol=1e-3 + # Now the objective is @objective(model, Min, x^2 + x*y + y^2 + y*z + z^2 - 5x) + set_objective_coefficient(model, x, -5.0) + optimize!(model) + @test objective_value(model) ≈ -9.15 atol=1e-3 +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 5ac68fc..69e85a7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -93,3 +93,4 @@ include("Solvers/scs_test.jl") include("Tests/test_JuMP_dualize.jl") include("Tests/test_MOI_wrapper.jl") +include("Tests/test_modify.jl") \ No newline at end of file