1pub(crate) mod boolvar;
2use super::{Display, HandleT, Variable};
3use crate::constraint::{ArithmeticOperator, Constraint, EqualityOperator};
4use crate::model::Model;
5use crate::utils::{Handle, make_intvar_array};
6use crate::utils::{ModelObject, get_int_array, make_int_array};
7use crate::{
8 ArithmConstraint, ArrayEqualityConstraints, ConstraintArithmT, ConstraintEquality, IntOrIntVar,
9 Sealed,
10};
11use crate::{CHOCO_BACKEND, CHOCO_LIB};
12pub use boolvar::*;
13
14use std::borrow::Borrow;
15use std::fmt::{Debug, Formatter};
16use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
17
18pub struct IntVar<'model> {
24 handle: Handle,
25 model: &'model Model,
26}
27
28impl HandleT for IntVar<'_> {
29 fn get_raw_handle(&self) -> *mut std::os::raw::c_void {
30 self.handle.get_raw_handle()
31 }
32}
33
34impl<'model> ModelObject<'model> for IntVar<'model> {
35 fn get_model(&self) -> &'model Model {
36 self.model
37 }
38}
39
40unsafe impl<'model> Variable<'model> for IntVar<'model> {}
44
45pub(crate) trait NewIntVarT {
46 fn create_int_var<'model>(&self, model: &'model Model) -> IntVar<'model>;
60}
61
62impl NewIntVarT for (i32, Option<&str>) {
63 fn create_int_var<'model>(&self, model: &'model Model) -> IntVar<'model> {
64 let handle = CHOCO_BACKEND.with(|backend| unsafe {
67 match self.1 {
68 Some(name) => {
69 let c_name =
70 std::ffi::CString::new(name).expect("Failed to convert name to CString");
71 CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_intVar_si(
72 backend.thread,
73 model.get_raw_handle(),
74 c_name.as_ptr().cast_mut(),
75 self.0,
76 )
77 }
78 None => CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_intVar_i(
79 backend.thread,
80 model.get_raw_handle(),
81 self.0,
82 ),
83 }
84 });
85 IntVar {
86 handle: Handle::new(handle),
87 model,
88 }
89 }
90}
91
92impl NewIntVarT for (&[i32], Option<&str>) {
93 fn create_int_var<'model>(&self, model: &'model Model) -> IntVar<'model> {
94 let vals = make_int_array(self.0);
95 let handle = CHOCO_BACKEND.with(|backend|
96 unsafe {
99 match self.1 {
100 Some(name) => {
101 let c_name =
102 std::ffi::CString::new(name).expect("Failed to convert name to CString");
103 CHOCO_LIB
104 .Java_org_chocosolver_capi_IntVarApi_intVar_s_arr(
105 backend.thread,
106 model.get_raw_handle(),
107 c_name.as_ptr().cast_mut(),
108 vals,
109 )
110 }
111 None => CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_intVar_arr(
112 backend.thread,
113 model.get_raw_handle(),
114 vals,
115 ),
116 }
117 });
118 IntVar {
119 handle: Handle::new(handle),
120 model,
121 }
122 }
123}
124
125impl NewIntVarT for (i32, i32, Option<&str>) {
126 fn create_int_var<'model>(&self, model: &'model Model) -> IntVar<'model> {
127 let handle = CHOCO_BACKEND.with(|backend| unsafe {
130 match self.2 {
131 Some(name) => {
132 let c_name =
133 std::ffi::CString::new(name).expect("Failed to convert name to CString");
134 CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_intVar_sii(
135 backend.thread,
136 model.get_raw_handle(),
137 c_name.as_ptr().cast_mut(),
138 self.0,
139 self.1,
140 )
141 }
142 None => CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_intVar_ii(
143 backend.thread,
144 model.get_raw_handle(),
145 self.0,
146 self.1,
147 ),
148 }
149 });
150 IntVar {
151 handle: Handle::new(handle),
152 model,
153 }
154 }
155}
156
157impl NewIntVarT for (i32, i32, Option<&str>, bool) {
158 fn create_int_var<'model>(&self, model: &'model Model) -> IntVar<'model> {
159 let handle = CHOCO_BACKEND.with(|backend| unsafe {
162 match self.2 {
163 Some(name) => {
164 let c_name =
165 std::ffi::CString::new(name).expect("Failed to convert name to CString");
166 CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_intVar_siib(
167 backend.thread,
168 model.get_raw_handle(),
169 c_name.as_ptr().cast_mut(),
170 self.0,
171 self.1,
172 self.3.into(),
173 )
174 }
175 None => CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_intVar_iib(
176 backend.thread,
177 model.get_raw_handle(),
178 self.0,
179 self.1,
180 self.3.into(),
181 ),
182 }
183 });
184 IntVar {
185 handle: Handle::new(handle),
186 model,
187 }
188 }
189}
190
191impl<'model> IntVar<'model> {
192 #[must_use]
193 #[allow(private_bounds)]
194 pub(crate) fn new<T: NewIntVarT>(model: &'model Model, args: T) -> Self {
195 args.create_int_var(model)
196 }
197 #[must_use]
198 pub fn lb(&self) -> i32 {
199 CHOCO_BACKEND.with(|backend| unsafe {
202 CHOCO_LIB
203 .Java_org_chocosolver_capi_IntVarApi_getLB(backend.thread, self.get_raw_handle())
204 })
205 }
206 #[must_use]
207 pub fn ub(&self) -> i32 {
208 CHOCO_BACKEND.with(|backend| unsafe {
211 CHOCO_LIB
212 .Java_org_chocosolver_capi_IntVarApi_getUB(backend.thread, self.get_raw_handle())
213 })
214 }
215
216 #[must_use]
217 pub fn value(&self) -> Option<i32> {
218 if self.is_instantiated() {
219 Some(CHOCO_BACKEND.with(|backend|
220 unsafe {
224 CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_getValue(
225 backend.thread,
226 self.get_raw_handle(),
227 )
228 }))
229 } else {
230 None
231 }
232 }
233 #[must_use]
234 pub fn has_enumerated_domain(&self) -> bool {
235 CHOCO_BACKEND.with(|backend| unsafe {
238 CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_hasEnumeratedDomain(
239 backend.thread,
240 self.get_raw_handle(),
241 ) != 0
242 })
243 }
244
245 #[must_use]
246 pub fn get_domain_values(&self) -> Option<Vec<i32>> {
247 unsafe {
251 if self.has_enumerated_domain() {
252 let value_handle = CHOCO_BACKEND.with(|backend| {
253 CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_getDomainValues(
254 backend.thread,
255 self.get_raw_handle(),
256 )
257 });
258 let values = get_int_array(value_handle);
259 Some(values)
260 } else {
261 None
262 }
263 }
264 }
265
266 pub(crate) fn int_offset_view(&self, offset: i32) -> IntVar<'model> {
267 let view_handle = CHOCO_BACKEND.with(|backend| unsafe {
270 CHOCO_LIB.Java_org_chocosolver_capi_ViewApi_int_offset_view(
271 backend.thread,
272 self.get_raw_handle(),
273 offset,
274 )
275 });
276 IntVar {
277 handle: Handle::new(view_handle),
278 model: self.model,
279 }
280 }
281 pub(crate) fn int_scale_view(&self, scale: i32) -> IntVar<'model> {
282 let view_handle = CHOCO_BACKEND.with(|backend| unsafe {
285 CHOCO_LIB.Java_org_chocosolver_capi_ViewApi_int_scale_view(
286 backend.thread,
287 self.get_raw_handle(),
288 scale,
289 )
290 });
291 IntVar {
292 handle: Handle::new(view_handle),
293 model: self.model,
294 }
295 }
296 pub(crate) fn int_minus_view(&self) -> IntVar<'model> {
297 let view_handle = CHOCO_BACKEND.with(|backend| unsafe {
300 CHOCO_LIB.Java_org_chocosolver_capi_ViewApi_int_minus_view(
301 backend.thread,
302 self.get_raw_handle(),
303 )
304 });
305 IntVar {
306 handle: Handle::new(view_handle),
307 model: self.model,
308 }
309 }
310 #[must_use]
312 pub fn eq_view(&self, value: i32) -> BoolVar<'model> {
313 CHOCO_BACKEND.with(|backend|
314 unsafe {
317 let view_handle = CHOCO_LIB.Java_org_chocosolver_capi_ViewApi_int_eq_view(
318 backend.thread,
319 self.get_raw_handle(),
320 value,
321 );
322 BoolVar::from_raw_handle(view_handle, self.model)
323 })
324 }
325 #[must_use]
327 pub fn ge_view(&self, value: i32) -> BoolVar<'model> {
328 CHOCO_BACKEND.with(|backend|
329 unsafe {
332 let view_handle = CHOCO_LIB.Java_org_chocosolver_capi_ViewApi_int_ge_view(
333 backend.thread,
334 self.get_raw_handle(),
335 value,
336 );
337 BoolVar::from_raw_handle(view_handle, self.model)})
338 }
339 #[must_use]
341 pub fn le_view(&self, value: i32) -> BoolVar<'model> {
342 CHOCO_BACKEND.with(|backend|
343 unsafe {
346 let view_handle =CHOCO_LIB.Java_org_chocosolver_capi_ViewApi_int_le_view(
347 backend.thread,
348 self.get_raw_handle(),
349 value,
350 );
351 BoolVar::from_raw_handle(view_handle, self.model)
352 })
353 }
354 #[must_use]
356 pub fn ne_view(&self, value: i32) -> BoolVar<'model> {
357 CHOCO_BACKEND.with(|backend|
358 unsafe {
361 let view_handle =CHOCO_LIB.Java_org_chocosolver_capi_ViewApi_int_ne_view(
362 backend.thread,
363 self.get_raw_handle(),
364 value,
365 );
366 BoolVar::from_raw_handle(view_handle, self.model)
367 })
368 }
369
370 #[must_use]
371 #[allow(private_bounds)]
372 pub fn arithm<'a, 'b, OP, Y>(&'b self, op: OP, y: Y) -> Constraint<'model>
373 where
374 (&'a IntVar<'model>, OP, Y): ConstraintArithmT<'model>,
375 'model: 'a,
376 'model: 'b,
377 'b: 'a,
378 Y: 'b,
379 {
380 (self, op, y).create()
381 }
382
383 #[must_use]
385 #[allow(private_bounds)]
386 pub fn arithm2<OP, Y, OP2, Z>(&self, op: OP, y: Y, op2: OP2, z: Z) -> Constraint<'model>
387 where
388 for<'a> (&'a IntVar<'model>, OP, Y, OP2, Z): ConstraintArithmT<'model>,
389 {
390 (self, op, y, op2, z).create()
391 }
392
393 #[allow(private_bounds)]
396 pub fn reify_eq_y<'a>(&self, y: impl Into<IntOrIntVar<'a, 'model>>, b: &BoolVar<'model>)
397 where
398 'model: 'a,
399 {
400 let y_coverted: IntOrIntVar<'_, 'model> = y.into();
401 CHOCO_BACKEND.with(|backend| unsafe {
404 match y_coverted {
405 IntOrIntVar::IntVar(y_var) => CHOCO_LIB
406 .Java_org_chocosolver_capi_ReificationApi_reify_x_eq_y(
407 backend.thread,
408 self.get_model().get_raw_handle(),
409 self.get_raw_handle(),
410 y_var.get_raw_handle(),
411 b.get_raw_handle(),
412 ),
413 IntOrIntVar::Int(y_int) => CHOCO_LIB
414 .Java_org_chocosolver_capi_ReificationApi_reify_x_eq_c(
415 backend.thread,
416 self.get_model().get_raw_handle(),
417 self.get_raw_handle(),
418 y_int,
419 b.get_raw_handle(),
420 ),
421 }
422 });
423 }
424
425 #[allow(private_bounds)]
428 pub fn reify_ne_y<'a>(&self, y: impl Into<IntOrIntVar<'a, 'model>>, b: &BoolVar<'model>)
429 where
430 'model: 'a,
431 {
432 let y_coverted: IntOrIntVar<'_, 'model> = y.into();
433 CHOCO_BACKEND.with(|backend| unsafe {
436 match y_coverted {
437 IntOrIntVar::IntVar(y_var) => CHOCO_LIB
438 .Java_org_chocosolver_capi_ReificationApi_reify_x_ne_y(
439 backend.thread,
440 self.get_model().get_raw_handle(),
441 self.get_raw_handle(),
442 y_var.get_raw_handle(),
443 b.get_raw_handle(),
444 ),
445 IntOrIntVar::Int(y_int) => CHOCO_LIB
446 .Java_org_chocosolver_capi_ReificationApi_reify_x_ne_c(
447 backend.thread,
448 self.get_model().get_raw_handle(),
449 self.get_raw_handle(),
450 y_int,
451 b.get_raw_handle(),
452 ),
453 }
454 });
455 }
456
457 #[allow(private_bounds)]
460 pub fn reify_lt_y<'a>(&self, y: impl Into<IntOrIntVar<'a, 'model>>, b: &BoolVar<'model>)
461 where
462 'model: 'a,
463 {
464 let y_coverted: IntOrIntVar<'_, 'model> = y.into();
465 CHOCO_BACKEND.with(|backend| unsafe {
468 match y_coverted {
469 IntOrIntVar::IntVar(y_var) => CHOCO_LIB
470 .Java_org_chocosolver_capi_ReificationApi_reify_x_lt_y(
471 backend.thread,
472 self.get_model().get_raw_handle(),
473 self.get_raw_handle(),
474 y_var.get_raw_handle(),
475 b.get_raw_handle(),
476 ),
477 IntOrIntVar::Int(y_int) => CHOCO_LIB
478 .Java_org_chocosolver_capi_ReificationApi_reify_x_lt_c(
479 backend.thread,
480 self.get_model().get_raw_handle(),
481 self.get_raw_handle(),
482 y_int,
483 b.get_raw_handle(),
484 ),
485 }
486 });
487 }
488
489 #[allow(private_bounds)]
492 pub fn reify_gt_y<'a>(&self, y: impl Into<IntOrIntVar<'a, 'model>>, b: &BoolVar<'model>)
493 where
494 'model: 'a,
495 {
496 let y_coverted: IntOrIntVar<'_, 'model> = y.into();
497 CHOCO_BACKEND.with(|backend| unsafe {
500 match y_coverted {
501 IntOrIntVar::IntVar(y_var) => CHOCO_LIB
502 .Java_org_chocosolver_capi_ReificationApi_reify_x_gt_y(
503 backend.thread,
504 self.get_model().get_raw_handle(),
505 self.get_raw_handle(),
506 y_var.get_raw_handle(),
507 b.get_raw_handle(),
508 ),
509 IntOrIntVar::Int(y_int) => CHOCO_LIB
510 .Java_org_chocosolver_capi_ReificationApi_reify_x_gt_c(
511 backend.thread,
512 self.get_model().get_raw_handle(),
513 self.get_raw_handle(),
514 y_int,
515 b.get_raw_handle(),
516 ),
517 }
518 });
519 }
520
521 #[allow(private_bounds)]
524 pub fn reify_le_y<'a>(&self, y: impl Into<IntOrIntVar<'a, 'model>>, b: &BoolVar<'model>)
525 where
526 'model: 'a,
527 {
528 let y_coverted: IntOrIntVar<'_, 'model> = y.into();
529 CHOCO_BACKEND.with(|backend| unsafe {
532 match y_coverted {
533 IntOrIntVar::IntVar(y_var) => CHOCO_LIB
534 .Java_org_chocosolver_capi_ReificationApi_reify_x_le_y(
535 backend.thread,
536 self.get_model().get_raw_handle(),
537 self.get_raw_handle(),
538 y_var.get_raw_handle(),
539 b.get_raw_handle(),
540 ),
541 IntOrIntVar::Int(y_int) => {
542 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_reify_x_lt_c(
544 backend.thread,
545 self.get_model().get_raw_handle(),
546 self.get_raw_handle(),
547 y_int + 1,
548 b.get_raw_handle(),
549 )
550 }
551 }
552 });
553 }
554
555 #[allow(private_bounds)]
558 pub fn reify_ge_y<'a>(&self, y: impl Into<IntOrIntVar<'a, 'model>>, b: &BoolVar<'model>)
559 where
560 'model: 'a,
561 {
562 let y_coverted: IntOrIntVar<'_, 'model> = y.into();
563 CHOCO_BACKEND.with(|backend| unsafe {
566 match y_coverted {
567 IntOrIntVar::IntVar(y_var) => CHOCO_LIB
568 .Java_org_chocosolver_capi_ReificationApi_reify_x_ge_y(
569 backend.thread,
570 self.get_model().get_raw_handle(),
571 self.get_raw_handle(),
572 y_var.get_raw_handle(),
573 b.get_raw_handle(),
574 ),
575 IntOrIntVar::Int(y_int) => {
576 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_reify_x_gt_c(
578 backend.thread,
579 self.get_model().get_raw_handle(),
580 self.get_raw_handle(),
581 y_int - 1,
582 b.get_raw_handle(),
583 )
584 }
585 }
586 });
587 }
588
589 pub fn reify_eq_yc(&self, y: &IntVar<'model>, c: i32, b: &BoolVar<'model>) {
592 CHOCO_BACKEND.with(|backend| unsafe {
595 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_reify_x_eq_yc(
596 backend.thread,
597 self.get_model().get_raw_handle(),
598 self.get_raw_handle(),
599 y.get_raw_handle(),
600 c,
601 b.get_raw_handle(),
602 )
603 });
604 }
605
606 pub fn reify_ne_yc(&self, y: &IntVar<'model>, c: i32, b: &BoolVar<'model>) {
609 CHOCO_BACKEND.with(|backend| unsafe {
612 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_reify_x_ne_yc(
613 backend.thread,
614 self.get_model().get_raw_handle(),
615 self.get_raw_handle(),
616 y.get_raw_handle(),
617 c,
618 b.get_raw_handle(),
619 )
620 });
621 }
622
623 pub fn reify_lt_yc(&self, y: &IntVar<'model>, c: i32, b: &BoolVar<'model>) {
626 CHOCO_BACKEND.with(|backend| unsafe {
629 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_reify_x_lt_yc(
630 backend.thread,
631 self.get_model().get_raw_handle(),
632 self.get_raw_handle(),
633 y.get_raw_handle(),
634 c,
635 b.get_raw_handle(),
636 )
637 });
638 }
639
640 pub fn reify_gt_yc(&self, y: &IntVar<'model>, c: i32, b: &BoolVar<'model>) {
643 CHOCO_BACKEND.with(|backend| unsafe {
646 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_reify_x_gt_yc(
647 backend.thread,
648 self.get_model().get_raw_handle(),
649 self.get_raw_handle(),
650 y.get_raw_handle(),
651 c,
652 b.get_raw_handle(),
653 )
654 });
655 }
656
657 #[must_use]
659 pub fn member_table(&self, table: &[i32]) -> Constraint<'model> {
660 let vals = make_int_array(table);
661 CHOCO_BACKEND.with(|backend|
662 unsafe {
665 let ptr = CHOCO_LIB
666 .Java_org_chocosolver_capi_ConstraintApi_member_iv_iarray(
667 backend.thread,
668 self.get_model().get_raw_handle(),
669 self.get_raw_handle(),
670 vals,
671 );
672 assert!(!ptr.is_null(), "Invalid parameters for member constraint");
673 Constraint::new(ptr, self.get_model())})
674 }
675 #[must_use]
677 pub fn member_bounds(&self, lb: i32, ub: i32) -> Constraint<'model> {
678 CHOCO_BACKEND.with(|backend|
679 unsafe {
682 let ptr = CHOCO_LIB
683 .Java_org_chocosolver_capi_ConstraintApi_member_iv_i_i(
684 backend.thread,
685 self.get_model().get_raw_handle(),
686 self.get_raw_handle(),
687 lb,
688 ub,
689 );
690 assert!(!ptr.is_null(), "Invalid parameters for member constraint");
691 Constraint::new(ptr, self.get_model())})
692 }
693 #[must_use]
695 pub fn not_member_table(&self, table: &[i32]) -> Constraint<'model> {
696 let vals = make_int_array(table);
697 CHOCO_BACKEND.with(|backend|
698 unsafe {
701 let ptr = CHOCO_LIB
702 .Java_org_chocosolver_capi_ConstraintApi_not_member_iv_iarray(
703 backend.thread,
704 self.get_model().get_raw_handle(),
705 self.get_raw_handle(),
706 vals,
707 );
708 assert!(
709 !ptr.is_null(),
710 "Invalid parameters for not member constraint"
711 );
712 Constraint::new(ptr, self.get_model())})
713 }
714 #[must_use]
716 pub fn not_member_bounds(&self, lb: i32, ub: i32) -> Constraint<'model> {
717 CHOCO_BACKEND.with(|backend|
718 unsafe {
721 let ptr = CHOCO_LIB
722 .Java_org_chocosolver_capi_ConstraintApi_not_member_iv_i_i(
723 backend.thread,
724 self.get_model().get_raw_handle(),
725 self.get_raw_handle(),
726 lb,
727 ub,
728 );
729 assert!(
730 !ptr.is_null(),
731 "Invalid parameters for not member constraint"
732 );
733 Constraint::new(ptr, self.get_model())})
734 }
735 #[must_use]
737 pub fn abs(&self, y: &IntVar<'model>) -> Constraint<'model> {
738 CHOCO_BACKEND.with(|backend|
739 unsafe {
742 let ptr = CHOCO_LIB
743 .Java_org_chocosolver_capi_ConstraintApi_absolute(
744 backend.thread,
745 self.get_model().get_raw_handle(),
746 self.get_raw_handle(),
747 y.get_raw_handle(),
748 );
749 assert!(!ptr.is_null(), "Invalid parameters for abs constraint");
750 Constraint::new(ptr, self.get_model())})
751 }
752 #[must_use]
754 pub fn square(&self, y: &IntVar<'model>) -> Constraint<'model> {
755 CHOCO_BACKEND.with(|backend|
756 unsafe {
759 let ptr =CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_square(
760 backend.thread,
761 self.get_model().get_raw_handle(),
762 self.get_raw_handle(),
763 y.get_raw_handle(),
764 );
765 assert!(!ptr.is_null(), "Invalid parameters for square constraint");
766 Constraint::new(ptr, self.get_model())})
767 }
768 #[must_use]
770 pub fn pow(&self, c: i32, y: &IntVar<'model>) -> Constraint<'model> {
771 CHOCO_BACKEND.with(|backend|
772 unsafe {
775 let ptr = CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_pow(
776 backend.thread,
777 self.get_model().get_raw_handle(),
778 self.get_raw_handle(),
779 c,
780 y.get_raw_handle(),
781 );
782 assert!(!ptr.is_null(), "Invalid parameters for power constraint");
783 Constraint::new(ptr, self.get_model())
784 })
785 }
786 #[must_use]
788 pub fn max(&self, intvars: &[&IntVar<'model>]) -> Constraint<'model> {
789 let vals = make_intvar_array(intvars);
790 CHOCO_BACKEND.with(|backend|
791 unsafe {
794 let ptr = CHOCO_LIB
795 .Java_org_chocosolver_capi_ConstraintApi_max_iv_ivarray(
796 backend.thread,
797 self.get_model().get_raw_handle(),
798 self.get_raw_handle(),
799 vals,
800 );
801 assert!(!ptr.is_null(), "Invalid parameters for max constraint");
802 Constraint::new(ptr, self.get_model())
803 })
804 }
805 #[must_use]
807 pub fn min(&self, intvars: &[&IntVar<'model>]) -> Constraint<'model> {
808 let vals = make_intvar_array(intvars);
809 CHOCO_BACKEND.with(|backend|
810 unsafe {
813 let ptr =CHOCO_LIB
814 .Java_org_chocosolver_capi_ConstraintApi_min_iv_ivarray(
815 backend.thread,
816 self.get_model().get_raw_handle(),
817 self.get_raw_handle(),
818 vals,
819 );
820 assert!(!ptr.is_null(), "Invalid parameters for min constraint");
821 Constraint::new(ptr, self.get_model())})
822 }
823 #[must_use]
830 pub fn among(&self, intvars: &[&IntVar<'model>], values: &[i32]) -> Constraint<'model> {
831 let intvar_vals = make_intvar_array(intvars);
832 let vals = make_int_array(values);
833 CHOCO_BACKEND.with(|backend|
834 unsafe {
837 let ptr = CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_among(
838 backend.thread,
839 self.get_model().get_raw_handle(),
840 self.get_raw_handle(),
841 intvar_vals,
842 vals,
843 );
844 assert!(!ptr.is_null(), "Invalid parameters for among constraint");
845 Constraint::new(ptr, self.get_model())
846 })
847 }
848}
849
850impl Debug for IntVar<'_> {
851 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
852 if self.has_enumerated_domain() {
853 let values = self.get_domain_values().unwrap();
854 write!(
855 f,
856 "IntVar {{ name: {:?}, lb: {}, ub: {}, is_instantiated: {}, is_view: {}, domain_values: {:?} }}",
857 self.name(),
858 self.lb(),
859 self.ub(),
860 self.is_instantiated(),
861 self.is_view(),
862 values
863 )
864 } else {
865 write!(
866 f,
867 "IntVar {{ name: {:?}, lb: {}, ub: {}, is_instantiated: {}, is_view: {} }}",
868 self.name(),
869 self.lb(),
870 self.ub(),
871 self.is_instantiated(),
872 self.is_view()
873 )
874 }
875 }
876}
877
878impl<'model> Add<&IntVar<'model>> for &IntVar<'model> {
879 type Output = IntVar<'model>;
880
881 fn add(self, rhs: &IntVar<'model>) -> IntVar<'model> {
882 let var = IntVar::new(
883 self.model,
884 (self.lb() + rhs.lb(), self.ub() + rhs.ub(), None),
885 );
886
887 debug_assert_eq!(
888 self.arithm2(ArithmeticOperator::Sum, rhs, EqualityOperator::Eq, &var,)
889 .post(),
890 Ok(())
891 );
892 var
893 }
894}
895
896impl<'model> Add<i32> for &IntVar<'model> {
897 type Output = IntVar<'model>;
898
899 fn add(self, rhs: i32) -> IntVar<'model> {
900 self.int_offset_view(rhs)
901 }
902}
903
904impl<'model> Sub<&IntVar<'model>> for &IntVar<'model> {
905 type Output = IntVar<'model>;
906
907 fn sub(self, rhs: &IntVar<'model>) -> IntVar<'model> {
908 let var = IntVar::new(
909 self.model,
910 (self.lb() - rhs.ub(), self.ub() - rhs.lb(), None),
911 );
912 debug_assert_eq!(
913 self.arithm2(ArithmeticOperator::Sub, rhs, EqualityOperator::Eq, &var,)
914 .post(),
915 Ok(())
916 );
917 var
918 }
919}
920
921impl<'model> Sub<i32> for &IntVar<'model> {
922 type Output = IntVar<'model>;
923
924 fn sub(self, rhs: i32) -> IntVar<'model> {
925 self.int_offset_view(-rhs)
926 }
927}
928
929impl<'model> Mul<&IntVar<'model>> for &IntVar<'model> {
930 type Output = IntVar<'model>;
931
932 fn mul(self, rhs: &IntVar<'model>) -> IntVar<'model> {
933 let candidates = [
934 self.lb() * rhs.lb(),
935 self.lb() * rhs.ub(),
936 self.ub() * rhs.lb(),
937 self.ub() * rhs.ub(),
938 ];
939 let (min_val, max_val) = candidates
940 .iter()
941 .fold((i32::MAX, i32::MIN), |acc, &v| (acc.0.min(v), acc.1.max(v)));
942 let var = IntVar::new(self.model, (min_val, max_val, None));
943
944 debug_assert_eq!(
945 self.arithm2(ArithmeticOperator::Mul, rhs, EqualityOperator::Eq, &var,)
946 .post(),
947 Ok(())
948 );
949 var
950 }
951}
952
953impl<'model> Mul<i32> for &IntVar<'model> {
954 type Output = IntVar<'model>;
955
956 fn mul(self, rhs: i32) -> IntVar<'model> {
957 self.int_scale_view(rhs)
958 }
959}
960
961impl<'model> Div<&IntVar<'model>> for &IntVar<'model> {
962 type Output = IntVar<'model>;
963
964 fn div(self, rhs: &IntVar<'model>) -> IntVar<'model> {
965 let candidates = [
966 self.lb() / rhs.lb(),
967 self.lb() / rhs.ub(),
968 self.ub() / rhs.lb(),
969 self.ub() / rhs.ub(),
970 ];
971 let (min_val, max_val) = candidates
972 .iter()
973 .fold((i32::MAX, i32::MIN), |acc, &v| (acc.0.min(v), acc.1.max(v)));
974 let var = IntVar::new(self.model, (min_val, max_val, None));
975
976 debug_assert_eq!(
977 self.arithm2(ArithmeticOperator::Div, rhs, EqualityOperator::Eq, &var,)
978 .post(),
979 Ok(())
980 );
981 var
982 }
983}
984
985impl<'model> Div<i32> for &IntVar<'model> {
986 type Output = IntVar<'model>;
987
988 fn div(self, rhs: i32) -> IntVar<'model> {
989 let candidates = [self.lb() / rhs, self.ub() / rhs];
990 let (min_val, max_val) = candidates
991 .iter()
992 .fold((i32::MAX, i32::MIN), |acc, &v| (acc.0.min(v), acc.1.max(v)));
993 let var = IntVar::new(self.model, (min_val, max_val, None));
994
995 debug_assert_eq!(
996 self.arithm2(ArithmeticOperator::Div, rhs, EqualityOperator::Eq, &var,)
997 .post(),
998 Ok(())
999 );
1000 var
1001 }
1002}
1003
1004impl<'model> Neg for &IntVar<'model> {
1005 type Output = IntVar<'model>;
1006
1007 fn neg(self) -> IntVar<'model> {
1008 self.int_minus_view()
1009 }
1010}
1011
1012impl<'model> Rem<&IntVar<'model>> for &IntVar<'model> {
1013 type Output = IntVar<'model>;
1014
1015 fn rem(self, rhs: &IntVar<'model>) -> IntVar<'model> {
1016 assert!(
1017 rhs.lb() != 0 && rhs.ub() != 0,
1018 "Remainder by zero is not allowed"
1019 );
1020 let candidates = [
1021 self.lb() % rhs.lb(),
1022 self.lb() % rhs.ub(),
1023 self.ub() % rhs.lb(),
1024 self.ub() % rhs.ub(),
1025 ];
1026 let (min_val, max_val) = candidates
1027 .iter()
1028 .fold((i32::MAX, i32::MIN), |acc, &v| (acc.0.min(v), acc.1.max(v)));
1029 let var = IntVar::new(self.model, (min_val, max_val, None));
1030
1031 debug_assert_eq!(Ok(()), self.modulo(rhs, &var).post());
1032 var
1033 }
1034}
1035
1036impl<'model> Rem<i32> for &IntVar<'model> {
1037 type Output = IntVar<'model>;
1038
1039 fn rem(self, rhs: i32) -> IntVar<'model> {
1040 assert!(rhs != 0, "Remainder by zero is not allowed");
1041 let candidates = [self.lb() % rhs, self.ub() % rhs];
1042 let (min_val, max_val) = candidates
1043 .iter()
1044 .fold((i32::MAX, i32::MIN), |acc, &v| (acc.0.min(v), acc.1.max(v)));
1045 let var = IntVar::new(self.model, (min_val, max_val, None));
1046 debug_assert_eq!(Ok(()), self.modulo(rhs, &var).post());
1047 var
1048 }
1049}
1050
1051impl<'model, A> ConstraintEquality<'model, i32> for &A
1052where
1053 A: Borrow<IntVar<'model>>,
1054{
1055 fn eq(self, other: i32) -> Constraint<'model> {
1056 self.borrow().arithm(EqualityOperator::Eq, other)
1057 }
1058
1059 fn ne(self, other: i32) -> Constraint<'model> {
1060 self.borrow().arithm(EqualityOperator::Neq, other)
1061 }
1062}
1063
1064impl<'model, A> ConstraintEquality<'model, bool> for &A
1065where
1066 A: Borrow<IntVar<'model>>,
1067{
1068 fn eq(self, other: bool) -> Constraint<'model> {
1069 self.borrow().arithm(EqualityOperator::Eq, i32::from(other))
1070 }
1071
1072 fn ne(self, other: bool) -> Constraint<'model> {
1073 self.borrow()
1074 .arithm(EqualityOperator::Neq, i32::from(other))
1075 }
1076}
1077
1078impl<'model, A, B> ConstraintEquality<'model, &A> for &B
1079where
1080 A: Borrow<IntVar<'model>>,
1081 B: Borrow<IntVar<'model>>,
1082{
1083 fn eq(self, other: &A) -> Constraint<'model> {
1084 self.borrow().arithm(EqualityOperator::Eq, other.borrow())
1085 }
1086
1087 fn ne(self, other: &A) -> Constraint<'model> {
1088 self.borrow().arithm(EqualityOperator::Neq, other.borrow())
1089 }
1090}
1091
1092impl<'model, A> ConstraintEquality<'model, &A> for bool
1093where
1094 A: Borrow<IntVar<'model>>,
1095{
1096 fn eq(self, other: &A) -> Constraint<'model> {
1097 other.eq(self)
1098 }
1099
1100 fn ne(self, other: &A) -> Constraint<'model> {
1101 other.ne(self)
1102 }
1103}
1104
1105impl<'model, A> ConstraintEquality<'model, &A> for i32
1106where
1107 A: Borrow<IntVar<'model>>,
1108{
1109 fn eq(self, other: &A) -> Constraint<'model> {
1110 other.eq(self)
1111 }
1112
1113 fn ne(self, other: &A) -> Constraint<'model> {
1114 other.ne(self)
1115 }
1116}
1117
1118impl<'model> ArithmConstraint<'model, &IntVar<'model>, &IntVar<'model>> for IntVar<'model> {
1119 fn modulo(&'model self, modulo: &IntVar<'model>, res: &IntVar<'model>) -> Constraint<'model> {
1120 CHOCO_BACKEND.with(|backend|
1121 unsafe {
1125 let ptr = CHOCO_LIB
1126 .Java_org_chocosolver_capi_ConstraintApi_mod_iv_iv_iv(
1127 backend.thread,
1128 self.model.get_raw_handle(),
1129 self.get_raw_handle(),
1130 modulo.get_raw_handle(),
1131 res.get_raw_handle(),
1132 );
1133 assert!(
1134 !ptr.is_null(),
1135 "Invalid parameters combination for mod constraint"
1136 );
1137 Constraint::new(ptr, self.model)})
1138 }
1139}
1140
1141impl<'model> ArithmConstraint<'model, i32, i32> for IntVar<'model> {
1142 fn modulo(&'model self, modulo: i32, res: i32) -> Constraint<'model> {
1143 CHOCO_BACKEND.with(|backend|
1144 unsafe {
1148 let ptr = CHOCO_LIB
1149 .Java_org_chocosolver_capi_ConstraintApi_mod_iv_i_i(
1150 backend.thread,
1151 self.model.get_raw_handle(),
1152 self.get_raw_handle(),
1153 modulo,
1154 res,
1155 );
1156 assert!(
1157 !ptr.is_null(),
1158 "Invalid parameters combination for mod constraint"
1159 );
1160 Constraint::new(ptr, self.model)})
1161 }
1162}
1163
1164impl<'model> ArithmConstraint<'model, i32, &IntVar<'model>> for IntVar<'model> {
1165 fn modulo(&'model self, modulo: i32, res: &IntVar<'model>) -> Constraint<'model> {
1166 CHOCO_BACKEND.with(|backend|
1167 unsafe {
1171 let ptr =CHOCO_LIB
1172 .Java_org_chocosolver_capi_ConstraintApi_mod_iv_i_iv(
1173 backend.thread,
1174 self.model.get_raw_handle(),
1175 self.get_raw_handle(),
1176 modulo,
1177 res.get_raw_handle(),
1178 );
1179 assert!(
1180 !ptr.is_null(),
1181 "Invalid parameters combination for mod constraint"
1182 );
1183 Constraint::new(ptr, self.model)
1184 })
1185 }
1186}
1187
1188impl<'model, Q: Borrow<IntVar<'model>> + Sealed> ArrayEqualityConstraints<'model> for &[Q] {
1189 fn all_different(self) -> Constraint<'model> {
1191 assert!(!self.is_empty(), "intvars slice cannot be empty");
1192
1193 let model = self.first().unwrap().borrow().get_model();
1194 let vals = make_intvar_array(self);
1195 CHOCO_BACKEND.with(|backend|
1196 unsafe {
1199 let ptr =CHOCO_LIB
1200 .Java_org_chocosolver_capi_ConstraintApi_allDifferent(
1201 backend.thread,
1202 model.get_raw_handle(),
1203 vals,
1204 );
1205 debug_assert!(
1206 !ptr.is_null(),
1207 "Invalid parameters for all different constraint"
1208 );
1209 Constraint::new(ptr, model)
1210 })
1211 }
1212 fn all_different_except_0(self) -> Constraint<'model> {
1213 assert!(!self.is_empty(), "intvars slice cannot be empty");
1214
1215 let model = self.first().unwrap().borrow().get_model();
1216 let vals = make_intvar_array(self);
1217 CHOCO_BACKEND.with(|backend|
1218 unsafe {
1221 let ptr =CHOCO_LIB
1222 .Java_org_chocosolver_capi_ConstraintApi_allDifferentExcept0(
1223 backend.thread,
1224 model.get_raw_handle(),
1225 vals,
1226 );
1227 assert!(
1228 !ptr.is_null(),
1229 "Invalid parameters for all different except 0 constraint"
1230 );
1231 Constraint::new(ptr, model)})
1232 }
1233 fn all_equal(self) -> Constraint<'model> {
1234 assert!(!self.is_empty(), "intvars slice cannot be empty");
1235
1236 let model = self.first().unwrap().borrow().get_model();
1237 let vals = make_intvar_array(self);
1238 CHOCO_BACKEND.with(|backend|
1239 unsafe {
1242 let ptr = CHOCO_LIB
1243 .Java_org_chocosolver_capi_ConstraintApi_all_equal(
1244 backend.thread,
1245 model.get_raw_handle(),
1246 vals,
1247 );
1248 debug_assert!(
1249 !ptr.is_null(),
1250 "Invalid parameters for all equal constraint"
1251 );
1252 Constraint::new(ptr, model)
1253 })
1254 }
1255 fn not_all_equal(self) -> Constraint<'model> {
1256 assert!(!self.is_empty(), "intvars slice cannot be empty");
1257
1258 let model = self.first().unwrap().borrow().get_model();
1259 let vals = make_intvar_array(self);
1260 CHOCO_BACKEND.with(|backend|
1261 unsafe {
1264 let ptr = CHOCO_LIB
1265 .Java_org_chocosolver_capi_ConstraintApi_not_all_equal(
1266 backend.thread,
1267 model.get_raw_handle(),
1268 vals,
1269 );
1270 debug_assert!(
1271 !ptr.is_null(),
1272 "Invalid parameters for not all equal constraint"
1273 );
1274 Constraint::new(ptr, model)
1275 })
1276 }
1277 fn at_least_n_value<'a>(self, n_values: &'a IntVar<'model>, ac: bool) -> Constraint<'model>
1278 where
1279 'model: 'a,
1280 {
1281 assert!(!self.is_empty(), "intvars slice cannot be empty");
1282
1283 let model = self.first().unwrap().borrow().get_model();
1284 let vals = make_intvar_array(self);
1285 CHOCO_BACKEND.with(|backend|
1286 unsafe {
1289 let ptr = CHOCO_LIB
1290 .Java_org_chocosolver_capi_ConstraintApi_atLeastNValues(
1291 backend.thread,
1292 model.get_raw_handle(),
1293 vals,
1294 n_values.get_raw_handle(),
1295 ac.into(),
1296 );
1297 debug_assert!(
1298 !ptr.is_null(),
1299 "Invalid parameters for at least n value constraint"
1300 );
1301 Constraint::new(ptr, model)
1302 })
1303 }
1304 fn at_most_n_value<'a>(self, n_values: &IntVar<'model>, strong: bool) -> Constraint<'model>
1305 where
1306 'model: 'a,
1307 {
1308 assert!(!self.is_empty(), "intvars slice cannot be empty");
1309
1310 let model = self.first().unwrap().borrow().get_model();
1311 let vals = make_intvar_array(self);
1312 CHOCO_BACKEND.with(|backend|
1313 unsafe {
1316 let ptr = CHOCO_LIB
1317 .Java_org_chocosolver_capi_ConstraintApi_atMostNValues(
1318 backend.thread,
1319 model.get_raw_handle(),
1320 vals,
1321 n_values.get_raw_handle(),
1322 strong.into(),
1323 );
1324 debug_assert!(
1325 !ptr.is_null(),
1326 "Invalid parameters for at most n value constraint"
1327 );
1328 Constraint::new(ptr, model)
1329 })
1330 }
1331}
1332
1333impl Display for IntVar<'_> {
1334 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1335 if self.has_enumerated_domain() {
1336 let values = self.get_domain_values().unwrap();
1337 write!(
1338 f,
1339 "IntVar {{ name: {:?}, lb: {}, ub: {}, is_instantiated: {}, is_view: {}, domain_values: {:?} }}",
1340 self.name(),
1341 self.lb(),
1342 self.ub(),
1343 self.is_instantiated(),
1344 self.is_view(),
1345 values
1346 )
1347 } else {
1348 write!(
1349 f,
1350 "IntVar {{ name: {:?}, lb: {}, ub: {}, is_instantiated: {}, is_view: {} }}",
1351 self.name(),
1352 self.lb(),
1353 self.ub(),
1354 self.is_instantiated(),
1355 self.is_view()
1356 )
1357 }
1358 }
1359}
1360
1361#[cfg(test)]
1362mod tests;