1use std::borrow::Borrow;
2use std::ffi::CStr;
3
4use crate::CHOCO_BACKEND;
5use crate::CHOCO_LIB;
6use crate::Sealed;
7use crate::SolverError;
8use crate::model::Model;
9use crate::utils::{Handle, HandleT, ModelObject, make_constraint_array};
10use crate::variables::{BoolVar, IntVar};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum EqualityOperator {
15 Eq,
16 Neq,
17 Lt,
18 Leq,
19 Gt,
20 Geq,
21}
22
23impl EqualityOperator {
24 #[must_use]
25 pub fn to_cstr(&self) -> &CStr {
26 match self {
27 EqualityOperator::Eq => c"=",
28 EqualityOperator::Neq => c"!=",
29 EqualityOperator::Lt => c"<",
30 EqualityOperator::Leq => c"<=",
31 EqualityOperator::Gt => c">",
32 EqualityOperator::Geq => c">=",
33 }
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum ArithmeticOperator {
40 Sum,
41 Sub,
42 Mul,
43 Div,
44}
45
46impl ArithmeticOperator {
47 #[must_use]
48 pub fn to_cstr(&self) -> &CStr {
49 match self {
50 ArithmeticOperator::Sum => c"+",
51 ArithmeticOperator::Sub => c"-",
52 ArithmeticOperator::Mul => c"*",
53 ArithmeticOperator::Div => c"/",
54 }
55 }
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum ConstraintStatus {
61 FREE,
63 POSTED,
65 REIFIED,
67}
68
69impl TryFrom<i32> for ConstraintStatus {
70 type Error = ();
71
72 fn try_from(value: i32) -> Result<Self, Self::Error> {
73 match value {
74 0 => Ok(ConstraintStatus::FREE),
75 1 => Ok(ConstraintStatus::POSTED),
76 2 => Ok(ConstraintStatus::REIFIED),
77 _ => Err(()),
78 }
79 }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub enum ESat {
88 True,
90 False,
92 Undefined,
94}
95
96pub trait ConstraintEquality<'model, Rhs> {
100 fn eq(self, other: Rhs) -> Constraint<'model>;
102 fn ne(self, other: Rhs) -> Constraint<'model>;
104}
105
106pub trait ArithmConstraint<'model, MOD, RES> {
108 fn modulo(&'model self, modulo: MOD, res: RES) -> Constraint<'model>;
110}
111
112pub struct Constraint<'model> {
117 handle: Handle,
118 model: &'model Model,
119}
120
121impl HandleT for Constraint<'_> {
122 fn get_raw_handle(&self) -> *mut std::os::raw::c_void {
123 self.handle.get_raw_handle()
124 }
125}
126impl<'model> ModelObject<'model> for Constraint<'model> {
127 fn get_model(&self) -> &'model Model {
128 self.model
129 }
130}
131
132impl<'model> Constraint<'model> {
133 pub(crate) unsafe fn new(handle: *mut std::os::raw::c_void, model: &'model Model) -> Self {
136 Constraint {
137 handle: Handle::new(handle),
138 model,
139 }
140 }
141
142 pub fn post(&self) -> Result<(), SolverError> {
143 if self.status() != ConstraintStatus::FREE {
144 Err(SolverError::NotFreeConstraint)
145 } else {
146 CHOCO_BACKEND.with(|backend| unsafe {
149 CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_post(
150 backend.thread,
151 self.get_raw_handle(),
152 )
153 });
154 Ok(())
155 }
156 }
157
158 #[must_use]
169 pub fn reify(&self) -> BoolVar<'model> {
170 CHOCO_BACKEND.with(|backend|
171 unsafe {
174 let var_handle = CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_reify(
175 backend.thread,
176 self.get_raw_handle(),
177 );
178 assert!(!var_handle.is_null(), "Failed to reify constraint");
179 BoolVar::from_raw_handle(var_handle, self.model)})
180 }
181
182 pub fn reify_with(&self, boolvar: &BoolVar<'model>) {
189 CHOCO_BACKEND.with(|backend| unsafe {
192 CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_reify_with(
193 backend.thread,
194 self.get_raw_handle(),
195 boolvar.get_raw_handle(),
196 )
197 });
198 }
199
200 pub fn implies(&self, boolvar: &BoolVar<'model>) {
207 CHOCO_BACKEND.with(|backend| unsafe {
210 CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_implies(
211 backend.thread,
212 self.get_raw_handle(),
213 boolvar.get_raw_handle(),
214 )
215 });
216 }
217
218 pub fn implied_by(&self, boolvar: &BoolVar<'model>) {
226 CHOCO_BACKEND.with(|backend| unsafe {
229 CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_implied_by(
230 backend.thread,
231 self.get_raw_handle(),
232 boolvar.get_raw_handle(),
233 )
234 });
235 }
236
237 #[must_use]
252 pub fn is_satisfied(&self) -> ESat {
253 let state = CHOCO_BACKEND.with(|backend| unsafe {
256 CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_is_satisfied(
257 backend.thread,
258 self.get_raw_handle(),
259 )
260 });
261 match state {
262 0 => ESat::False,
263 1 => ESat::True,
264 _ => ESat::Undefined,
265 }
266 }
267
268 #[must_use]
269 pub fn status(&self) -> ConstraintStatus {
270 let status_code = CHOCO_BACKEND.with(|backend| unsafe {
273 CHOCO_LIB.Java_org_chocosolver_capi_ConstraintApi_getStatus(
274 backend.thread,
275 self.get_raw_handle(),
276 )
277 });
278 match ConstraintStatus::try_from(status_code) {
279 Ok(status) => status,
280 Err(_) => panic!("Unknown constraint status code: {}", status_code),
281 }
282 }
283 pub fn if_then_else(
286 &self,
287 then_constraint: &Constraint<'model>,
288 else_constraint: &Constraint<'model>,
289 ) {
290 CHOCO_BACKEND.with(|backend| unsafe {
293 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_if_then_else(
294 backend.thread,
295 self.model.get_raw_handle(),
296 self.get_raw_handle(),
297 then_constraint.get_raw_handle(),
298 else_constraint.get_raw_handle(),
299 )
300 });
301 }
302 pub fn if_then(&self, then_constraint: &Constraint<'model>) {
304 CHOCO_BACKEND.with(|backend| unsafe {
307 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_if_then(
308 backend.thread,
309 self.model.get_raw_handle(),
310 self.get_raw_handle(),
311 then_constraint.get_raw_handle(),
312 )
313 });
314 }
315
316 pub fn if_only_if(&self, constraint: &Constraint<'model>) {
319 CHOCO_BACKEND.with(|backend| unsafe {
322 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_if_only_if(
323 backend.thread,
324 self.model.get_raw_handle(),
325 self.get_raw_handle(),
326 constraint.get_raw_handle(),
327 )
328 });
329 }
330}
331
332unsafe trait IntoRawIntVarHandleT: Copy {
335 fn into_raw_ptr(self, model: &Model) -> *mut std::os::raw::c_void;
336}
337
338unsafe impl<'model, T: Borrow<IntVar<'model>>> IntoRawIntVarHandleT for &T {
341 fn into_raw_ptr(self, _model: &Model) -> *mut std::os::raw::c_void {
342 self.borrow().get_raw_handle()
343 }
344}
345unsafe impl IntoRawIntVarHandleT for i32 {
349 fn into_raw_ptr(self, model: &Model) -> *mut std::os::raw::c_void {
350 CHOCO_BACKEND.with(|backend| unsafe {
353 CHOCO_LIB.Java_org_chocosolver_capi_IntVarApi_intVar_i(
354 backend.thread,
355 model.get_raw_handle(),
356 self,
357 )
358 })
359 }
360}
361
362pub(crate) trait ConstraintArithmT<'model> {
363 fn create(&self) -> Constraint<'model>;
364}
365
366impl<'model, X: Borrow<IntVar<'model>>> ConstraintArithmT<'model> for (X, EqualityOperator, i32) {
367 fn create(&self) -> Constraint<'model> {
368 let int_var = self.0.borrow();
369 CHOCO_BACKEND.with(|backend|
370 unsafe {
373 let constraint_handle = CHOCO_LIB
374 .Java_org_chocosolver_capi_ConstraintApi_arithm_iv_cst(
375 backend.thread,
376 int_var.get_model().get_raw_handle(),
377 int_var.get_raw_handle(),
378 self.1.to_cstr().as_ptr().cast_mut(),
379 self.2,
380 );
381assert!(
382 !constraint_handle.is_null(),
383 "Invalid parameters combination for arithm constraint. Please refer to the doc"
384 );
385 Constraint::new(constraint_handle, int_var.get_model())})
386 }
387}
388
389impl<'model, X: Borrow<IntVar<'model>>, Y: Borrow<IntVar<'model>>> ConstraintArithmT<'model>
390 for (X, EqualityOperator, Y)
391{
392 fn create(&self) -> Constraint<'model> {
393 let x_var = self.0.borrow();
394 let y_var = self.2.borrow();
395 CHOCO_BACKEND.with(|backend|
396unsafe {
399 let constraint_handle = CHOCO_LIB
400 .Java_org_chocosolver_capi_ConstraintApi_arithm_iv_iv(
401 backend.thread,
402 x_var.get_model().get_raw_handle(),
403 x_var.get_raw_handle(),
404 self.1.to_cstr().as_ptr().cast_mut(),
405 y_var.get_raw_handle(),
406 );
407assert!(
408 !constraint_handle.is_null(),
409 "Invalid parameters combination for arithm constraint. Please refer to the doc"
410 );
411 Constraint::new(constraint_handle, x_var.get_model())})
412 }
413}
414
415impl<'model, X: Borrow<IntVar<'model>>, Y: IntoRawIntVarHandleT> ConstraintArithmT<'model>
416 for (X, EqualityOperator, Y, ArithmeticOperator, &IntVar<'model>)
417{
418 fn create(&self) -> Constraint<'model> {
419 let x_var = self.0.borrow();
420 let yy = self.2.into_raw_ptr(x_var.get_model());
421 assert!(
422 !yy.is_null(),
423 "Failed to convert parameter to raw pointer for arithm constraint"
424 );
425
426 CHOCO_BACKEND.with(|backend|
427unsafe {
430 let constraint_handle = CHOCO_LIB
431 .Java_org_chocosolver_capi_ConstraintApi_arithm_iv_iv_iv(
432 backend.thread,
433 x_var.get_model().get_raw_handle(),
434 x_var.get_raw_handle(),
435 self.1.to_cstr().as_ptr().cast_mut(),
436 yy,
437 self.3.to_cstr().as_ptr().cast_mut(),
438 self.4.get_raw_handle(),
439 );
440 assert!(
441 !constraint_handle.is_null(),
442 "Invalid parameters combination for arithm constraint. Please refer to the doc"
443 );
444 Constraint::new(constraint_handle, x_var.get_model())})
445 }
446}
447impl<'model, X: Borrow<IntVar<'model>>, Y: IntoRawIntVarHandleT> ConstraintArithmT<'model>
448 for (X, EqualityOperator, Y, ArithmeticOperator, i32)
449{
450 fn create(&self) -> Constraint<'model> {
451 let x_var = self.0.borrow();
452 let yy = self.2.into_raw_ptr(x_var.get_model());
453
454 CHOCO_BACKEND.with(|backend|
455 unsafe {
458 let constraint_handle = CHOCO_LIB
459 .Java_org_chocosolver_capi_ConstraintApi_arithm_iv_iv_cst(
460 backend.thread,
461 x_var.get_model().get_raw_handle(),
462 x_var.get_raw_handle(),
463 self.1.to_cstr().as_ptr().cast_mut(),
464 yy,
465 self.3.to_cstr().as_ptr().cast_mut(),
466 self.4,
467 );
468 assert!(
469 !constraint_handle.is_null(),
470 "Invalid parameters combination for arithm constraint. Please refer to the doc");
471 Constraint::new(constraint_handle, x_var.get_model())
472 })
473 }
474}
475
476impl<'model, X: Borrow<IntVar<'model>>, Y: IntoRawIntVarHandleT> ConstraintArithmT<'model>
477 for (X, ArithmeticOperator, Y, EqualityOperator, &IntVar<'model>)
478{
479 fn create(&self) -> Constraint<'model> {
480 let x_var = self.0.borrow();
481 let yy = self.2.into_raw_ptr(x_var.get_model());
482 assert!(
483 !yy.is_null(),
484 "Failed to convert parameter to raw pointer for arithm constraint"
485 );
486
487 CHOCO_BACKEND.with(|backend|
488 unsafe {
491 let constraint_handle =CHOCO_LIB
492 .Java_org_chocosolver_capi_ConstraintApi_arithm_iv_iv_iv(
493 backend.thread,
494 x_var.get_model().get_raw_handle(),
495 x_var.get_raw_handle(),
496 self.1.to_cstr().as_ptr().cast_mut(),
497 yy,
498 self.3.to_cstr().as_ptr().cast_mut(),
499 self.4.get_raw_handle(),
500 );
501 assert!(
502 !constraint_handle.is_null(),
503 "Invalid parameters combination for arithm constraint. Please refer to the doc");
504 Constraint::new(constraint_handle, x_var.get_model())
505 })
506 }
507}
508impl<'model, X: Borrow<IntVar<'model>>, Y: IntoRawIntVarHandleT> ConstraintArithmT<'model>
509 for (X, ArithmeticOperator, Y, EqualityOperator, i32)
510{
511 fn create(&self) -> Constraint<'model> {
512 let x_var = self.0.borrow();
513 let yy = self.2.into_raw_ptr(x_var.get_model());
514
515 CHOCO_BACKEND.with(|backend|
516 unsafe {
519 let constraint_handle = CHOCO_LIB
520 .Java_org_chocosolver_capi_ConstraintApi_arithm_iv_iv_cst(
521 backend.thread,
522 x_var.get_model().get_raw_handle(),
523 x_var.get_raw_handle(),
524 self.1.to_cstr().as_ptr().cast_mut(),
525 yy,
526 self.3.to_cstr().as_ptr().cast_mut(),
527 self.4,
528 );
529 assert!(
530 !constraint_handle.is_null(),
531 "Invalid parameters combination for arithm constraint. Please refer to the doc");
532 Constraint::new(constraint_handle, x_var.get_model())
533 })
534 }
535}
536#[allow(private_bounds)]
537pub trait ConstraintArrayLogicOps<'model>: Sealed {
539 fn and(self) -> Constraint<'model>;
547 fn or(self) -> Constraint<'model>;
555}
556
557impl<'model, Q: Borrow<Constraint<'model>> + Sealed> ConstraintArrayLogicOps<'model> for &[Q] {
558 fn and(self) -> Constraint<'model> {
559 let array_handle = make_constraint_array(self);
560 let model = self
561 .first()
562 .expect("Slice shall contains at least one element")
563 .borrow()
564 .get_model();
565 CHOCO_BACKEND.with(|backend|
566 unsafe {
569 let constraint_handle =CHOCO_LIB
570 .Java_org_chocosolver_capi_ConstraintApi_and_cs_cs(
571 backend.thread,
572 model.get_raw_handle(),
573 array_handle,
574 );
575 assert!(
576 !constraint_handle.is_null(),
577 "Failed to create AND constraint"
578 );
579 Constraint::new(constraint_handle, model)
580 })
581 }
582 fn or(self) -> Constraint<'model> {
583 let array_handle = make_constraint_array(self);
584 let model = self
585 .first()
586 .expect("Slice shall contains at least one element")
587 .borrow()
588 .get_model();
589 CHOCO_BACKEND.with(|backend|
590 unsafe {
593 let constraint_handle = CHOCO_LIB
594 .Java_org_chocosolver_capi_ConstraintApi_or_cs_cs(
595 backend.thread,
596 model.get_raw_handle(),
597 array_handle,
598 );
599 assert!(!constraint_handle.is_null(),
600 "Failed to create OR constraint"
601 );
602 Constraint::new(constraint_handle, model)
603 })
604 }
605}
606
607#[cfg(test)]
608mod tests;