@@ -65,6 +65,7 @@ function test_cpsat_CountDistinct(
6565 @requires _supports (config, MOI. optimize!)
6666 y = [MOI. add_constrained_variable (model, MOI. Integer ()) for _ in 1 : 4 ]
6767 x = first .(y)
68+ MOI. add_constraint .(model, x, MOI. Interval (T (0 ), T (4 )))
6869 MOI. add_constraint (model, MOI. VectorOfVariables (x), MOI. CountDistinct (4 ))
6970 MOI. optimize! (model)
7071 x_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), x))
@@ -142,6 +143,7 @@ function test_cpsat_CountAtLeast(
142143 x, _ = MOI. add_constrained_variable (model, MOI. Integer ())
143144 y, _ = MOI. add_constrained_variable (model, MOI. Integer ())
144145 z, _ = MOI. add_constrained_variable (model, MOI. Integer ())
146+ MOI. add_constraint .(model, [x, y, z], MOI. Interval (T (0 ), T (3 )))
145147 variables = [x, y, y, z]
146148 partitions = [2 , 2 ]
147149 set = Set ([3 ])
@@ -220,3 +222,253 @@ function setup_test(
220222 )
221223 return
222224end
225+
226+ """
227+ test_cpsat_BinPacking(model::MOI.ModelLike, config::Config)
228+
229+ Add a VectorOfVariables-in-BinPacking constraint.
230+ """
231+ function test_cpsat_BinPacking (
232+ model:: MOI.ModelLike ,
233+ config:: Config{T} ,
234+ ) where {T}
235+ @requires MOI. supports_constraint (
236+ model,
237+ MOI. VectorOfVariables,
238+ MOI. BinPacking{T},
239+ )
240+ @requires MOI. supports_add_constrained_variable (model, MOI. Integer)
241+ @requires _supports (config, MOI. optimize!)
242+ N = 5
243+ bins = MOI. add_variables (model, N)
244+ weights = T[1 , 1 , 2 , 2 , 3 ]
245+ MOI. add_constraint .(model, bins, MOI. Integer ())
246+ MOI. add_constraint .(model, bins, MOI. Interval (T (1 ), T (3 )))
247+ MOI. add_constraint (
248+ model,
249+ MOI. VectorOfVariables (bins),
250+ MOI. BinPacking (T (3 ), weights),
251+ )
252+ MOI. optimize! (model)
253+ x_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), bins))
254+ sol = zeros (3 )
255+ for i in 1 : N
256+ sol[x_val[i]] += weights[i]
257+ end
258+ @test all (sol .<= 3 )
259+ return
260+ end
261+
262+ function setup_test (
263+ :: typeof (test_cpsat_BinPacking),
264+ model:: MOIU.MockOptimizer ,
265+ :: Config{T} ,
266+ ) where {T}
267+ MOIU. set_mock_optimize! (
268+ model,
269+ (mock:: MOIU.MockOptimizer ) -> MOIU. mock_optimize! (
270+ mock,
271+ MOI. OPTIMAL,
272+ (MOI. FEASIBLE_POINT, T[1 , 2 , 1 , 2 , 3 ]),
273+ ),
274+ )
275+ return
276+ end
277+
278+ """
279+ test_cpsat_Cumulative(model::MOI.ModelLike, config::Config)
280+
281+ Add a VectorOfVariables-in-Cumulative constraint.
282+ """
283+ function test_cpsat_Cumulative (
284+ model:: MOI.ModelLike ,
285+ config:: Config{T} ,
286+ ) where {T}
287+ @requires MOI. supports_constraint (
288+ model,
289+ MOI. VectorOfVariables,
290+ MOI. Cumulative,
291+ )
292+ @requires MOI. supports_add_constrained_variable (model, MOI. Integer)
293+ @requires _supports (config, MOI. optimize!)
294+ s = [MOI. add_constrained_variable (model, MOI. Integer ())[1 ] for _ in 1 : 3 ]
295+ MOI. add_constraint .(model, s, MOI. Interval (T (0 ), T (3 )))
296+ d = [MOI. add_constrained_variable (model, MOI. Integer ())[1 ] for _ in 1 : 3 ]
297+ MOI. add_constraint .(model, d, MOI. EqualTo (T (2 )))
298+ r = [MOI. add_constrained_variable (model, MOI. Integer ())[1 ] for _ in 1 : 3 ]
299+ MOI. add_constraint .(model, r, MOI. EqualTo .(T[3 , 2 , 1 ]))
300+ b, _ = MOI. add_constrained_variable (model, MOI. Integer ())
301+ MOI. add_constraint .(model, b, MOI. EqualTo (T (5 )))
302+ MOI. add_constraint (
303+ model,
304+ MOI. VectorOfVariables ([s; d; r; b]),
305+ MOI. Cumulative (10 ),
306+ )
307+ MOI. optimize! (model)
308+ s_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), s))
309+ d_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), d))
310+ r_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), r))
311+ b_val = round (Int, MOI. get (model, MOI. VariablePrimal (), b))
312+ times = zeros (1 + maximum (s_val) + maximum (d_val))
313+ for i in 1 : 3
314+ for j in 0 : (d_val[i]- 1 )
315+ t = s_val[i] + j
316+ times[t+ 1 ] += r_val[i]
317+ end
318+ end
319+ @test all (times .<= b_val)
320+ return
321+ end
322+
323+ function setup_test (
324+ :: typeof (test_cpsat_Cumulative),
325+ model:: MOIU.MockOptimizer ,
326+ :: Config{T} ,
327+ ) where {T}
328+ MOIU. set_mock_optimize! (
329+ model,
330+ (mock:: MOIU.MockOptimizer ) -> MOIU. mock_optimize! (
331+ mock,
332+ MOI. OPTIMAL,
333+ (MOI. FEASIBLE_POINT, T[0 , 1 , 2 , 2 , 2 , 2 , 3 , 2 , 1 , 5 ]),
334+ ),
335+ )
336+ return
337+ end
338+
339+ """
340+ test_cpsat_Table(model::MOI.ModelLike, config::Config)
341+
342+ Add a VectorOfVariables-in-Table constraint.
343+ """
344+ function test_cpsat_Table (model:: MOI.ModelLike , config:: Config{T} ) where {T}
345+ @requires MOI. supports_constraint (
346+ model,
347+ MOI. VectorOfVariables,
348+ MOI. Table{T},
349+ )
350+ @requires MOI. supports_add_constrained_variable (model, MOI. Integer)
351+ @requires _supports (config, MOI. optimize!)
352+ x = [MOI. add_constrained_variable (model, MOI. Integer ())[1 ] for _ in 1 : 3 ]
353+ table = T[1 1 0 ; 0 1 1 ]
354+ MOI. add_constraint (model, MOI. VectorOfVariables (x), MOI. Table (table))
355+ MOI. optimize! (model)
356+ x_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), x))
357+ @test x_val == [1 , 1 , 0 ] || x_val == [0 , 1 , 1 ]
358+ return
359+ end
360+
361+ function setup_test (
362+ :: typeof (test_cpsat_Table),
363+ model:: MOIU.MockOptimizer ,
364+ :: Config{T} ,
365+ ) where {T}
366+ MOIU. set_mock_optimize! (
367+ model,
368+ (mock:: MOIU.MockOptimizer ) -> MOIU. mock_optimize! (
369+ mock,
370+ MOI. OPTIMAL,
371+ (MOI. FEASIBLE_POINT, T[1 , 1 , 0 ]),
372+ ),
373+ )
374+ return
375+ end
376+
377+ """
378+ test_cpsat_Circuit(model::MOI.ModelLike, config::Config)
379+
380+ Add a VectorOfVariables-in-Circuit constraint.
381+ """
382+ function test_cpsat_Circuit (model:: MOI.ModelLike , config:: Config{T} ) where {T}
383+ @requires MOI. supports_constraint (model, MOI. VectorOfVariables, MOI. Circuit)
384+ @requires MOI. supports_add_constrained_variable (model, MOI. Integer)
385+ @requires _supports (config, MOI. optimize!)
386+ x = [MOI. add_constrained_variable (model, MOI. Integer ())[1 ] for _ in 1 : 3 ]
387+ MOI. add_constraint (model, MOI. VectorOfVariables (x), MOI. Circuit (3 ))
388+ MOI. optimize! (model)
389+ x_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), x))
390+ @test x_val == [3 , 1 , 2 ] || x_val == [2 , 3 , 1 ]
391+ return
392+ end
393+
394+ function setup_test (
395+ :: typeof (test_cpsat_Circuit),
396+ model:: MOIU.MockOptimizer ,
397+ :: Config{T} ,
398+ ) where {T}
399+ MOIU. set_mock_optimize! (
400+ model,
401+ (mock:: MOIU.MockOptimizer ) -> MOIU. mock_optimize! (
402+ mock,
403+ MOI. OPTIMAL,
404+ (MOI. FEASIBLE_POINT, T[3 , 1 , 2 ]),
405+ ),
406+ )
407+ return
408+ end
409+
410+ """
411+ test_cpsat_Path(model::MOI.ModelLike, config::Config)
412+
413+ Add a VectorOfVariables-in-Path constraint.
414+ """
415+ function test_cpsat_Path (model:: MOI.ModelLike , config:: Config{T} ) where {T}
416+ @requires MOI. supports_constraint (model, MOI. VectorOfVariables, MOI. Path)
417+ @requires MOI. supports_add_constrained_variable (model, MOI. Integer)
418+ @requires _supports (config, MOI. optimize!)
419+ from = [1 , 1 , 2 , 2 , 3 ]
420+ to = [2 , 3 , 3 , 4 , 4 ]
421+ N, E = 4 , 5
422+ s, _ = MOI. add_constrained_variable (model, MOI. Integer ())
423+ t, _ = MOI. add_constrained_variable (model, MOI. Integer ())
424+ ns = MOI. add_variables (model, N)
425+ MOI. add_constraint .(model, ns, MOI. ZeroOne ())
426+ es = MOI. add_variables (model, E)
427+ MOI. add_constraint .(model, es, MOI. ZeroOne ())
428+ MOI. add_constraint (
429+ model,
430+ MOI. VectorOfVariables ([s; t; ns; es]),
431+ MOI. Path (from, to),
432+ )
433+ MOI. optimize! (model)
434+ s_val = round (Int, MOI. get (model, MOI. VariablePrimal (), s))
435+ @test 1 <= s_val <= 4
436+ t_val = round (Int, MOI. get (model, MOI. VariablePrimal (), t))
437+ @test 1 <= t_val <= 4
438+ ns_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), ns))
439+ es_val = round .(Int, MOI. get .(model, MOI. VariablePrimal (), es))
440+ outs = Vector{Int}[[1 , 2 ], [3 , 4 ], [5 ], Int[]]
441+ ins = Vector{Int}[[], [1 ], [2 , 3 ], [4 , 5 ]]
442+ has_edges = s_val == t_val ? 0 : 1
443+ # source: must have no incoming and one outgoing (if s != t)
444+ @test sum (es_val[o] for o in ins[s_val]; init = 0 ) == 0
445+ @test sum (es_val[o] for o in outs[s_val]; init = 0 ) == has_edges
446+ # dest: must have no outgoing and one incoming (if s != t)
447+ @test sum (es_val[o] for o in ins[t_val]; init = 0 ) == has_edges
448+ @test sum (es_val[o] for o in outs[t_val]; init = 0 ) == 0
449+ for i in 1 : 4
450+ if i != s_val && i != t_val
451+ # other nodes: must have one incoming and one outgoing iff node is
452+ # in subgraph.
453+ @test sum (es_val[o] for o in outs[i]; init = 0 ) == ns_val[i]
454+ @test sum (es_val[o] for o in ins[i]; init = 0 ) == ns_val[i]
455+ end
456+ end
457+ return
458+ end
459+
460+ function setup_test (
461+ :: typeof (test_cpsat_Path),
462+ model:: MOIU.MockOptimizer ,
463+ :: Config{T} ,
464+ ) where {T}
465+ MOIU. set_mock_optimize! (
466+ model,
467+ (mock:: MOIU.MockOptimizer ) -> MOIU. mock_optimize! (
468+ mock,
469+ MOI. OPTIMAL,
470+ (MOI. FEASIBLE_POINT, T[1 , 4 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 ]),
471+ ),
472+ )
473+ return
474+ end
0 commit comments