Skip to content

Commit 7627b6a

Browse files
committed
Add support for MOI.ScalarQuadraticCoefficientChange
1 parent a17bcfd commit 7627b6a

File tree

3 files changed

+116
-4
lines changed

3 files changed

+116
-4
lines changed

Project.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "HiGHS"
22
uuid = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
3-
version = "1.7.5"
3+
version = "1.8.0"
44

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

1111
[compat]
1212
HiGHS_jll = "=1.5.1, =1.5.3, =1.6.0"
13-
MathOptInterface = "1.20"
13+
MathOptInterface = "1.21"
1414
PrecompileTools = "1"
1515
SparseArrays = "1.6"
1616
Test = "1.6"

src/MOI_wrapper.jl

+50-2
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,12 @@ end
10551055

10561056
function MOI.modify(
10571057
model::Optimizer,
1058-
::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}},
1058+
::MOI.ObjectiveFunction{
1059+
<:Union{
1060+
MOI.ScalarAffineFunction{Float64},
1061+
MOI.ScalarQuadraticFunction{Float64},
1062+
},
1063+
},
10591064
chg::MOI.ScalarConstantChange{Float64},
10601065
)
10611066
ret = Highs_changeObjectiveOffset(model, chg.new_constant)
@@ -1066,7 +1071,12 @@ end
10661071

10671072
function MOI.modify(
10681073
model::Optimizer,
1069-
::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}},
1074+
::MOI.ObjectiveFunction{
1075+
<:Union{
1076+
MOI.ScalarAffineFunction{Float64},
1077+
MOI.ScalarQuadraticFunction{Float64},
1078+
},
1079+
},
10701080
chg::MOI.ScalarCoefficientChange{Float64},
10711081
)
10721082
ret = Highs_changeColCost(
@@ -1079,6 +1089,44 @@ function MOI.modify(
10791089
return
10801090
end
10811091

1092+
function MOI.modify(
1093+
model::Optimizer,
1094+
attr::MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}},
1095+
chg::MOI.ScalarQuadraticCoefficientChange{Float64},
1096+
)
1097+
if model.hessian === nothing
1098+
f = MOI.get(
1099+
model,
1100+
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
1101+
)
1102+
term = MOI.ScalarQuadraticTerm(
1103+
chg.new_coefficient,
1104+
chg.variable_1,
1105+
chg.variable_2,
1106+
)
1107+
new_f = MOI.ScalarQuadraticFunction([term], f.terms, f.constant)
1108+
MOI.set(model, attr, new_f)
1109+
return
1110+
end
1111+
i, j = column(model, chg.variable_1), column(model, chg.variable_2)
1112+
if i < j
1113+
j, i = i, j
1114+
end
1115+
model.hessian[i+1, j+1] = chg.new_coefficient
1116+
ret = Highs_passHessian(
1117+
model,
1118+
size(model.hessian, 1),
1119+
length(model.hessian.nzval),
1120+
kHighsHessianFormatTriangular,
1121+
model.hessian.colptr .- HighsInt(1),
1122+
model.hessian.rowval .- HighsInt(1),
1123+
model.hessian.nzval,
1124+
)
1125+
_check_ret(ret)
1126+
model.is_objective_function_set = true
1127+
return
1128+
end
1129+
10821130
###
10831131
### VariableIndex-in-Set constraints.
10841132
###

test/MOI_wrapper.jl

+64
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,70 @@ function test_relax_integrality_after_solve()
476476
return
477477
end
478478

479+
function test_quadratic_modification_from_affine()
480+
model = HiGHS.Optimizer()
481+
MOI.set(model, MOI.Silent(), true)
482+
x = MOI.add_variable(model)
483+
MOI.add_constraint(model, x, MOI.GreaterThan(2.0))
484+
f = 2.0 * x + 1.0
485+
attr = MOI.ObjectiveFunction{typeof(f)}()
486+
MOI.set(model, attr, f)
487+
MOI.optimize!(model)
488+
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 5, atol = 1e-5)
489+
F = MOI.ScalarQuadraticFunction{Float64}
490+
attr = MOI.ObjectiveFunction{F}()
491+
MOI.modify(model, attr, MOI.ScalarQuadraticCoefficientChange(x, x, 3.0))
492+
MOI.optimize!(model)
493+
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 11, atol = 1e-5)
494+
return
495+
end
496+
497+
function test_quadratic_off_diagonal_modification()
498+
model = HiGHS.Optimizer()
499+
MOI.set(model, MOI.Silent(), true)
500+
x = MOI.add_variables(model, 2)
501+
MOI.add_constraint.(model, x, MOI.GreaterThan.([2.0, 3.0]))
502+
f = 4.0 * x[1] * x[1] + 2.0 * x[1] * x[2] + 2.0 * x[2] * x[2]
503+
attr = MOI.ObjectiveFunction{typeof(f)}()
504+
MOI.set(model, attr, f)
505+
MOI.optimize!(model)
506+
a = MOI.get(model, MOI.VariablePrimal(), x)
507+
y = 0.5 * a' * [8 2; 2 4] * a
508+
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), y, atol = 1e-5)
509+
MOI.modify(
510+
model,
511+
attr,
512+
MOI.ScalarQuadraticCoefficientChange(x[1], x[2], -1.0),
513+
)
514+
MOI.optimize!(model)
515+
a = MOI.get(model, MOI.VariablePrimal(), x)
516+
y = 0.5 * a' * [8 -1; -1 4] * a
517+
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), y, atol = 1e-5)
518+
return
519+
end
520+
521+
function test_quadratic_diagonal_modification()
522+
model = HiGHS.Optimizer()
523+
MOI.set(model, MOI.Silent(), true)
524+
x = MOI.add_variable(model)
525+
MOI.add_constraint(model, x, MOI.GreaterThan(2.0))
526+
f = 3.0 * x * x + 2.0 * x + 1.0
527+
attr = MOI.ObjectiveFunction{typeof(f)}()
528+
MOI.set(model, attr, f)
529+
MOI.optimize!(model)
530+
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 17, atol = 1e-5)
531+
MOI.modify(model, attr, MOI.ScalarConstantChange(2.0))
532+
MOI.optimize!(model)
533+
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 18, atol = 1e-5)
534+
MOI.modify(model, attr, MOI.ScalarCoefficientChange(x, 3.0))
535+
MOI.optimize!(model)
536+
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 20, atol = 1e-5)
537+
MOI.modify(model, attr, MOI.ScalarQuadraticCoefficientChange(x, x, 8.0))
538+
MOI.optimize!(model)
539+
@test isapprox(MOI.get(model, MOI.ObjectiveValue()), 24, atol = 1e-5)
540+
return
541+
end
542+
479543
end
480544

481545
TestMOIHighs.runtests()

0 commit comments

Comments
 (0)