1use super::*;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub(crate) enum SetChannelName {
6 Link,
7 IntSet,
8 Inverse,
9 Range,
10 Precede,
11 Sorted,
12 Selected {
13 operation: SetAggregate,
14 explicit_universe: bool,
15 },
16}
17impl SetChannelName {
18 pub fn from_name(name: &str) -> Option<Self> {
19 for base in [
20 name,
21 name.strip_prefix("gecode_").unwrap_or(""),
22 name.strip_prefix("fzn_").unwrap_or(""),
23 ] {
24 return Some(match base {
25 "gecode_link_set_to_booleans" => Self::Link,
26 "gecode_int_set_channel" => Self::IntSet,
27 "gecode_inverse_set" => Self::Inverse,
28 "gecode_range" => Self::Range,
29 "gecode_precede_set" => Self::Precede,
30 "gecode_set_channel_sorted" => Self::Sorted,
31 "gecode_array_set_element_union" => Self::Selected {
32 operation: SetAggregate::Union,
33 explicit_universe: false,
34 },
35 "gecode_array_set_element_intersect" => Self::Selected {
36 operation: SetAggregate::Intersection,
37 explicit_universe: false,
38 },
39 "gecode_array_set_element_partition" => Self::Selected {
40 operation: SetAggregate::Partition,
41 explicit_universe: false,
42 },
43 "gecode_array_set_element_intersect_in" => Self::Selected {
44 operation: SetAggregate::Intersection,
45 explicit_universe: true,
46 },
47 _ => continue,
48 });
49 }
50 None
51 }
52 #[cfg(feature = "prepare")]
53 pub fn signature(self) -> Vec<prepare::ArgumentType> {
54 use ValueType::*;
55 let scalar = |kind, is_var| prepare::ArgumentType {
56 kind,
57 is_var,
58 is_array: false,
59 };
60 let array = |kind| prepare::ArgumentType {
61 kind,
62 is_var: true,
63 is_array: true,
64 };
65 let set = scalar(IntegerSet, true);
66 let fixed = scalar(Integer, false);
67 match self {
68 Self::Link => vec![set, array(Boolean), fixed],
69 Self::IntSet => vec![array(Integer), fixed.clone(), array(IntegerSet), fixed],
70 Self::Inverse => vec![array(IntegerSet), array(IntegerSet), fixed.clone(), fixed],
71 Self::Range => vec![array(Integer), fixed, set.clone(), set],
72 Self::Precede => vec![array(IntegerSet), fixed.clone(), fixed],
73 Self::Sorted => vec![array(Integer), set],
74 Self::Selected {
75 explicit_universe, ..
76 } => {
77 let mut args = vec![set.clone(), array(IntegerSet), set];
78 if explicit_universe {
79 args.push(scalar(IntegerSet, false));
80 }
81 args
82 }
83 }
84 }
85}
86
87#[derive(Debug, Serialize, Deserialize)]
88pub(crate) enum SetChannel {
89 Link {
90 set: Operand,
91 flags: Vec<Operand>,
92 #[serde(
93 serialize_with = "serialize_integer",
94 deserialize_with = "deserialize_integer"
95 )]
96 offset: i64,
97 },
98 IntSet {
99 integers: Vec<Operand>,
100 sets: Vec<Operand>,
101 #[serde(
102 serialize_with = "serialize_integer",
103 deserialize_with = "deserialize_integer"
104 )]
105 integer_offset: i64,
106 #[serde(
107 serialize_with = "serialize_integer",
108 deserialize_with = "deserialize_integer"
109 )]
110 set_offset: i64,
111 },
112 Inverse {
113 forward: Vec<Operand>,
114 inverse: Vec<Operand>,
115 #[serde(
116 serialize_with = "serialize_integer",
117 deserialize_with = "deserialize_integer"
118 )]
119 forward_offset: i64,
120 #[serde(
121 serialize_with = "serialize_integer",
122 deserialize_with = "deserialize_integer"
123 )]
124 inverse_offset: i64,
125 },
126 Range {
127 integers: Vec<Operand>,
128 #[serde(
129 serialize_with = "serialize_integer",
130 deserialize_with = "deserialize_integer"
131 )]
132 offset: i64,
133 selection: Operand,
134 result: Operand,
135 },
136 Precede {
137 sets: Vec<Operand>,
138 #[serde(
139 serialize_with = "serialize_integer",
140 deserialize_with = "deserialize_integer"
141 )]
142 first: i64,
143 #[serde(
144 serialize_with = "serialize_integer",
145 deserialize_with = "deserialize_integer"
146 )]
147 second: i64,
148 },
149 Sorted {
150 integers: Vec<Operand>,
151 set: Operand,
152 },
153 Selected {
154 operation: SetAggregate,
155 indices: Operand,
156 sets: Vec<Operand>,
157 result: Operand,
158 universe: Option<IntegerSet>,
159 },
160}
161
162#[derive(Clone, Debug, Serialize)]
164pub struct SetChannelArgument {
165 pub role: SetChannelSide,
166 pub position: Option<usize>,
167 #[serde(serialize_with = "serialize_optional_integer")]
168 pub index: Option<i64>,
169 pub value: Option<ArgumentValue>,
170 pub unresolved: Option<Box<VariableRef>>,
171}
172#[derive(Clone, Copy, Debug, Serialize)]
173#[serde(rename_all = "snake_case")]
174pub enum SetChannelSide {
175 Set,
176 Flags,
177 Integers,
178 Sets,
179 Forward,
180 Inverse,
181 Selection,
182 Result,
183}
184#[derive(Clone, Debug, Serialize)]
185#[serde(tag = "kind", rename_all = "snake_case")]
186pub enum SetChannelFault {
187 Outside {
188 side: SetChannelSide,
189 position: Option<usize>,
190 members: IntegerSet,
191 allowed: IntegerSet,
192 },
193 Membership {
194 position: usize,
195 #[serde(serialize_with = "serialize_integer")]
196 index: i64,
197 set_position: usize,
198 #[serde(serialize_with = "serialize_integer")]
199 set_index: i64,
200 expected: bool,
201 },
202 MembershipCount {
203 position: usize,
204 #[serde(serialize_with = "serialize_integer")]
205 index: i64,
206 memberships: IntegerSet,
207 },
208 Padding {
209 integer_indices: IntegerSet,
210 set_indices: IntegerSet,
211 },
212 Mismatch {
213 side: SetChannelSide,
214 position: Option<usize>,
215 expected: Value,
216 },
217 Partition {
218 first: usize,
219 second: usize,
220 intersection: IntegerSet,
221 },
222 Precedence {
223 position: usize,
224 },
225 Order {
226 first: usize,
227 second: usize,
228 },
229 Cardinality {
230 #[serde(serialize_with = "serialize_integer")]
231 expected: i64,
232 #[serde(serialize_with = "serialize_integer")]
233 actual: i64,
234 },
235}
236#[derive(Clone, Debug, Serialize)]
237#[serde(tag = "operation", rename_all = "snake_case")]
238pub enum SetChannelFinding {
239 Link {
240 arguments: Vec<SetChannelArgument>,
241 #[serde(serialize_with = "serialize_integer")]
242 offset: i64,
243 faults: Vec<SetChannelFault>,
244 },
245 IntSet {
246 arguments: Vec<SetChannelArgument>,
247 #[serde(serialize_with = "serialize_integer")]
248 integer_offset: i64,
249 #[serde(serialize_with = "serialize_integer")]
250 set_offset: i64,
251 faults: Vec<SetChannelFault>,
252 },
253 Inverse {
254 arguments: Vec<SetChannelArgument>,
255 #[serde(serialize_with = "serialize_integer")]
256 forward_offset: i64,
257 #[serde(serialize_with = "serialize_integer")]
258 inverse_offset: i64,
259 faults: Vec<SetChannelFault>,
260 },
261 Range {
262 arguments: Vec<SetChannelArgument>,
263 #[serde(serialize_with = "serialize_integer")]
264 offset: i64,
265 faults: Vec<SetChannelFault>,
266 },
267 Precede {
268 arguments: Vec<SetChannelArgument>,
269 #[serde(serialize_with = "serialize_integer")]
270 first: i64,
271 #[serde(serialize_with = "serialize_integer")]
272 second: i64,
273 faults: Vec<SetChannelFault>,
274 },
275 Sorted {
276 arguments: Vec<SetChannelArgument>,
277 faults: Vec<SetChannelFault>,
278 },
279 Selected {
280 arguments: Vec<SetChannelArgument>,
281 aggregate: SetAggregate,
282 universe: Option<IntegerSet>,
283 faults: Vec<SetChannelFault>,
284 },
285}
286
287impl SetChannel {
288 pub fn name(&self) -> SetChannelName {
289 match self {
290 Self::Link { .. } => SetChannelName::Link,
291 Self::IntSet { .. } => SetChannelName::IntSet,
292 Self::Inverse { .. } => SetChannelName::Inverse,
293 Self::Range { .. } => SetChannelName::Range,
294 Self::Precede { .. } => SetChannelName::Precede,
295 Self::Sorted { .. } => SetChannelName::Sorted,
296 Self::Selected {
297 operation,
298 universe,
299 ..
300 } => SetChannelName::Selected {
301 operation: *operation,
302 explicit_universe: universe.is_some(),
303 },
304 }
305 }
306 pub fn validate_shape(&self) -> Result<(), &'static str> {
307 match self {
308 Self::Link { flags, offset, .. } => {
309 checked_length(*offset, flags.len())?;
310 if *offset - 1 > GECODE_SET_MAX {
311 return Err("Boolean channel prefix exceeds Gecode set limits");
312 }
313 }
314 Self::IntSet {
315 integers,
316 sets,
317 integer_offset,
318 set_offset,
319 } => {
320 let n = integer_length(*integer_offset, integers.len())?;
321 let m = checked_length(*set_offset, sets.len())?;
322 if *set_offset > 0 {
323 check_set_constant(*integer_offset - 1)?;
324 }
325 if !sets.is_empty() {
327 check_set_constant(*integer_offset)?;
328 check_set_constant(n - 1)?;
329 }
330 if !integers.is_empty() && (*set_offset > 2147483646 || m - 1 > 2147483646) {
331 return Err("integer channel domain exceeds Gecode integer limits");
332 }
333 }
334 Self::Inverse {
335 forward,
336 inverse,
337 forward_offset,
338 inverse_offset,
339 } => {
340 checked_length(*forward_offset, forward.len())?;
341 checked_length(*inverse_offset, inverse.len())?;
342 }
343 Self::Range {
344 integers, offset, ..
345 } => {
346 integer_length(*offset, integers.len())?;
347 }
348 Self::Precede { first, second, .. } => {
349 check_set_constant(*first)?;
350 check_set_constant(*second)?;
351 }
352 Self::Selected {
353 operation,
354 sets,
355 universe,
356 ..
357 } => {
358 if !matches!(
359 operation,
360 SetAggregate::Union | SetAggregate::Intersection | SetAggregate::Partition
361 ) || universe.is_some() && *operation != SetAggregate::Intersection
362 {
363 return Err("invalid selected-set operation or universe");
364 }
365 checked_length(1, sets.len())?;
366 if let Some(universe) = universe
367 && !universe.is_subset(&IntegerSet::interval(
368 i64::from(i32::MIN),
369 i64::from(i32::MAX),
370 ))
371 {
372 return Err("fixed intersection universe exceeds native integer bounds");
373 }
374 }
375 Self::Sorted { .. } => {}
376 }
377 Ok(())
378 }
379 pub fn typed_operands(&self) -> Vec<(&Operand, ValueType)> {
380 use ValueType::*;
381 fn array(entries: &[Operand], kind: ValueType) -> Vec<(&Operand, ValueType)> {
382 entries.iter().map(|entry| (entry, kind)).collect()
383 }
384 match self {
385 Self::Link { set, flags, .. } => std::iter::once((set, IntegerSet))
386 .chain(array(flags, Boolean))
387 .collect(),
388 Self::IntSet { integers, sets, .. } => array(integers, Integer)
389 .into_iter()
390 .chain(array(sets, IntegerSet))
391 .collect(),
392 Self::Inverse {
393 forward, inverse, ..
394 } => array(forward, IntegerSet)
395 .into_iter()
396 .chain(array(inverse, IntegerSet))
397 .collect(),
398 Self::Range {
399 integers,
400 selection,
401 result,
402 ..
403 } => array(integers, Integer)
404 .into_iter()
405 .chain([(selection, IntegerSet), (result, IntegerSet)])
406 .collect(),
407 Self::Precede { sets, .. } => array(sets, IntegerSet),
408 Self::Sorted { integers, set } => array(integers, Integer)
409 .into_iter()
410 .chain([(set, IntegerSet)])
411 .collect(),
412 Self::Selected {
413 indices,
414 sets,
415 result,
416 ..
417 } => std::iter::once((indices, IntegerSet))
418 .chain(array(sets, IntegerSet))
419 .chain([(result, IntegerSet)])
420 .collect(),
421 }
422 }
423 pub fn operands(&self) -> Vec<&Operand> {
424 self.typed_operands()
425 .into_iter()
426 .map(|(operand, _)| operand)
427 .collect()
428 }
429 pub fn required_operands(&self, values: &[Option<Value>]) -> Vec<&Operand> {
430 if self
431 .faults(values)
432 .map_or(true, |faults| !faults.is_empty())
433 {
434 return Vec::new();
435 }
436 match self {
437 Self::Selected {
438 indices,
439 sets,
440 result,
441 ..
442 } => {
443 let mut required = vec![indices, result];
444 if let Some(selected) = indices.value(values) {
445 required.extend(
446 sets.iter()
447 .enumerate()
448 .filter(|(i, _)| selected.set().contains(label(1, *i)))
449 .map(|(_, operand)| operand),
450 );
451 }
452 required
453 }
454 Self::Range {
455 integers,
456 offset,
457 selection,
458 result,
459 } => {
460 let mut required = vec![selection, result];
461 if let Some(selected) = selection.value(values) {
462 required.extend(
463 integers
464 .iter()
465 .enumerate()
466 .filter(|(i, _)| selected.set().contains(label(*offset, *i)))
467 .map(|(_, operand)| operand),
468 );
469 }
470 required
471 }
472 Self::Precede {
473 sets,
474 first,
475 second,
476 } if sets.is_empty() || first == second => Vec::new(),
477 _ => self.operands(),
478 }
479 }
480 pub fn array_outputs(&self) -> Vec<(&[Operand], ValueType)> {
481 match self {
482 Self::Link { flags, .. } => vec![(flags, ValueType::Boolean)],
483 Self::IntSet { integers, sets, .. } => vec![
484 (integers, ValueType::Integer),
485 (sets, ValueType::IntegerSet),
486 ],
487 Self::Inverse {
488 forward, inverse, ..
489 } => vec![
490 (forward, ValueType::IntegerSet),
491 (inverse, ValueType::IntegerSet),
492 ],
493 Self::Sorted { integers, .. } => vec![(integers, ValueType::Integer)],
494 _ => Vec::new(),
495 }
496 }
497 pub fn can_define(&self, output: usize) -> bool {
498 let is_output =
499 |operand: &Operand| matches!(operand, Operand::Variable(slot) if *slot == output);
500 let contains_output = |operands: &[Operand]| operands.iter().any(is_output);
501 match self {
502 Self::Link { set, flags, .. } => is_output(set) != contains_output(flags),
503 Self::IntSet { integers, sets, .. } => {
504 contains_output(integers) != contains_output(sets)
505 }
506 Self::Inverse {
507 forward, inverse, ..
508 } => contains_output(forward) != contains_output(inverse),
509 Self::Sorted { integers, set } => is_output(set) != contains_output(integers),
510 Self::Range {
511 integers,
512 selection,
513 result,
514 ..
515 } => is_output(result) && !is_output(selection) && !contains_output(integers),
516 Self::Selected {
518 indices, result, ..
519 } => is_output(result) && !is_output(indices),
520 Self::Precede { .. } => false,
521 }
522 }
523 pub fn derive(
524 &self,
525 output: usize,
526 values: &[Option<Value>],
527 constraint: &Constraint,
528 ) -> Result<Option<Value>, CheckError> {
529 let is_output =
530 |operand: &Operand| matches!(operand, Operand::Variable(slot) if *slot == output);
531 let mut candidates = Vec::new();
532 match self {
533 Self::Selected {
534 operation,
535 indices,
536 sets,
537 universe,
538 ..
539 } => {
540 return Ok(
541 selected_set(*operation, indices, sets, universe.as_ref(), values)
542 .map(Value::IntegerSet),
543 );
544 }
545 Self::Range {
546 integers,
547 offset,
548 selection,
549 ..
550 } => return Ok(range_set(integers, *offset, selection, values).map(Value::IntegerSet)),
551 Self::Link { set, flags, offset } => {
552 if is_output(set) {
553 return Ok(link_set(flags, *offset, values).map(Value::IntegerSet));
554 }
555 let Some(set) = set.value(values) else {
556 return Ok(None);
557 };
558 for (i, _) in flags.iter().enumerate().filter(|(_, flag)| is_output(flag)) {
559 candidates.push(Value::Boolean(set.set().contains(label(*offset, i))));
560 }
561 }
562 Self::IntSet {
563 integers,
564 sets,
565 integer_offset,
566 set_offset,
567 } => {
568 if sets.iter().any(is_output) {
569 let Some(integers) = integer_values(integers, values) else {
570 return Ok(None);
571 };
572 for (j, _) in sets.iter().enumerate().filter(|(_, set)| is_output(set)) {
573 let bucket = label(*set_offset, j);
574 let mut members = IntegerSet::from_values(
575 integers
576 .iter()
577 .enumerate()
578 .filter(|(_, value)| **value == bucket)
579 .map(|(i, _)| label(*integer_offset, i)),
580 );
581 if bucket == 0 && !integers.is_empty() {
582 members = members.union(&IntegerSet::interval(0, *integer_offset - 1));
583 }
584 candidates.push(Value::IntegerSet(members));
585 }
586 } else {
587 let Some(sets) = set_values(sets, values) else {
588 return Ok(None);
589 };
590 for (i, _) in integers
591 .iter()
592 .enumerate()
593 .filter(|(_, integer)| is_output(integer))
594 {
595 let memberships: Vec<_> = sets
596 .iter()
597 .enumerate()
598 .filter(|(_, set)| set.contains(label(*integer_offset, i)))
599 .map(|(j, _)| label(*set_offset, j))
600 .collect();
601 if memberships.len() != 1 {
602 return Ok(None);
603 }
604 candidates.push(Value::Integer(memberships[0]));
605 }
606 }
607 }
608 Self::Inverse {
609 forward,
610 inverse,
611 forward_offset,
612 inverse_offset,
613 } => {
614 let (inputs, input_offset, targets, target_offset) =
615 if forward.iter().any(is_output) {
616 (inverse, *inverse_offset, forward, *forward_offset)
617 } else {
618 (forward, *forward_offset, inverse, *inverse_offset)
619 };
620 let Some(inputs) = set_values(inputs, values) else {
621 return Ok(None);
622 };
623 for (i, _) in targets
624 .iter()
625 .enumerate()
626 .filter(|(_, target)| is_output(target))
627 {
628 candidates.push(Value::IntegerSet(IntegerSet::from_values(
629 inputs
630 .iter()
631 .enumerate()
632 .filter(|(_, set)| set.contains(label(target_offset, i)))
633 .map(|(j, _)| label(input_offset, j)),
634 )));
635 }
636 }
637 Self::Sorted { integers, set } => {
638 if is_output(set) {
639 return Ok(integer_values(integers, values)
640 .map(|integers| Value::IntegerSet(IntegerSet::from_values(integers))));
641 }
642 let Some(set) = set.value(values) else {
643 return Ok(None);
644 };
645 let cardinality = checked_cardinality(set.set(), constraint)?;
646 if cardinality != integers.len() as i64 {
647 return Ok(None);
648 }
649 let members = set.set().members();
651 for (_, member) in integers
652 .iter()
653 .zip(members)
654 .filter(|(operand, _)| is_output(operand))
655 {
656 candidates.push(Value::Integer(member));
657 }
658 }
659 Self::Precede { .. } => return Ok(None),
660 }
661 Ok(agreed(candidates))
662 }
663 fn faults(&self, values: &[Option<Value>]) -> Result<Vec<SetChannelFault>, &'static str> {
664 use SetChannelFault::*;
665 use SetChannelSide as Side;
666 let mut faults = Vec::new();
667 match self {
668 Self::Selected {
669 operation,
670 indices,
671 sets,
672 result,
673 universe,
674 } => {
675 outside(
676 &mut faults,
677 Side::Selection,
678 None,
679 indices,
680 &IntegerSet::interval(1, sets.len() as i64),
681 values,
682 );
683 if let Some(indices) = indices.value(values)
684 && *operation == SetAggregate::Partition
685 {
686 for (i, a) in sets
687 .iter()
688 .enumerate()
689 .filter(|(i, _)| indices.set().contains(label(1, *i)))
690 {
691 if let Some(a) = a.value(values) {
692 for (j, b) in sets
693 .iter()
694 .enumerate()
695 .skip(i + 1)
696 .filter(|(j, _)| indices.set().contains(label(1, *j)))
697 {
698 if let Some(b) = b.value(values) {
699 let intersection = a.set().intersection(b.set());
700 if !intersection.is_empty() {
701 faults.push(Partition {
702 first: i + 1,
703 second: j + 1,
704 intersection,
705 });
706 }
707 }
708 }
709 }
710 }
711 }
712 if let Some(universe) = universe {
713 outside(&mut faults, Side::Result, None, result, universe, values);
714 }
715 mismatch(
716 &mut faults,
717 Side::Result,
718 None,
719 result,
720 selected_set(*operation, indices, sets, universe.as_ref(), values)
721 .map(Value::IntegerSet),
722 values,
723 );
724 }
725 Self::Link { set, flags, offset } => {
726 outside(
727 &mut faults,
728 Side::Set,
729 None,
730 set,
731 &visible(*offset, flags.len()),
732 values,
733 );
734 if let Some(set) = set.value(values) {
735 for (i, flag) in flags.iter().enumerate() {
736 mismatch(
737 &mut faults,
738 Side::Flags,
739 Some(i + 1),
740 flag,
741 Some(Value::Boolean(set.set().contains(label(*offset, i)))),
742 values,
743 );
744 }
745 }
746 mismatch(
747 &mut faults,
748 Side::Set,
749 None,
750 set,
751 link_set(flags, *offset, values).map(Value::IntegerSet),
752 values,
753 );
754 }
755 Self::Range {
756 integers,
757 offset,
758 selection,
759 result,
760 } => {
761 let n = integer_length(*offset, integers.len()).expect("validated interval");
762 outside(
763 &mut faults,
764 Side::Selection,
765 None,
766 selection,
767 &IntegerSet::interval(0, n - 1),
768 values,
769 );
770 mismatch(
771 &mut faults,
772 Side::Result,
773 None,
774 result,
775 range_set(integers, *offset, selection, values).map(Value::IntegerSet),
776 values,
777 );
778 }
779 Self::IntSet {
780 integers,
781 sets,
782 integer_offset: a,
783 set_offset: b,
784 } => {
785 let n = integer_length(*a, integers.len()).expect("validated interval");
786 let prefix = if integers.is_empty() {
787 IntegerSet::empty()
788 } else {
789 IntegerSet::interval(0, *a - 1)
790 };
791 if !integers.is_empty() && sets.is_empty() {
792 faults.push(Padding {
793 integer_indices: visible(*a, integers.len()).union(&prefix),
794 set_indices: IntegerSet::empty(),
795 });
796 }
797 if *b > 0 && integers.is_empty() && *a > 0 {
798 faults.push(Padding {
799 integer_indices: IntegerSet::interval(0, *a - 1),
800 set_indices: IntegerSet::interval(0, 0),
801 });
802 }
803 if *b == 0 && !sets.is_empty() && !prefix.is_empty() {
805 faults.push(Padding {
806 integer_indices: prefix.clone(),
807 set_indices: IntegerSet::interval(0, 0),
808 });
809 }
810 for (i, integer) in integers.iter().enumerate() {
811 if let Some(value) = integer.value(values)
812 && !visible(*b, sets.len()).contains(value.integer())
813 {
814 faults.push(Outside {
815 side: Side::Integers,
816 position: Some(i + 1),
817 members: IntegerSet::from_values([value.integer()]),
818 allowed: visible(*b, sets.len()),
819 });
820 }
821 }
822 for (j, set) in sets.iter().enumerate() {
823 outside(
824 &mut faults,
825 Side::Sets,
826 Some(j + 1),
827 set,
828 &IntegerSet::interval(*a, n - 1),
829 values,
830 );
831 if let Some(set) = set.value(values) {
832 let expected_prefix = if label(*b, j) == 0 {
833 prefix.clone()
834 } else {
835 IntegerSet::empty()
836 };
837 let actual_prefix =
838 set.set().intersection(&IntegerSet::interval(0, *a - 1));
839 if expected_prefix != actual_prefix {
840 faults.push(Padding {
841 integer_indices: expected_prefix
842 .symmetric_difference(&actual_prefix),
843 set_indices: IntegerSet::interval(label(*b, j), label(*b, j)),
844 });
845 }
846 }
847 }
848 if let Some(sets) = set_values(sets, values) {
849 for i in 0..integers.len() {
850 let index = label(*a, i);
851 let memberships = IntegerSet::from_values(
852 sets.iter()
853 .enumerate()
854 .filter(|(_, set)| set.contains(index))
855 .map(|(j, _)| label(*b, j)),
856 );
857 if memberships.cardinality() != Some(1) {
858 faults.push(MembershipCount {
859 position: i + 1,
860 index,
861 memberships,
862 });
863 }
864 }
865 }
866 membership_faults(&mut faults, integers, sets, *a, *b, values, false);
867 }
868 Self::Inverse {
869 forward,
870 inverse,
871 forward_offset: a,
872 inverse_offset: b,
873 } => {
874 for (i, set) in forward.iter().enumerate() {
875 outside(
876 &mut faults,
877 Side::Forward,
878 Some(i + 1),
879 set,
880 &visible(*b, inverse.len()),
881 values,
882 );
883 }
884 for (i, set) in inverse.iter().enumerate() {
885 outside(
886 &mut faults,
887 Side::Inverse,
888 Some(i + 1),
889 set,
890 &visible(*a, forward.len()),
891 values,
892 );
893 }
894 membership_faults(&mut faults, forward, inverse, *a, *b, values, true);
895 }
896 Self::Precede {
897 sets,
898 first,
899 second,
900 } => {
901 let mut earlier = false;
902 let mut unknown = false;
903 for (i, set) in sets.iter().enumerate() {
904 let Some(set) = set.value(values) else {
905 unknown = true;
906 continue;
907 };
908 let (s, t) = (set.set().contains(*first), set.set().contains(*second));
909 if t && !s && !earlier && !unknown {
910 faults.push(Precedence { position: i + 1 });
911 }
912 earlier |= s && !t;
913 }
914 }
915 Self::Sorted { integers, set } => {
916 for (i, pair) in integers.windows(2).enumerate() {
917 if let (Some(a), Some(b)) = (pair[0].value(values), pair[1].value(values))
918 && a.integer() >= b.integer()
919 {
920 faults.push(Order {
921 first: i + 1,
922 second: i + 2,
923 });
924 }
925 }
926 if let Some(set) = set.value(values) {
927 let actual = set
928 .set()
929 .cardinality()
930 .ok_or("checked i64 overflow in sorted channel cardinality")?;
931 let expected = integers.len() as i64;
932 if actual != expected {
933 faults.push(Cardinality { expected, actual });
934 }
935 for (i, integer) in integers.iter().enumerate() {
936 if let Some(integer) = integer.value(values)
937 && !set.set().contains(integer.integer())
938 {
939 faults.push(Outside {
940 side: Side::Integers,
941 position: Some(i + 1),
942 members: IntegerSet::from_values([integer.integer()]),
943 allowed: set.set().clone(),
944 });
945 }
946 }
947 }
948 mismatch(
949 &mut faults,
950 Side::Set,
951 None,
952 set,
953 integer_values(integers, values)
954 .map(|integers| Value::IntegerSet(IntegerSet::from_values(integers))),
955 values,
956 );
957 }
958 }
959 Ok(faults)
960 }
961}
962fn check_set_constant(value: i64) -> Result<(), &'static str> {
963 if (GECODE_SET_MIN..=GECODE_SET_MAX).contains(&value) {
964 Ok(())
965 } else {
966 Err("fixed parameter exceeds Gecode set limits")
967 }
968}
969fn checked_length(offset: i64, length: usize) -> Result<i64, &'static str> {
970 if offset < 0 {
971 return Err("set channel offsets must be nonnegative");
972 }
973 let length = i64::try_from(length).map_err(|_| "set channel array length exceeds i64")?;
974 offset
975 .checked_add(length)
976 .filter(|n| *n <= i64::from(i32::MAX))
977 .ok_or("fixed set channel interval exceeds native index bounds")
978}
979fn integer_length(offset: i64, length: usize) -> Result<i64, &'static str> {
980 let n = checked_length(offset, length)?;
981 Ok(if length == 0 { 0 } else { n })
982}
983fn label(offset: i64, position: usize) -> i64 {
984 offset + position as i64
985}
986fn visible(offset: i64, length: usize) -> IntegerSet {
987 IntegerSet::interval(offset, label(offset, length) - 1)
988}
989fn integer_values(entries: &[Operand], values: &[Option<Value>]) -> Option<Vec<i64>> {
990 entries
991 .iter()
992 .map(|entry| entry.value(values).map(Value::integer))
993 .collect()
994}
995fn set_values<'a>(
996 entries: &'a [Operand],
997 values: &'a [Option<Value>],
998) -> Option<Vec<&'a IntegerSet>> {
999 entries
1000 .iter()
1001 .map(|entry| entry.value(values).map(Value::set))
1002 .collect()
1003}
1004fn agreed(values: Vec<Value>) -> Option<Value> {
1005 let first = values.first()?;
1006 values
1007 .iter()
1008 .all(|value| value == first)
1009 .then(|| first.clone())
1010}
1011fn checked_cardinality(set: &IntegerSet, constraint: &Constraint) -> Result<i64, CheckError> {
1012 set.cardinality().ok_or_else(|| {
1013 constraint.execution_error("checked i64 overflow in sorted channel cardinality")
1014 })
1015}
1016fn selected_set(
1017 operation: SetAggregate,
1018 indices: &Operand,
1019 sets: &[Operand],
1020 universe: Option<&IntegerSet>,
1021 values: &[Option<Value>],
1022) -> Option<IntegerSet> {
1023 let indices = indices.value(values)?.set();
1024 if !indices.is_subset(&IntegerSet::interval(1, sets.len() as i64)) {
1025 return None;
1026 }
1027 let mut result = None;
1028 for (_, set) in sets
1029 .iter()
1030 .enumerate()
1031 .filter(|(i, _)| indices.contains(label(1, *i)))
1032 {
1033 let set = set.value(values)?.set();
1034 result = Some(match result {
1035 None => set.clone(),
1036 Some(result) => {
1037 if operation == SetAggregate::Intersection {
1038 set.intersection(&result)
1039 } else {
1040 set.union(&result)
1041 }
1042 }
1043 });
1044 }
1045 Some(result.unwrap_or_else(|| {
1046 if operation == SetAggregate::Intersection {
1047 universe
1048 .cloned()
1049 .unwrap_or_else(|| IntegerSet::interval(GECODE_SET_MIN, GECODE_SET_MAX))
1050 } else {
1051 IntegerSet::empty()
1052 }
1053 }))
1054}
1055fn range_set(
1056 integers: &[Operand],
1057 offset: i64,
1058 selection: &Operand,
1059 values: &[Option<Value>],
1060) -> Option<IntegerSet> {
1061 let selection = selection.value(values)?.set();
1062 let n = integer_length(offset, integers.len()).expect("validated interval");
1063 if !selection.is_subset(&IntegerSet::interval(0, n - 1)) {
1064 return None;
1065 }
1066 let mut result = Vec::new();
1067 if !selection
1068 .intersection(&IntegerSet::interval(0, offset - 1))
1069 .is_empty()
1070 {
1071 result.push(0);
1072 }
1073 for (_, integer) in integers
1074 .iter()
1075 .enumerate()
1076 .filter(|(i, _)| selection.contains(label(offset, *i)))
1077 {
1078 result.push(integer.value(values)?.integer());
1079 }
1080 Some(IntegerSet::from_values(result))
1081}
1082fn link_set(flags: &[Operand], offset: i64, values: &[Option<Value>]) -> Option<IntegerSet> {
1083 let flags: Vec<_> = flags
1084 .iter()
1085 .map(|flag| flag.value(values).map(Value::boolean))
1086 .collect::<Option<_>>()?;
1087 Some(IntegerSet::from_values(
1088 flags
1089 .iter()
1090 .enumerate()
1091 .filter(|(_, flag)| **flag)
1092 .map(|(i, _)| label(offset, i)),
1093 ))
1094}
1095fn outside(
1096 faults: &mut Vec<SetChannelFault>,
1097 side: SetChannelSide,
1098 position: Option<usize>,
1099 operand: &Operand,
1100 allowed: &IntegerSet,
1101 values: &[Option<Value>],
1102) {
1103 if let Some(set) = operand.value(values) {
1104 let members = set.set().difference(allowed);
1105 if !members.is_empty() {
1106 faults.push(SetChannelFault::Outside {
1107 side,
1108 position,
1109 members,
1110 allowed: allowed.clone(),
1111 });
1112 }
1113 }
1114}
1115fn mismatch(
1116 faults: &mut Vec<SetChannelFault>,
1117 side: SetChannelSide,
1118 position: Option<usize>,
1119 operand: &Operand,
1120 expected: Option<Value>,
1121 values: &[Option<Value>],
1122) {
1123 if let Some(expected) = expected
1124 && operand
1125 .value(values)
1126 .is_some_and(|actual| *actual != expected)
1127 {
1128 faults.push(SetChannelFault::Mismatch {
1129 side,
1130 position,
1131 expected,
1132 });
1133 }
1134}
1135fn membership_faults(
1136 faults: &mut Vec<SetChannelFault>,
1137 left: &[Operand],
1138 right: &[Operand],
1139 a: i64,
1140 b: i64,
1141 values: &[Option<Value>],
1142 left_is_set: bool,
1143) {
1144 for (i, left) in left.iter().enumerate() {
1145 if let Some(left) = left.value(values) {
1146 for (j, right) in right.iter().enumerate() {
1147 if let Some(right) = right.value(values) {
1148 let expected = if left_is_set {
1149 left.set().contains(label(b, j))
1150 } else {
1151 left.integer() == label(b, j)
1152 };
1153 if expected != right.set().contains(label(a, i)) {
1154 faults.push(SetChannelFault::Membership {
1155 position: i + 1,
1156 index: label(a, i),
1157 set_position: j + 1,
1158 set_index: label(b, j),
1159 expected,
1160 });
1161 }
1162 }
1163 }
1164 }
1165 }
1166}
1167
1168impl PreparedModel {
1169 pub(crate) fn evaluate_set_channel(
1170 &self,
1171 constraint: &Constraint,
1172 channel: &SetChannel,
1173 values: &[Option<Value>],
1174 ) -> Result<Option<ViolationKind>, CheckError> {
1175 let faults = channel
1176 .faults(values)
1177 .map_err(|message| constraint.execution_error(message))?;
1178 if faults.is_empty() {
1179 return Ok(None);
1180 }
1181 let argument = |operand: &Operand, role, position, index| SetChannelArgument {
1182 role,
1183 position,
1184 index,
1185 value: self.argument(operand, values),
1186 unresolved: match operand {
1187 Operand::Variable(slot) if values[*slot].is_none() => {
1188 Some(Box::new(self.slots[*slot].reference.clone()))
1189 }
1190 _ => None,
1191 },
1192 };
1193 let array = |entries: &[Operand], role, offset| {
1194 entries
1195 .iter()
1196 .enumerate()
1197 .map(|(i, operand)| argument(operand, role, Some(i + 1), Some(label(offset, i))))
1198 .collect::<Vec<_>>()
1199 };
1200 use SetChannelSide as Side;
1201 let finding = match channel {
1202 SetChannel::Link { set, flags, offset } => SetChannelFinding::Link {
1203 arguments: std::iter::once(argument(set, Side::Set, None, None))
1204 .chain(array(flags, Side::Flags, *offset))
1205 .collect(),
1206 offset: *offset,
1207 faults,
1208 },
1209 SetChannel::IntSet {
1210 integers,
1211 sets,
1212 integer_offset,
1213 set_offset,
1214 } => SetChannelFinding::IntSet {
1215 arguments: array(integers, Side::Integers, *integer_offset)
1216 .into_iter()
1217 .chain(array(sets, Side::Sets, *set_offset))
1218 .collect(),
1219 integer_offset: *integer_offset,
1220 set_offset: *set_offset,
1221 faults,
1222 },
1223 SetChannel::Inverse {
1224 forward,
1225 inverse,
1226 forward_offset,
1227 inverse_offset,
1228 } => SetChannelFinding::Inverse {
1229 arguments: array(forward, Side::Forward, *forward_offset)
1230 .into_iter()
1231 .chain(array(inverse, Side::Inverse, *inverse_offset))
1232 .collect(),
1233 forward_offset: *forward_offset,
1234 inverse_offset: *inverse_offset,
1235 faults,
1236 },
1237 SetChannel::Range {
1238 integers,
1239 offset,
1240 selection,
1241 result,
1242 } => SetChannelFinding::Range {
1243 arguments: array(integers, Side::Integers, *offset)
1244 .into_iter()
1245 .chain([
1246 argument(selection, Side::Selection, None, None),
1247 argument(result, Side::Result, None, None),
1248 ])
1249 .collect(),
1250 offset: *offset,
1251 faults,
1252 },
1253 SetChannel::Precede {
1254 sets,
1255 first,
1256 second,
1257 } => SetChannelFinding::Precede {
1258 arguments: array(sets, Side::Sets, 0),
1259 first: *first,
1260 second: *second,
1261 faults,
1262 },
1263 SetChannel::Sorted { integers, set } => SetChannelFinding::Sorted {
1264 arguments: array(integers, Side::Integers, 0)
1265 .into_iter()
1266 .chain([argument(set, Side::Set, None, None)])
1267 .collect(),
1268 faults,
1269 },
1270 SetChannel::Selected {
1271 operation,
1272 indices,
1273 sets,
1274 result,
1275 universe,
1276 } => SetChannelFinding::Selected {
1277 arguments: std::iter::once(argument(indices, Side::Selection, None, None))
1278 .chain(array(sets, Side::Sets, 1))
1279 .chain([argument(result, Side::Result, None, None)])
1280 .collect(),
1281 aggregate: *operation,
1282 universe: universe.clone(),
1283 faults,
1284 },
1285 };
1286 Ok(Some(ViolationKind::SetChannel { finding }))
1287 }
1288}