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