choco_solver/variables/intvar/
boolvar.rs1use std::borrow::Borrow;
2use std::ops::BitAnd;
3use std::ops::BitOr;
4use std::ops::Not;
5
6use super::{Handle, HandleT};
7use crate::CHOCO_LIB;
8use crate::Sealed;
9use crate::SolverError;
10
11use crate::CHOCO_BACKEND;
12use crate::constraint::Constraint;
13use crate::model::Model;
14use crate::utils;
15use crate::utils::ModelObject;
16use crate::variables::IntVar;
17use crate::variables::Variable;
18
19pub struct BoolVar<'model> {
24 int_var: IntVar<'model>,
25}
26
27impl HandleT for BoolVar<'_> {
28 fn get_raw_handle(&self) -> *mut std::os::raw::c_void {
29 self.int_var.get_raw_handle()
30 }
31}
32
33impl<'model> ModelObject<'model> for BoolVar<'model> {
34 fn get_model(&self) -> &'model Model {
35 self.int_var.get_model()
36 }
37}
38
39impl<'model> From<BoolVar<'model>> for IntVar<'model> {
40 fn from(bool_var: BoolVar<'model>) -> Self {
41 bool_var.int_var
42 }
43}
44
45impl<'model> TryFrom<IntVar<'model>> for BoolVar<'model> {
46 type Error = SolverError;
47
48 fn try_from(int_var: IntVar<'model>) -> Result<Self, Self::Error> {
49 let lb = int_var.lb();
50 let ub = int_var.ub();
51 if lb == 0 && ub == 1 {
52 Ok(BoolVar { int_var })
53 } else {
54 Err(SolverError::BoolVarConversionError)
55 }
56 }
57}
58
59impl<'model> Borrow<IntVar<'model>> for BoolVar<'model> {
60 fn borrow(&self) -> &IntVar<'model> {
61 &self.int_var
62 }
63}
64
65unsafe impl<'model> Variable<'model> for BoolVar<'model> {}
69
70impl<'model> BoolVar<'model> {
71 #[must_use]
77 pub(crate) fn new(model: &'model Model, value: Option<bool>, name: Option<&str>) -> Self {
78 let raw_handle = CHOCO_BACKEND.with(|backend| unsafe {
81 match name {
82 Some(name_str) => {
83 let c_name = std::ffi::CString::new(name_str)
84 .expect("Failed to convert name to CString");
85 match value {
86 Some(x) => CHOCO_LIB.Java_org_chocosolver_capi_BoolVarApi_boolVar_sb(
87 backend.thread,
88 model.get_raw_handle(),
89 c_name.as_ptr().cast_mut(),
90 i32::from(x),
91 ),
92 None => CHOCO_LIB.Java_org_chocosolver_capi_BoolVarApi_boolVar_s(
93 backend.thread,
94 model.get_raw_handle(),
95 c_name.as_ptr().cast_mut(),
96 ),
97 }
98 }
99 None => match value {
100 Some(x) => CHOCO_LIB.Java_org_chocosolver_capi_BoolVarApi_boolVar_b(
101 backend.thread,
102 model.get_raw_handle(),
103 i32::from(x),
104 ),
105 None => CHOCO_LIB.Java_org_chocosolver_capi_BoolVarApi_boolVar(
106 backend.thread,
107 model.get_raw_handle(),
108 ),
109 },
110 }
111 });
112 assert!(
113 !raw_handle.is_null(),
114 "Failed to create BoolVar: received null handle"
115 );
116
117 BoolVar {
118 int_var: IntVar {
119 handle: Handle::new(raw_handle),
120 model,
121 },
122 }
123 }
124
125 #[must_use]
126 pub(crate) fn not_view(bool_var: &BoolVar<'model>) -> BoolVar<'model> {
127 let view_handle = CHOCO_BACKEND.with(|backend| unsafe {
130 CHOCO_LIB.Java_org_chocosolver_capi_ViewApi_bool_not_view(
131 backend.thread,
132 bool_var.get_raw_handle(),
133 )
134 });
135 BoolVar {
136 int_var: IntVar {
137 handle: Handle::new(view_handle),
138 model: bool_var.int_var.model,
139 },
140 }
141 }
142
143 pub(crate) unsafe fn from_raw_handle(
155 handle: *mut std::os::raw::c_void,
156 model: &'model Model,
157 ) -> BoolVar<'model> {
158 BoolVar {
159 int_var: IntVar {
160 handle: Handle::new(handle),
161 model,
162 },
163 }
164 }
165
166 pub fn if_then_else(
169 &self,
170 then_constraint: &Constraint<'model>,
171 else_constraint: &Constraint<'model>,
172 ) {
173 CHOCO_BACKEND.with(|backend| unsafe {
176 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_if_then_else_bool(
177 backend.thread,
178 self.get_model().get_raw_handle(),
179 self.get_raw_handle(),
180 then_constraint.get_raw_handle(),
181 else_constraint.get_raw_handle(),
182 )
183 });
184 }
185
186 pub fn if_then(&self, then_constraint: &Constraint<'model>) {
188 CHOCO_BACKEND.with(|backend| unsafe {
191 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_if_then_bool(
192 backend.thread,
193 self.get_model().get_raw_handle(),
194 self.get_raw_handle(),
195 then_constraint.get_raw_handle(),
196 )
197 });
198 }
199
200 pub fn if_only_if(&self, constraint: &Constraint<'model>) {
203 CHOCO_BACKEND.with(|backend| unsafe {
206 CHOCO_LIB.Java_org_chocosolver_capi_ReificationApi_reification(
207 backend.thread,
208 self.get_model().get_raw_handle(),
209 self.get_raw_handle(),
210 constraint.get_raw_handle(),
211 )
212 });
213 }
214}
215
216impl<'model> BitAnd for &BoolVar<'model> {
217 type Output = BoolVar<'model>;
218
219 fn bitand(self, rhs: Self) -> Self::Output {
220 [self, rhs].and().reify()
221 }
222}
223
224impl<'model> BitAnd<bool> for &BoolVar<'model> {
225 type Output = BoolVar<'model>;
226
227 fn bitand(self, rhs: bool) -> Self::Output {
228 let rhs_bool_var = BoolVar::new(self.get_model(), Some(rhs), None);
229 [self, &rhs_bool_var].and().reify()
230 }
231}
232
233impl<'model> BitAnd<&BoolVar<'model>> for bool {
234 type Output = BoolVar<'model>;
235
236 fn bitand(self, rhs: &BoolVar<'model>) -> Self::Output {
237 let self_bool_var = BoolVar::new(rhs.get_model(), Some(self), None);
238 [&self_bool_var, rhs].and().reify()
239 }
240}
241
242impl<'model> BitOr for &BoolVar<'model> {
243 type Output = BoolVar<'model>;
244
245 fn bitor(self, rhs: Self) -> Self::Output {
246 [self, rhs].or().reify()
247 }
248}
249
250impl<'model> BitOr<bool> for &BoolVar<'model> {
251 type Output = BoolVar<'model>;
252
253 fn bitor(self, rhs: bool) -> Self::Output {
254 let rhs_bool_var = BoolVar::new(self.get_model(), Some(rhs), None);
255 [self, &rhs_bool_var].or().reify()
256 }
257}
258
259impl<'model> BitOr<&BoolVar<'model>> for bool {
260 type Output = BoolVar<'model>;
261
262 fn bitor(self, rhs: &BoolVar<'model>) -> Self::Output {
263 let self_bool_var = BoolVar::new(rhs.get_model(), Some(self), None);
264 [&self_bool_var, rhs].or().reify()
265 }
266}
267
268impl<'model> Not for &BoolVar<'model> {
269 type Output = BoolVar<'model>;
270
271 fn not(self) -> Self::Output {
272 BoolVar::not_view(self)
273 }
274}
275
276#[allow(private_bounds)]
277pub trait BoolVarArrayLogicOps<'model>: Sealed {
279 fn and(self) -> Constraint<'model>;
287 fn or(self) -> Constraint<'model>;
295}
296
297impl<'model, Q: Borrow<BoolVar<'model>> + Sealed> BoolVarArrayLogicOps<'model> for &[Q] {
298 fn and(self) -> Constraint<'model> {
299 let array_handle = utils::make_boolvar_array(self);
300 let model = self
301 .first()
302 .expect("Slice shall contains at least one element")
303 .borrow()
304 .get_model();
305 CHOCO_BACKEND.with(|backend|
306 unsafe {
309 let constraint_handle = CHOCO_LIB
310 .Java_org_chocosolver_capi_ConstraintApi_and_bv_bv(
311 backend.thread,
312 model.get_raw_handle(),
313 array_handle,
314 );
315 assert!(
316 !constraint_handle.is_null(),
317 "Failed to create AND constraint"
318 );
319 Constraint::new(constraint_handle, model)})
320 }
321 fn or(self) -> Constraint<'model> {
322 let array_handle = utils::make_boolvar_array(self);
323 let model = self
324 .first()
325 .expect("Slice shall contains at least one element")
326 .borrow()
327 .get_model();
328 CHOCO_BACKEND.with(|backend|
329 unsafe {
332 let constraint_handle = CHOCO_LIB
333 .Java_org_chocosolver_capi_ConstraintApi_or_bv_bv(
334 backend.thread,
335 model.get_raw_handle(),
336 array_handle,
337 );
338 assert!(
339 !constraint_handle.is_null(),
340 "Failed to create OR constraint"
341 );
342 Constraint::new(constraint_handle, model)
343 })
344 }
345}
346
347#[cfg(test)]
348mod tests;