Skip to content

Commit

Permalink
Add support for MOI.ScalarQuadraticCoefficientChange
Browse files Browse the repository at this point in the history
  • Loading branch information
odow committed Jan 23, 2024
1 parent a17bcfd commit 7627b6a
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 4 deletions.
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "HiGHS"
uuid = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
version = "1.7.5"
version = "1.8.0"

[deps]
HiGHS_jll = "8fd58aa0-07eb-5a78-9b36-339c94fd15ea"
Expand All @@ -10,7 +10,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[compat]
HiGHS_jll = "=1.5.1, =1.5.3, =1.6.0"
MathOptInterface = "1.20"
MathOptInterface = "1.21"
PrecompileTools = "1"
SparseArrays = "1.6"
Test = "1.6"
Expand Down
52 changes: 50 additions & 2 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,12 @@ end

function MOI.modify(
model::Optimizer,
::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}},
::MOI.ObjectiveFunction{
<:Union{
MOI.ScalarAffineFunction{Float64},
MOI.ScalarQuadraticFunction{Float64},
},
},
chg::MOI.ScalarConstantChange{Float64},
)
ret = Highs_changeObjectiveOffset(model, chg.new_constant)
Expand All @@ -1066,7 +1071,12 @@ end

function MOI.modify(
model::Optimizer,
::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}},
::MOI.ObjectiveFunction{
<:Union{
MOI.ScalarAffineFunction{Float64},
MOI.ScalarQuadraticFunction{Float64},
},
},
chg::MOI.ScalarCoefficientChange{Float64},
)
ret = Highs_changeColCost(
Expand All @@ -1079,6 +1089,44 @@ function MOI.modify(
return
end

function MOI.modify(
model::Optimizer,
attr::MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}},
chg::MOI.ScalarQuadraticCoefficientChange{Float64},
)
if model.hessian === nothing
f = MOI.get(
model,
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
)
term = MOI.ScalarQuadraticTerm(
chg.new_coefficient,
chg.variable_1,
chg.variable_2,
)
new_f = MOI.ScalarQuadraticFunction([term], f.terms, f.constant)
MOI.set(model, attr, new_f)
return
end
i, j = column(model, chg.variable_1), column(model, chg.variable_2)
if i < j
j, i = i, j
end
model.hessian[i+1, j+1] = chg.new_coefficient
ret = Highs_passHessian(
model,
size(model.hessian, 1),
length(model.hessian.nzval),
kHighsHessianFormatTriangular,
model.hessian.colptr .- HighsInt(1),
model.hessian.rowval .- HighsInt(1),
model.hessian.nzval,
)
_check_ret(ret)
model.is_objective_function_set = true
return
end

###
### VariableIndex-in-Set constraints.
###
Expand Down
64 changes: 64 additions & 0 deletions test/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,70 @@ function test_relax_integrality_after_solve()
return
end

function test_quadratic_modification_from_affine()
model = HiGHS.Optimizer()
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variable(model)
MOI.add_constraint(model, x, MOI.GreaterThan(2.0))
f = 2.0 * x + 1.0
attr = MOI.ObjectiveFunction{typeof(f)}()
MOI.set(model, attr, f)
MOI.optimize!(model)
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 5, atol = 1e-5)
F = MOI.ScalarQuadraticFunction{Float64}
attr = MOI.ObjectiveFunction{F}()
MOI.modify(model, attr, MOI.ScalarQuadraticCoefficientChange(x, x, 3.0))
MOI.optimize!(model)
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 11, atol = 1e-5)
return
end

function test_quadratic_off_diagonal_modification()
model = HiGHS.Optimizer()
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variables(model, 2)
MOI.add_constraint.(model, x, MOI.GreaterThan.([2.0, 3.0]))
f = 4.0 * x[1] * x[1] + 2.0 * x[1] * x[2] + 2.0 * x[2] * x[2]
attr = MOI.ObjectiveFunction{typeof(f)}()
MOI.set(model, attr, f)
MOI.optimize!(model)
a = MOI.get(model, MOI.VariablePrimal(), x)
y = 0.5 * a' * [8 2; 2 4] * a
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), y, atol = 1e-5)
MOI.modify(
model,
attr,
MOI.ScalarQuadraticCoefficientChange(x[1], x[2], -1.0),
)
MOI.optimize!(model)
a = MOI.get(model, MOI.VariablePrimal(), x)
y = 0.5 * a' * [8 -1; -1 4] * a
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), y, atol = 1e-5)
return
end

function test_quadratic_diagonal_modification()
model = HiGHS.Optimizer()
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variable(model)
MOI.add_constraint(model, x, MOI.GreaterThan(2.0))
f = 3.0 * x * x + 2.0 * x + 1.0
attr = MOI.ObjectiveFunction{typeof(f)}()
MOI.set(model, attr, f)
MOI.optimize!(model)
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 17, atol = 1e-5)
MOI.modify(model, attr, MOI.ScalarConstantChange(2.0))
MOI.optimize!(model)
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 18, atol = 1e-5)
MOI.modify(model, attr, MOI.ScalarCoefficientChange(x, 3.0))
MOI.optimize!(model)
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 20, atol = 1e-5)
MOI.modify(model, attr, MOI.ScalarQuadraticCoefficientChange(x, x, 8.0))
MOI.optimize!(model)
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 24, atol = 1e-5)
return
end

end

TestMOIHighs.runtests()

0 comments on commit 7627b6a

Please sign in to comment.