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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ docs/build
docs/src/release_notes.md
Manifest.toml
.DS_Store
*.cov
18 changes: 18 additions & 0 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,24 @@ function MOI.add_constraint(
set::MOI.AbstractVectorSet,
) where {T}
if !_has_parameters(f)
# The user might construct a VectorQuadraticFunction with no actual
# quadratic terms (e.g. from a JuMP expression that simplifies to
# affine). Convert to VectorAffineFunction while still recording the
# outer_to_inner map so that get(ConstraintFunction) can return the
# original VectorQuadraticFunction type.
if _is_vector_affine(f)
fa = MOI.VectorAffineFunction(f.affine_terms, f.constants)
inner_ci = MOI.add_constraint(model.optimizer, fa, set)
model.last_vec_quad_add_added += 1
outer_ci =
MOI.ConstraintIndex{MOI.VectorQuadraticFunction{T},typeof(set)}(
model.last_vec_quad_add_added,
)
model.vector_quadratic_outer_to_inner[outer_ci] = inner_ci
model.constraint_outer_to_inner[outer_ci] = inner_ci
model.vector_quadratic_constraint_cache_set[inner_ci] = set
return outer_ci
end
return _add_constraint_direct_and_cache_map!(model, f, set)
else
return _add_constraint_with_parameters_on_function(model, f, set)
Expand Down
19 changes: 19 additions & 0 deletions test/test_MathOptInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2346,6 +2346,25 @@ function test_constraint_primal_start_get_for_parameter()
return
end

function test_vector_quadratic_no_parameters_affine_get_constraint_function()
# A VectorQuadraticFunction with no parameters and no quadratic terms
# (empty quadratic_terms) should use the affine fast path. The outer
# constraint index is a VectorQuadraticFunction index (preserving the
# original type), but the inner optimizer stores it as VectorAffine.
# get(ConstraintFunction) must reconstruct the original VQF.
model = POI.Optimizer(MOI.Utilities.Model{Float64}())
x = MOI.add_variable(model)
quadratic_terms = MOI.VectorQuadraticTerm{Float64}[]
affine_terms = [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x))]
constants = [1.0]
f = MOI.VectorQuadraticFunction(quadratic_terms, affine_terms, constants)
ci = MOI.add_constraint(model, f, MOI.Zeros(1))
@test MOI.is_valid(model, ci)
f2 = MOI.get(model, MOI.ConstraintFunction(), ci)
@test canonical_compare(f, f2)
return
end

end # module

TestMathOptInterfaceTests.runtests()
Loading