@@ -2380,6 +2380,131 @@ function test_constraint_primal_start_get_for_parameter()
23802380 return
23812381end
23822382
2383+ function test_vector_quadratic_parameter_update_round_trip ()
2384+ # Maximize x s.t. x >= 0, p*x <= 1.
2385+ # Initial p=2 → x=0.5; update p=4 → x=0.25.
2386+ model = POI. Optimizer (SCS. Optimizer)
2387+ MOI. set (model, MOI. Silent (), true )
2388+ x = MOI. add_variable (model)
2389+ p, cp = MOI. add_constrained_variable (model, MOI. Parameter (2.0 ))
2390+ MOI. add_constraint (model, x, MOI. GreaterThan (0.0 ))
2391+ # VectorQuadratic: [1.0 - p*x] ∈ Nonnegatives(1) → p*x ≤ 1
2392+ f = MOI. VectorQuadraticFunction (
2393+ [MOI. VectorQuadraticTerm (1 , MOI. ScalarQuadraticTerm (- 1.0 , p, x))],
2394+ MOI. VectorAffineTerm{Float64}[],
2395+ [1.0 ],
2396+ )
2397+ MOI. add_constraint (model, f, MOI. Nonnegatives (1 ))
2398+ # Minimize -x (maximize x)
2399+ MOI. set (model, MOI. ObjectiveSense (), MOI. MIN_SENSE)
2400+ MOI. set (
2401+ model,
2402+ MOI. ObjectiveFunction {MOI.ScalarAffineFunction{Float64}} (),
2403+ MOI. ScalarAffineFunction ([MOI. ScalarAffineTerm (- 1.0 , x)], 0.0 ),
2404+ )
2405+ MOI. optimize! (model)
2406+ @test MOI. get (model, MOI. VariablePrimal (), x) ≈ 0.5 atol = ATOL
2407+ # Update p = 4 → now x ≤ 0.25
2408+ MOI. set (model, MOI. ConstraintSet (), cp, MOI. Parameter (4.0 ))
2409+ MOI. optimize! (model)
2410+ @test MOI. get (model, MOI. VariablePrimal (), x) ≈ 0.25 atol = ATOL
2411+ return
2412+ end
2413+
2414+ function test_list_of_parametric_constraint_types_with_vector_quadratic ()
2415+ T = Float64
2416+ model = POI. Optimizer (MOI. Utilities. Model {T} ())
2417+ x = MOI. add_variable (model)
2418+ p, _cp = MOI. add_constrained_variable (model, MOI. Parameter (2.0 ))
2419+ # VectorQuadratic constraint with a pv term
2420+ f = MOI. VectorQuadraticFunction (
2421+ [MOI. VectorQuadraticTerm (1 , MOI. ScalarQuadraticTerm (- 1.0 , p, x))],
2422+ MOI. VectorAffineTerm{T}[],
2423+ [1.0 ],
2424+ )
2425+ MOI. add_constraint (model, f, MOI. Nonnegatives (1 ))
2426+ types = MOI. get (model, POI. ListOfParametricConstraintTypesPresent ())
2427+ @test any (types) do (_, _, P)
2428+ return P == POI. ParametricVectorQuadraticFunction{T}
2429+ end
2430+ return
2431+ end
2432+
2433+ function test_compute_conflict_vector_quadratic ()
2434+ T = Float64
2435+ mock = MOI. Utilities. MockOptimizer (MOI. Utilities. Model {T} ())
2436+ MOI. set (mock, MOI. ConflictStatus (), MOI. COMPUTE_CONFLICT_NOT_CALLED)
2437+ model = POI. Optimizer (
2438+ MOI. Utilities. CachingOptimizer (MOI. Utilities. Model {T} (), mock),
2439+ )
2440+ x = MOI. add_variable (model)
2441+ p, p_ci = MOI. add_constrained_variable (model, MOI. Parameter (2.0 ))
2442+ p2, p2_ci = MOI. add_constrained_variable (model, MOI. Parameter (3.0 ))
2443+ p3, p3_ci = MOI. add_constrained_variable (model, MOI. Parameter (4.0 ))
2444+ p4, p4_ci = MOI. add_constrained_variable (model, MOI. Parameter (5.0 ))
2445+ # f1: pv term (IN_CONFLICT) — covers the pv push branch
2446+ f1 = MOI. VectorQuadraticFunction (
2447+ [MOI. VectorQuadraticTerm (1 , MOI. ScalarQuadraticTerm (- 1.0 , p, x))],
2448+ MOI. VectorAffineTerm{T}[],
2449+ [1.0 ],
2450+ )
2451+ # f2: affine parameter term only (IN_CONFLICT) — covers the affine-p push branch
2452+ f2 = MOI. VectorQuadraticFunction (
2453+ MOI. VectorQuadraticTerm{T}[],
2454+ [MOI. VectorAffineTerm (1 , MOI. ScalarAffineTerm (1.0 , p2))],
2455+ [0.0 ],
2456+ )
2457+ # f3: pp term (IN_CONFLICT) — covers the pp push branch
2458+ f3 = MOI. VectorQuadraticFunction (
2459+ [MOI. VectorQuadraticTerm (1 , MOI. ScalarQuadraticTerm (1.0 , p3, p3))],
2460+ MOI. VectorAffineTerm{T}[],
2461+ [0.0 ],
2462+ )
2463+ # f4: pv term (NOT_IN_CONFLICT) — covers the continue branch
2464+ f4 = MOI. VectorQuadraticFunction (
2465+ [MOI. VectorQuadraticTerm (1 , MOI. ScalarQuadraticTerm (- 1.0 , p4, x))],
2466+ MOI. VectorAffineTerm{T}[],
2467+ [1.0 ],
2468+ )
2469+ MOI. add_constraint (model, f1, MOI. Nonnegatives (1 ))
2470+ MOI. add_constraint (model, f2, MOI. Nonnegatives (1 ))
2471+ MOI. add_constraint (model, f3, MOI. Nonnegatives (1 ))
2472+ MOI. add_constraint (model, f4, MOI. Nonnegatives (1 ))
2473+ MOI. Utilities. set_mock_optimize! (
2474+ mock,
2475+ mock:: MOI.Utilities.MockOptimizer -> begin
2476+ MOI. Utilities. mock_optimize! (
2477+ mock,
2478+ MOI. INFEASIBLE,
2479+ MOI. NO_SOLUTION,
2480+ MOI. NO_SOLUTION;
2481+ constraint_conflict_status = [
2482+ (MOI. VectorAffineFunction{T}, MOI. Nonnegatives) => [
2483+ MOI. IN_CONFLICT, # f1 (pv)
2484+ MOI. IN_CONFLICT, # f2 (affine-p)
2485+ MOI. IN_CONFLICT, # f3 (pp)
2486+ MOI. NOT_IN_CONFLICT, # f4 (pv, not conflicting)
2487+ ],
2488+ ],
2489+ )
2490+ MOI. set (mock, MOI. ConflictStatus (), MOI. CONFLICT_FOUND)
2491+ end ,
2492+ )
2493+ MOI. optimize! (model)
2494+ @test MOI. get (model, MOI. TerminationStatus ()) == MOI. INFEASIBLE
2495+ MOI. compute_conflict! (model)
2496+ @test MOI. get (model, MOI. ConflictStatus ()) == MOI. CONFLICT_FOUND
2497+ @test MOI. get (model, MOI. ConstraintConflictStatus (), p_ci) ==
2498+ MOI. MAYBE_IN_CONFLICT # p in f1 (IN_CONFLICT, pv)
2499+ @test MOI. get (model, MOI. ConstraintConflictStatus (), p2_ci) ==
2500+ MOI. MAYBE_IN_CONFLICT # p2 in f2 (IN_CONFLICT, affine-p)
2501+ @test MOI. get (model, MOI. ConstraintConflictStatus (), p3_ci) ==
2502+ MOI. MAYBE_IN_CONFLICT # p3 in f3 (IN_CONFLICT, pp)
2503+ @test MOI. get (model, MOI. ConstraintConflictStatus (), p4_ci) ==
2504+ MOI. NOT_IN_CONFLICT # p4 in f4 (NOT_IN_CONFLICT)
2505+ return
2506+ end
2507+
23832508function test_vector_quadratic_no_parameters_affine_get_constraint_function ()
23842509 # A VectorQuadraticFunction with no parameters and no quadratic terms
23852510 # (empty quadratic_terms) should use the affine fast path. The outer
0 commit comments