Skip to main content

choco_solver/variables/
intvar.rs

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
18/// An integer decision variable belonging to a [`Model`].
19///
20/// `IntVar` represents a domain of possible integer values and provides
21/// accessors, views, arithmetic constraints, and reification helpers.
22/// Instances are tied to the lifetime of their owning model.
23pub 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
40/// Safety:
41/// - Safe because IntVar is created from Model and therefore the backend is initialized
42///   and model is initialized.
43unsafe impl<'model> Variable<'model> for IntVar<'model> {}
44
45pub(crate) trait NewIntVarT {
46    /// Creates an IntVar.
47    ///
48    /// # Arguments
49    ///
50    /// * `model` - The model to which this variable belongs
51    /// * `lb` - Lower bound  
52    /// * `ub` - Upper bound
53    /// * `name` - The name of the intvar (automatically given if None)
54    /// * `bounded_domain` - Force bounded (true) or enumerated domain (false). If None, Choco will automatically choose the best option
55    ///
56    /// # Returns
57    ///
58    /// An IntVar instance
59    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        // Safety:
65        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
66        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            // Safety:
97            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
98            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        // Safety:
128        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
129        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        // Safety:
160        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
161        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        // Safety:
200        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
201        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        // Safety:
209        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
210        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                // Safety:
221                // Safe because IntVar is created from Model and therefore the backend is initialized, model handle is valid
222                // and get_intvar_value can be called only if the variable is instantiated.
223                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        // Safety:
236        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
237        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        // Safety:
248        // Safe because IntVar is created from Model and therefore the backend is initialized, model handle is valid and
249        // `get_domain_values` can be called only if the variable has enumerated domain.
250        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        // Safety:
268        // Safe because view is created from IntVar handle and therefore the backend is initialized.
269        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        // Safety:
283        // Safe because view is created from IntVar handle and therefore the backend is initialized.
284        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        // Safety:
298        // Safe because view is created from IntVar handle and therefore the backend is initialized.
299        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    /// Creates a boolean view representing the equality of the integer variable to a given value.
311    #[must_use]
312    pub fn eq_view(&self, value: i32) -> BoolVar<'model> {
313        CHOCO_BACKEND.with(|backend|
314            // Safety:
315            // Safe because view is created from IntVar handle and therefore the backend is initialized.
316            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    /// Creates a boolean view representing the "greater than or equal to" relation of the integer variable to a given value.
326    #[must_use]
327    pub fn ge_view(&self, value: i32) -> BoolVar<'model> {
328        CHOCO_BACKEND.with(|backend|
329            // Safety:
330            // Safe because view is created from IntVar handle and therefore the backend is initialized.
331            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    /// Creates a boolean view representing the "less than or equal to" relation of the integer variable to a given value.
340    #[must_use]
341    pub fn le_view(&self, value: i32) -> BoolVar<'model> {
342        CHOCO_BACKEND.with(|backend|
343            // Safety:
344            // Safe because view is created from IntVar handle and therefore the backend is initialized.
345            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    /// Creates a boolean view representing the "not equal to" relation of the integer variable to a given value.
355    #[must_use]
356    pub fn ne_view(&self, value: i32) -> BoolVar<'model> {
357        CHOCO_BACKEND.with(|backend|
358            // Safety:
359            // Safe because view is created from IntVar handle and therefore the backend is initialized.
360            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    /// Creates a two-operator arithmetic constraint associated with this model.
384    #[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    /// Posts a constraint that expresses: (self = y) <=> (b = true)
394    /// This bypass reification system.
395    #[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        // Safety:
402        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle
403        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    /// Posts a constraint that expresses: (self != y) <=> (b = true)
426    /// This bypass reification system.
427    #[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        // Safety:
434        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
435        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    /// Posts a constraint that expresses: (self < y) <=> (b = true)
458    /// This bypass reification system.
459    #[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        // Safety:
466        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
467        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    /// Posts a constraint that expresses: (self > y) <=> (b = true)
490    /// This bypass reification system.
491    #[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        // Safety:
498        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
499        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    /// Posts a constraint that expresses: (self <= y) <=> (b = true)
522    /// This bypass reification system.
523    #[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        // Safety:
530        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
531        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                    // For integer constants, x <= y is equivalent to x < y + 1
543                    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    /// Posts a constraint that expresses: (self >= y) <=> (b = true)
556    /// This bypass reification system.
557    #[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        // Safety:
564        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
565        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                    // For integer constants, x >= y is equivalent to x > y - 1
577                    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    ///  Posts a constraint that expresses : (self = y + c) <=> (b is true).
590    /// This bypass reification system.
591    pub fn reify_eq_yc(&self, y: &IntVar<'model>, c: i32, b: &BoolVar<'model>) {
592        // Safety:
593        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
594        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    ///  Posts a constraint that expresses : (self != y + c) <=> (b is true).
607    /// This bypass reification system.
608    pub fn reify_ne_yc(&self, y: &IntVar<'model>, c: i32, b: &BoolVar<'model>) {
609        // Safety:
610        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
611        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    ///  Posts a constraint that expresses : (self < y + c) <=> b.
624    /// This bypass reification system.
625    pub fn reify_lt_yc(&self, y: &IntVar<'model>, c: i32, b: &BoolVar<'model>) {
626        // Safety:
627        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
628        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    ///  Posts a constraint that expresses : (self > y + c) <=> b.
641    /// This bypass reification system.
642    pub fn reify_gt_yc(&self, y: &IntVar<'model>, c: i32, b: &BoolVar<'model>) {
643        // Safety:
644        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
645        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    ///  Creates a member constraint. Ensures `self` takes its values in `table`.
658    #[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            // Safety:
663        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
664            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    ///  Creates a member constraint. Ensures `self` takes its values in [`lb`, `ub`].
676    #[must_use]
677    pub fn member_bounds(&self, lb: i32, ub: i32) -> Constraint<'model> {
678        CHOCO_BACKEND.with(|backend|
679            // Safety:
680            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
681            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    /// Create not a member constraint. Ensures `self` does not take its values in `table`.
694    #[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            // Safety:
699            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
700            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    /// Create not a member constraint. Ensures `self` does not take its values in [`lb`, `ub`].
715    #[must_use]
716    pub fn not_member_bounds(&self, lb: i32, ub: i32) -> Constraint<'model> {
717        CHOCO_BACKEND.with(|backend|
718            // Safety:
719        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
720            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    /// Creates an absolute value constraint: `self` = | y |
736    #[must_use]
737    pub fn abs(&self, y: &IntVar<'model>) -> Constraint<'model> {
738        CHOCO_BACKEND.with(|backend|
739            // Safety:
740        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
741            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    ///  Creates a square constraint: `self` = y^2.
753    #[must_use]
754    pub fn square(&self, y: &IntVar<'model>) -> Constraint<'model> {
755        CHOCO_BACKEND.with(|backend|
756            // Safety:
757        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
758            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    /// Creates a power constraint: `self`^c = y
769    #[must_use]
770    pub fn pow(&self, c: i32, y: &IntVar<'model>) -> Constraint<'model> {
771        CHOCO_BACKEND.with(|backend|
772            // Safety:
773            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
774            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    ///  Creates a maximum constraint, `self` is the maximum value among IntVars in intvars.
787    #[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            // Safety:
792            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
793            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    ///  Creates a minimum constraint, `self` is the minimum value among IntVars in intvars.
806    #[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            // Safety:
811        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
812            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    /// Creates an among constraint.
824    /// `self` is the number of variables of the collection `intvars` that take their value in `values`.
825    ///
826    ///   Propagator :
827    ///
828    ///    C. Bessiere, E. Hebrard, B. Hnich, Z. Kiziltan, T. Walsh, Among, common and disjoint Constraints CP-2005
829    #[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            // Safety:
835            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
836            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            // Safety:
1122            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
1123            // Also, the handles passed are valid IntVar handles.
1124            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            // Safety:
1145            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
1146            // Also, the handles passed are valid IntVar handles.
1147            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            // Safety:
1168            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
1169            // Also, the handles passed are valid IntVar handles.
1170            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    /// Creates an all different constraint over a slice of integer variables.
1190    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        // Safety:
1197        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
1198        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            // Safety:
1219            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
1220            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            // Safety:
1240            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle
1241            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            // Safety:
1262            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle
1263            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        // Safety:
1287        // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
1288        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            // Safety:
1314            // Safe because IntVar is created from Model and therefore the backend is initialized and model handle is valid.
1315            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;