Skip to content

Commit 53860d2

Browse files
committed
Modify vector constraints for MatrixOfConstraints
1 parent 15b62ad commit 53860d2

2 files changed

Lines changed: 139 additions & 0 deletions

File tree

src/Utilities/matrix_of_constraints.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,32 @@ function MOI.modify(
739739
return
740740
end
741741

742+
function MOI.modify(
743+
model::MatrixOfConstraints,
744+
ci::MOI.ConstraintIndex,
745+
change::MOI.MultirowChange,
746+
)
747+
r = rows(model, ci)
748+
for (output_index, new_coefficient) in change.new_coefficients
749+
if !modify_coefficients(
750+
model.coefficients,
751+
r[output_index],
752+
change.variable.value,
753+
new_coefficient,
754+
)
755+
throw(
756+
MOI.ModifyConstraintNotAllowed(
757+
ci,
758+
change,
759+
"cannot set a new non-zero coefficient because no entry " *
760+
"exists in the sparse matrix of `MatrixOfConstraints`",
761+
),
762+
)
763+
end
764+
end
765+
return
766+
end
767+
742768
# See https://github.com/jump-dev/MathOptInterface.jl/pull/2976
743769
# Ideally we would have made it so that `modify_constants` operated like
744770
# `modify_coefficients` and returned a `Bool` indicating success. But we didn't,

test/Utilities/test_matrix_of_constraints.jl

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,119 @@ function test_modify_set_constants()
826826
return
827827
end
828828

829+
function test_modify_multirow_change()
830+
model = _new_VectorSets()
831+
src = MOI.Utilities.Model{Int}()
832+
x = MOI.add_variables(src, 2)
833+
terms = [
834+
MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2, x[1])),
835+
MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(3, x[2])),
836+
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(4, x[1])),
837+
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(5, x[2])),
838+
]
839+
func = MOI.VectorAffineFunction(terms, [0, 0])
840+
c = MOI.add_constraint(src, func, MOI.Nonnegatives(2))
841+
index_map = MOI.copy_to(model, src)
842+
ci = index_map[c]
843+
f = MOI.get(model, MOI.ConstraintFunction(), ci)
844+
@test length(f.terms) == 4
845+
x1 = index_map[x[1]]
846+
x2 = index_map[x[2]]
847+
MOI.modify(model, ci, MOI.MultirowChange(x1, [(1, 7), (2, 8)]))
848+
f = MOI.get(model, MOI.ConstraintFunction(), ci)
849+
coefs = Dict(
850+
(t.output_index, t.scalar_term.variable) => t.scalar_term.coefficient
851+
for t in f.terms
852+
)
853+
@test coefs[(1, x1)] == 7
854+
@test coefs[(2, x1)] == 8
855+
@test coefs[(1, x2)] == 3
856+
@test coefs[(2, x2)] == 5
857+
return
858+
end
859+
860+
function test_modify_multirow_change_single_row()
861+
model = _new_VectorSets()
862+
src = MOI.Utilities.Model{Int}()
863+
x = MOI.add_variables(src, 2)
864+
terms = [
865+
MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2, x[1])),
866+
MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(3, x[2])),
867+
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(4, x[1])),
868+
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(5, x[2])),
869+
]
870+
func = MOI.VectorAffineFunction(terms, [0, 0])
871+
c = MOI.add_constraint(src, func, MOI.Nonnegatives(2))
872+
index_map = MOI.copy_to(model, src)
873+
ci = index_map[c]
874+
x2 = index_map[x[2]]
875+
MOI.modify(model, ci, MOI.MultirowChange(x2, [(2, 9)]))
876+
f = MOI.get(model, MOI.ConstraintFunction(), ci)
877+
coefs = Dict(
878+
(t.output_index, t.scalar_term.variable) => t.scalar_term.coefficient
879+
for t in f.terms
880+
)
881+
x1 = index_map[x[1]]
882+
@test coefs[(1, x1)] == 2
883+
@test coefs[(2, x1)] == 4
884+
@test coefs[(1, x2)] == 3
885+
@test coefs[(2, x2)] == 9
886+
return
887+
end
888+
889+
function test_modify_multirow_change_to_zero()
890+
model = _new_VectorSets()
891+
src = MOI.Utilities.Model{Int}()
892+
x = MOI.add_variables(src, 2)
893+
terms = [
894+
MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2, x[1])),
895+
MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(3, x[2])),
896+
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(4, x[1])),
897+
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(5, x[2])),
898+
]
899+
func = MOI.VectorAffineFunction(terms, [0, 0])
900+
c = MOI.add_constraint(src, func, MOI.Nonnegatives(2))
901+
index_map = MOI.copy_to(model, src)
902+
ci = index_map[c]
903+
x1 = index_map[x[1]]
904+
MOI.modify(model, ci, MOI.MultirowChange(x1, [(1, 0)]))
905+
f = MOI.get(model, MOI.ConstraintFunction(), ci)
906+
coefs = Dict(
907+
(t.output_index, t.scalar_term.variable) => t.scalar_term.coefficient
908+
for t in f.terms
909+
)
910+
@test coefs[(1, x1)] == 0
911+
@test coefs[(2, x1)] == 4
912+
return
913+
end
914+
915+
function test_modify_multirow_change_no_entry()
916+
model = _new_VectorSets()
917+
src = MOI.Utilities.Model{Int}()
918+
x = MOI.add_variables(src, 3)
919+
terms = [
920+
MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2, x[1])),
921+
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(4, x[1])),
922+
]
923+
func = MOI.VectorAffineFunction(terms, [0, 0])
924+
c = MOI.add_constraint(src, func, MOI.Nonnegatives(2))
925+
index_map = MOI.copy_to(model, src)
926+
ci = index_map[c]
927+
x3 = index_map[x[3]]
928+
MOI.modify(model, ci, MOI.MultirowChange(x3, [(1, 0)]))
929+
change = MOI.MultirowChange(x3, [(1, 5)])
930+
@test_throws(
931+
MOI.ModifyConstraintNotAllowed(
932+
ci,
933+
change,
934+
"cannot set a new non-zero coefficient because no entry " *
935+
"exists in the sparse matrix of `MatrixOfConstraints`",
936+
),
937+
MOI.modify(model, ci, change),
938+
)
939+
return
940+
end
941+
829942
function test_unsupported_constraint()
830943
model = _new_ScalarSets()
831944
x = MOI.VariableIndex(1)

0 commit comments

Comments
 (0)