1use serde::{Deserialize, Serialize};
4use std::cmp::Ordering;
5
6pub const GECODE_SET_MIN: i64 = -1073741822;
8pub const GECODE_SET_MAX: i64 = 1073741822;
9pub const GECODE_SET_CARDINALITY: i64 = 2147483645;
10
11use super::RelationMode;
12#[cfg(feature = "prepare")]
13use super::{ValueType, prepare::ArgumentType};
14
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(deny_unknown_fields)]
17struct IntegerRange {
18 #[serde(
19 serialize_with = "super::serialize_integer",
20 deserialize_with = "super::deserialize_integer"
21 )]
22 lower: i64,
23 #[serde(
24 serialize_with = "super::serialize_integer",
25 deserialize_with = "super::deserialize_integer"
26 )]
27 upper: i64,
28}
29
30#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
33pub struct IntegerSet {
34 ranges: Vec<IntegerRange>,
35}
36
37impl IntegerSet {
38 pub fn empty() -> Self {
39 Self::default()
40 }
41
42 pub fn interval(lower: i64, upper: i64) -> Self {
44 if lower > upper {
45 Self::empty()
46 } else {
47 Self {
48 ranges: vec![IntegerRange { lower, upper }],
49 }
50 }
51 }
52
53 pub fn from_values(values: impl IntoIterator<Item = i64>) -> Self {
54 Self::normalize(
55 values
56 .into_iter()
57 .map(|value| IntegerRange {
58 lower: value,
59 upper: value,
60 })
61 .collect(),
62 )
63 }
64
65 fn normalize(mut ranges: Vec<IntegerRange>) -> Self {
66 ranges.sort_unstable_by_key(|range| range.lower);
67 let mut merged: Vec<IntegerRange> = Vec::new();
68 for range in ranges {
69 if let Some(previous) = merged.last_mut()
70 && i128::from(range.lower) <= i128::from(previous.upper) + 1
71 {
72 previous.upper = previous.upper.max(range.upper);
73 } else {
74 merged.push(range);
75 }
76 }
77 Self { ranges: merged }
78 }
79
80 pub(crate) fn contiguous_bounds(&self) -> Option<(i64, i64)> {
81 match self.ranges.as_slice() {
82 [range] => Some((range.lower, range.upper)),
83 _ => None,
84 }
85 }
86
87 pub fn minimum(&self) -> Option<i64> {
88 self.ranges.first().map(|range| range.lower)
89 }
90
91 pub fn maximum(&self) -> Option<i64> {
92 self.ranges.last().map(|range| range.upper)
93 }
94
95 pub fn hull(&self) -> Self {
96 match (self.minimum(), self.maximum()) {
97 (Some(lower), Some(upper)) => Self::interval(lower, upper),
98 _ => Self::empty(),
99 }
100 }
101
102 pub fn is_convex(&self) -> bool {
103 self.ranges.len() <= 1
104 }
105
106 pub fn is_empty(&self) -> bool {
107 self.ranges.is_empty()
108 }
109
110 pub fn contains(&self, value: i64) -> bool {
111 let index = self.ranges.partition_point(|range| range.upper < value);
112 self.ranges
113 .get(index)
114 .is_some_and(|range| range.lower <= value)
115 }
116
117 pub fn is_subset(&self, other: &Self) -> bool {
118 let mut index = 0;
119 for range in &self.ranges {
120 while other
121 .ranges
122 .get(index)
123 .is_some_and(|candidate| candidate.upper < range.lower)
124 {
125 index += 1;
126 }
127 if !other.ranges.get(index).is_some_and(|candidate| {
128 candidate.lower <= range.lower && range.upper <= candidate.upper
129 }) {
130 return false;
131 }
132 }
133 true
134 }
135
136 pub fn union(&self, other: &Self) -> Self {
137 Self::normalize(self.ranges.iter().chain(&other.ranges).cloned().collect())
138 }
139
140 pub fn intersection(&self, other: &Self) -> Self {
141 let mut ranges = Vec::new();
142 let (mut left, mut right) = (0, 0);
143 while let (Some(a), Some(b)) = (self.ranges.get(left), other.ranges.get(right)) {
144 let (lower, upper) = (a.lower.max(b.lower), a.upper.min(b.upper));
145 if lower <= upper {
146 ranges.push(IntegerRange { lower, upper });
147 }
148 if a.upper < b.upper {
149 left += 1;
150 } else {
151 right += 1;
152 }
153 }
154 Self { ranges }
155 }
156
157 pub fn difference(&self, other: &Self) -> Self {
158 let mut ranges = Vec::new();
159 let mut right = 0;
160 for range in &self.ranges {
161 let mut lower = i128::from(range.lower);
162 let upper = i128::from(range.upper);
163 while other
164 .ranges
165 .get(right)
166 .is_some_and(|r| i128::from(r.upper) < lower)
167 {
168 right += 1;
169 }
170 let mut index = right;
171 while let Some(excluded) = other.ranges.get(index) {
172 if i128::from(excluded.lower) > upper {
173 break;
174 }
175 if lower < i128::from(excluded.lower) {
176 ranges.push(IntegerRange {
177 lower: lower as i64,
178 upper: excluded.lower - 1,
179 });
180 }
181 lower = lower.max(i128::from(excluded.upper) + 1);
182 if lower > upper {
183 break;
184 }
185 index += 1;
186 }
187 right = index;
188 if lower <= upper {
189 ranges.push(IntegerRange {
190 lower: lower as i64,
191 upper: range.upper,
192 });
193 }
194 }
195 Self { ranges }
196 }
197
198 pub fn symmetric_difference(&self, other: &Self) -> Self {
199 self.difference(other).union(&other.difference(self))
200 }
201
202 pub fn is_disjoint(&self, other: &Self) -> bool {
203 self.intersection(other).is_empty()
204 }
205
206 pub fn lex_cmp(&self, other: &Self) -> Ordering {
208 let (mut left, mut right) = (self.ranges.iter(), other.ranges.iter());
209 let (mut a, mut b) = (left.next().cloned(), right.next().cloned());
210 loop {
211 match (&mut a, &mut b) {
212 (None, None) => return Ordering::Equal,
213 (None, Some(_)) => return Ordering::Less,
214 (Some(_), None) => return Ordering::Greater,
215 (Some(x), Some(y)) => {
216 if x.lower != y.lower {
217 return x.lower.cmp(&y.lower);
218 }
219 match x.upper.cmp(&y.upper) {
220 Ordering::Equal => {
221 a = left.next().cloned();
222 b = right.next().cloned();
223 }
224 Ordering::Less => {
225 y.lower = x.upper + 1;
226 a = left.next().cloned();
227 }
228 Ordering::Greater => {
229 x.lower = y.upper + 1;
230 b = right.next().cloned();
231 }
232 }
233 }
234 }
235 }
236 }
237
238 pub fn characteristic_cmp(&self, other: &Self) -> Ordering {
240 let difference = self.symmetric_difference(other);
241 match difference.ranges.first() {
242 None => Ordering::Equal,
243 Some(range) if self.contains(range.lower) => Ordering::Greater,
244 Some(_) => Ordering::Less,
245 }
246 }
247
248 pub(crate) fn members(&self) -> impl Iterator<Item = i64> + '_ {
250 self.ranges
251 .iter()
252 .flat_map(|range| range.lower..=range.upper)
253 }
254
255 pub fn cardinality(&self) -> Option<i64> {
257 let size: i128 = self
258 .ranges
259 .iter()
260 .map(|range| i128::from(range.upper) - i128::from(range.lower) + 1)
261 .sum();
262 i64::try_from(size).ok()
263 }
264}
265
266impl<'de> Deserialize<'de> for IntegerSet {
267 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
268 #[derive(Deserialize)]
269 #[serde(deny_unknown_fields)]
270 struct SetFile {
271 ranges: Vec<IntegerRange>,
272 }
273 let set = SetFile::deserialize(deserializer)?;
274 if set.ranges.iter().any(|range| range.lower > range.upper)
275 || set
276 .ranges
277 .windows(2)
278 .any(|pair| i128::from(pair[0].upper) + 1 >= i128::from(pair[1].lower))
279 {
280 return Err(serde::de::Error::custom(
281 "integer set ranges must be sorted, nonempty, disjoint and nonadjacent",
282 ));
283 }
284 Ok(Self { ranges: set.ranges })
285 }
286}
287
288impl std::fmt::Display for IntegerSet {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 f.write_str("{")?;
291 for (index, range) in self.ranges.iter().enumerate() {
292 if index > 0 {
293 f.write_str(", ")?;
294 }
295 if range.lower == range.upper {
296 write!(f, "{}", range.lower)?;
297 } else {
298 write!(f, "{}..{}", range.lower, range.upper)?;
299 }
300 }
301 f.write_str("}")
302 }
303}
304
305#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
307#[serde(rename_all = "snake_case")]
308pub enum SetRelation {
309 Equal,
310 NotEqual,
311 Subset,
312 Superset,
313 LessEqual,
314 Less,
315 Disjoint,
316 Complement,
317 CharacteristicLessEqual,
318 CharacteristicLess,
319 CharacteristicGreaterEqual,
320 CharacteristicGreater,
321}
322
323impl SetRelation {
324 pub(crate) fn from_code(code: i64) -> Option<Self> {
325 Some(match code {
326 1 => Self::Equal,
327 2 => Self::NotEqual,
328 3 => Self::Subset,
329 4 => Self::Superset,
330 5 => Self::Disjoint,
331 6 => Self::Complement,
332 7 => Self::CharacteristicLessEqual,
333 8 => Self::CharacteristicLess,
334 9 => Self::CharacteristicGreaterEqual,
335 10 => Self::CharacteristicGreater,
336 _ => return None,
337 })
338 }
339
340 pub(crate) fn holds(self, left: &IntegerSet, right: &IntegerSet) -> bool {
341 match self {
342 Self::Equal => left == right,
343 Self::NotEqual => left != right,
344 Self::Subset => left.is_subset(right),
345 Self::Superset => right.is_subset(left),
346 Self::LessEqual => left.lex_cmp(right).is_le(),
347 Self::Less => left.lex_cmp(right).is_lt(),
348 Self::Disjoint => left.is_disjoint(right),
349 Self::Complement => {
350 let universe = IntegerSet::interval(GECODE_SET_MIN, GECODE_SET_MAX);
351 left.is_subset(&universe)
352 && right.is_subset(&universe)
353 && left.is_disjoint(right)
354 && left.union(right) == universe
355 }
356 Self::CharacteristicLessEqual => left.characteristic_cmp(right).is_le(),
357 Self::CharacteristicLess => left.characteristic_cmp(right).is_lt(),
358 Self::CharacteristicGreaterEqual => left.characteristic_cmp(right).is_ge(),
359 Self::CharacteristicGreater => left.characteristic_cmp(right).is_gt(),
360 }
361 }
362}
363
364impl std::fmt::Display for SetRelation {
365 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
366 f.write_str(match self {
367 Self::Equal => "=",
368 Self::NotEqual => "!=",
369 Self::Subset => "subset",
370 Self::Superset => "superset",
371 Self::LessEqual => "<= (sorted elements)",
372 Self::Less => "< (sorted elements)",
373 Self::Disjoint => "disjoint",
374 Self::Complement => "complement (-1073741822..1073741822)",
375 Self::CharacteristicLessEqual => "<= (characteristic order)",
376 Self::CharacteristicLess => "< (characteristic order)",
377 Self::CharacteristicGreaterEqual => ">= (characteristic order)",
378 Self::CharacteristicGreater => "> (characteristic order)",
379 })
380 }
381}
382
383#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
384#[serde(rename_all = "snake_case")]
385pub enum SetOperation {
386 Union,
387 Intersection,
388 Difference,
389 SymmetricDifference,
390}
391
392impl SetOperation {
393 pub(crate) fn calculate(self, left: &IntegerSet, right: &IntegerSet) -> IntegerSet {
394 match self {
395 Self::Union => left.union(right),
396 Self::Intersection => left.intersection(right),
397 Self::Difference => left.difference(right),
398 Self::SymmetricDifference => left.symmetric_difference(right),
399 }
400 }
401}
402
403impl std::fmt::Display for SetOperation {
404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
405 f.write_str(match self {
406 Self::Union => "union",
407 Self::Intersection => "intersect",
408 Self::Difference => "diff",
409 Self::SymmetricDifference => "symdiff",
410 })
411 }
412}
413
414#[derive(Clone, Copy, Debug, PartialEq, Eq)]
415pub(crate) enum SetKind {
416 Relation(SetRelation),
417 Membership { fixed: bool },
418 Cardinality,
419 Operation(SetOperation),
420 NativeRelation,
421}
422
423#[derive(Clone, Copy, Debug, PartialEq, Eq)]
424pub(crate) struct SetName {
425 pub kind: SetKind,
426 pub mode: RelationMode,
427}
428
429impl SetName {
430 pub fn from_name(name: &str) -> Option<Self> {
431 use RelationMode::*;
432 use SetKind::*;
433 use SetOperation::*;
434 use SetRelation::*;
435 let (kind, mode) = match name {
436 "disjoint" | "gecode_disjoint" | "fzn_disjoint" => (Relation(Disjoint), Plain),
437 "set_eq" | "gecode_set_eq" | "fzn_set_eq" => (Relation(Equal), Plain),
438 "set_eq_reif" | "gecode_set_eq_reif" | "fzn_set_eq_reif" => (Relation(Equal), Reified),
439 "set_ne" | "gecode_set_ne" | "fzn_set_ne" => (Relation(NotEqual), Plain),
440 "set_ne_reif" | "gecode_set_ne_reif" | "fzn_set_ne_reif" => {
441 (Relation(NotEqual), Reified)
442 }
443 "set_le" | "gecode_set_le" | "fzn_set_le" => (Relation(LessEqual), Plain),
444 "set_le_reif" | "gecode_set_le_reif" | "fzn_set_le_reif" => {
445 (Relation(LessEqual), Reified)
446 }
447 "set_lt" | "gecode_set_lt" | "fzn_set_lt" => (Relation(Less), Plain),
448 "set_lt_reif" | "gecode_set_lt_reif" | "fzn_set_lt_reif" => (Relation(Less), Reified),
449 "set_subset" | "gecode_set_subset" | "fzn_set_subset" => (Relation(Subset), Plain),
450 "set_subset_reif" | "gecode_set_subset_reif" | "fzn_set_subset_reif" => {
451 (Relation(Subset), Reified)
452 }
453 "set_superset" | "gecode_set_superset" | "fzn_set_superset" => {
454 (Relation(Superset), Plain)
455 }
456 "set_superset_reif" | "gecode_set_superset_reif" | "fzn_set_superset_reif" => {
457 (Relation(Superset), Reified)
458 }
459 "equal" | "gecode_equal" | "fzn_equal" => (Relation(Equal), Plain),
460 "equal_reif" | "gecode_equal_reif" | "fzn_equal_reif" => (Relation(Equal), Reified),
461 "set_in" | "gecode_set_in" | "fzn_set_in" => (Membership { fixed: false }, Plain),
462 "set_in_reif" | "gecode_set_in_reif" | "fzn_set_in_reif" => {
463 (Membership { fixed: false }, Reified)
464 }
465 "set_in_imp" | "gecode_set_in_imp" | "fzn_set_in_imp" => {
466 (Membership { fixed: false }, Implied)
467 }
468 "int_in" | "gecode_int_in" | "fzn_int_in" => (Membership { fixed: true }, Plain),
469 "int_in_reif" | "gecode_int_in_reif" | "fzn_int_in_reif" => {
470 (Membership { fixed: true }, Reified)
471 }
472 "int_in_imp" | "gecode_int_in_imp" | "fzn_int_in_imp" => {
473 (Membership { fixed: true }, Implied)
474 }
475 "set_union" | "gecode_set_union" | "fzn_set_union" => (Operation(Union), Plain),
476 "set_intersect" | "gecode_set_intersect" | "fzn_set_intersect" => {
477 (Operation(Intersection), Plain)
478 }
479 "set_diff" | "gecode_set_diff" | "fzn_set_diff" => (Operation(Difference), Plain),
480 "set_symdiff" | "gecode_set_symdiff" | "fzn_set_symdiff" => {
481 (Operation(SymmetricDifference), Plain)
482 }
483 "set_card" | "gecode_set_card" | "fzn_set_card" => (Cardinality, Plain),
484 "gecode_set_rel_imp_fzn"
485 | "gecode_gecode_set_rel_imp_fzn"
486 | "fzn_gecode_set_rel_imp_fzn" => (NativeRelation, Implied),
487 "set_eq_imp" => (Relation(Equal), Implied),
488 "set_ne_imp" => (Relation(NotEqual), Implied),
489 "set_le_imp" => (Relation(LessEqual), Implied),
490 "set_lt_imp" => (Relation(Less), Implied),
491 "set_subset_imp" => (Relation(Subset), Implied),
492 "set_superset_imp" => (Relation(Superset), Implied),
493 _ => return None,
494 };
495 Some(Self { kind, mode })
496 }
497
498 #[cfg(feature = "prepare")]
499 pub fn signature(self, element: ValueType) -> Vec<ArgumentType> {
500 let scalar = |kind, is_var| ArgumentType {
501 kind,
502 is_var,
503 is_array: false,
504 };
505 let set = scalar(ValueType::IntegerSet, true);
506 let mut arguments = match self.kind {
507 SetKind::Relation(_) => vec![set; 2],
508 SetKind::Membership { fixed } => vec![
509 scalar(element, true),
510 scalar(
511 ValueType::IntegerSet,
512 !fixed && element != ValueType::Boolean,
513 ),
514 ],
515 SetKind::Cardinality => vec![set, scalar(ValueType::Integer, true)],
516 SetKind::Operation(_) => vec![set; 3],
517 SetKind::NativeRelation => vec![set.clone(), scalar(ValueType::Integer, false), set],
518 };
519 if self.mode != RelationMode::Plain {
520 arguments.push(scalar(ValueType::Boolean, true));
521 }
522 arguments
523 }
524}