1use serde::{Deserialize, Serialize};
5use std::collections::{HashMap, HashSet, VecDeque};
6
7mod packing;
8#[cfg(feature = "prepare")]
9use packing::bin_packing_signature;
10use packing::{BinPacking, is_bin_packing_name};
11pub use packing::{BinPackingFault, BinPackingFinding, PackingItem, PackingLoad};
12mod rectangles;
13pub use rectangles::{RectangleArguments, RectangleDimension, RectangleFault, RectanglesFinding};
14use rectangles::{RectangleName, Rectangles};
15mod scheduling;
16#[cfg(feature = "prepare")]
17use scheduling::ScheduleTasks;
18use scheduling::{Scheduling, SchedulingName};
19pub use scheduling::{SchedulingFault, SchedulingFinding, SchedulingTask};
20mod number_theory;
21#[cfg(feature = "prepare")]
22use number_theory::Modulus;
23use number_theory::{NumberTheory, NumberTheoryName};
24pub use number_theory::{
25 NumberTheoryArgument, NumberTheoryFinding, NumberTheoryOperation, NumberTheoryRole,
26};
27mod distance;
28use distance::{Distance, DistanceName};
29pub use distance::{DistanceArgument, DistanceFault, DistanceFinding};
30mod circuits;
31use circuits::{Circuit, CircuitName};
32pub use circuits::{CircuitArgument, CircuitFault, CircuitFinding};
33mod ordering;
34pub use ordering::{
35 IndexFault, InverseFault, InverseSide, OrderingArgument, OrderingFinding, OrderingPair,
36};
37use ordering::{Ordering, OrderingName};
38mod automata;
39#[cfg(feature = "prepare")]
40use automata::AutomatonEncoding;
41use automata::{Automaton, AutomatonName};
42pub use automata::{AutomatonFinding, AutomatonRejection};
43mod tables;
44pub use tables::TableData;
45use tables::{Table, TableName};
46mod counting;
47pub use counting::{CountPosition, CountSelectorValue, WindowCount};
48use counting::{Counting, CountingName};
49mod boolean;
50pub use boolean::BooleanOperation;
51use boolean::{BooleanKind, BooleanName};
52mod arithmetic;
53pub use arithmetic::ArithmeticOperation;
54mod relations;
55pub use relations::IntegerRelation;
56use relations::{RelationMode, RelationName, checked_sum};
57mod floats;
58use floats::FloatName;
59pub use floats::{
60 FiniteFloat, FloatConversion, FloatExtremum, FloatMembership, FloatOperation, FloatSet,
61 FloatTolerance,
62};
63mod selection;
64pub use selection::ElementLayout;
65use selection::{SelectionForm, SelectionName, SelectionPosition};
66mod serialized;
67mod set_channels;
68use set_channels::{SetChannel, SetChannelName};
69pub use set_channels::{SetChannelArgument, SetChannelFault, SetChannelFinding, SetChannelSide};
70mod set_globals;
71pub use set_globals::{
72 SetAggregate, SetArgument, SetCardinalityFault, SetGlobalFinding, SetPair, SetWeight,
73};
74use set_globals::{SetGlobal, SetGlobalName};
75mod sets;
76pub use sets::{
77 GECODE_SET_CARDINALITY, GECODE_SET_MAX, GECODE_SET_MIN, IntegerSet, SetOperation, SetRelation,
78};
79use sets::{SetKind, SetName};
80
81#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
82mod wasm;
83
84#[cfg(feature = "prepare")]
85mod prepare;
86#[cfg(feature = "prepare")]
87pub use prepare::{parse_assignment, prepare, prepare_json};
88#[cfg(feature = "prepare")]
89pub mod cli;
90
91#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
93#[serde(tag = "kind", content = "value", rename_all = "snake_case")]
94pub enum Value {
95 Float(FiniteFloat),
96 FloatSet(FloatSet),
97 IntegerSet(IntegerSet),
98 Boolean(bool),
99 Integer(
100 #[serde(
101 serialize_with = "serialize_integer",
102 deserialize_with = "deserialize_integer"
103 )]
104 i64,
105 ),
106}
107
108impl Value {
109 fn float(&self) -> FiniteFloat {
110 let Self::Float(value) = self else {
111 unreachable!("admission validates float operands")
112 };
113 *value
114 }
115
116 fn integer(&self) -> i64 {
117 let Self::Integer(value) = self else {
118 unreachable!("preparation validates integer operands")
119 };
120 *value
121 }
122
123 fn boolean(&self) -> bool {
124 let Self::Boolean(value) = self else {
125 unreachable!("admission validates Boolean operands")
126 };
127 *value
128 }
129
130 fn membership_element(&self) -> i64 {
131 match self {
132 Self::Integer(value) => *value,
133 Self::Boolean(value) => i64::from(*value),
134 _ => unreachable!("admission validates membership elements"),
135 }
136 }
137
138 fn set(&self) -> &IntegerSet {
139 let Self::IntegerSet(value) = self else {
140 unreachable!("preparation validates set operands")
141 };
142 value
143 }
144}
145
146impl std::fmt::Display for Value {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 match self {
149 Self::Float(value) => value.fmt(f),
150 Self::FloatSet(value) => value.fmt(f),
151 Self::Boolean(value) => value.fmt(f),
152 Self::Integer(value) => value.fmt(f),
153 Self::IntegerSet(value) => value.fmt(f),
154 }
155 }
156}
157
158#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
159#[serde(rename_all = "snake_case")]
160enum ValueType {
161 Float,
162 FloatSet,
163 IntegerSet,
164 Boolean,
165 Integer,
166}
167
168impl Value {
169 fn value_type(&self) -> ValueType {
170 match self {
171 Self::Float(_) => ValueType::Float,
172 Self::FloatSet(_) => ValueType::FloatSet,
173 Self::Boolean(_) => ValueType::Boolean,
174 Self::Integer(_) => ValueType::Integer,
175 Self::IntegerSet(_) => ValueType::IntegerSet,
176 }
177 }
178}
179
180#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
181pub struct Location {
182 pub source: String,
183 pub start: usize,
184 pub end: usize,
185 pub line: usize,
186 pub column: usize,
187}
188
189#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
190pub struct Diagnostic {
191 pub location: Option<Location>,
192 pub message: String,
193}
194
195#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
196pub struct Application {
197 pub id: String,
198 #[serde(
199 serialize_with = "serialize_integers",
200 deserialize_with = "deserialize_integers"
201 )]
202 pub entities: Vec<i64>,
203}
204
205#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
206pub struct Metadata {
207 pub application: Option<Application>,
208 #[serde(default, skip_serializing_if = "Option::is_none")]
209 pub value_application: Option<Application>,
210 pub label: Option<String>,
211 pub paths: Vec<String>,
212 pub is_defined: bool,
213 pub defines: Option<DefinitionTarget>,
214 pub output: bool,
215}
216
217#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
219#[serde(untagged)]
220pub enum DefinitionTarget {
221 Name(String),
222 Elements(Vec<String>),
223}
224
225impl std::fmt::Display for DefinitionTarget {
226 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227 match self {
228 Self::Name(name) => f.write_str(name),
229 Self::Elements(names) => write!(f, "[{}]", names.join(", ")),
230 }
231 }
232}
233
234#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
235pub struct VariableAlias {
236 pub name: String,
237 pub position: Option<usize>,
238}
239
240#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
241pub struct VariableRef {
242 pub name: String,
243 pub position: Option<usize>,
245 pub location: Location,
246 pub metadata: Metadata,
247 pub aliases: Vec<VariableAlias>,
248}
249
250#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
251pub struct ConstraintRef {
252 pub ordinal: usize,
253 pub predicate: String,
254 pub location: Location,
255 pub metadata: Metadata,
256}
257
258#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
259#[serde(tag = "kind", rename_all = "snake_case")]
260pub enum Domain {
261 Float,
262 FloatSet,
263 FloatRanges {
264 values: FloatSet,
265 },
266 IntegerRanges {
267 values: IntegerSet,
268 },
269 BooleanValues {
270 values: Vec<bool>,
271 },
272 FloatInterval {
273 lower: FiniteFloat,
274 upper: FiniteFloat,
275 },
276 IntegerSet {
277 upper: Option<IntegerSet>,
278 },
279 Boolean,
280 Integer,
281 Interval {
282 #[serde(
283 serialize_with = "serialize_integer",
284 deserialize_with = "deserialize_integer"
285 )]
286 lower: i64,
287 #[serde(
288 serialize_with = "serialize_integer",
289 deserialize_with = "deserialize_integer"
290 )]
291 upper: i64,
292 },
293 Enumeration {
294 #[serde(
295 serialize_with = "serialize_integers",
296 deserialize_with = "deserialize_integers"
297 )]
298 values: Vec<i64>,
299 },
300 Fixed {
301 value: Value,
302 },
303}
304
305impl Domain {
306 #[cfg(feature = "prepare")]
307 fn contains(&self, value: &Value) -> bool {
308 self.contains_with(value, FloatTolerance::new(0.0, 0.0).expect("exact policy"))
309 }
310
311 fn contains_with(&self, value: &Value, tolerance: FloatTolerance) -> bool {
312 match (self, value) {
313 (Self::Boolean, Value::Boolean(_))
314 | (Self::Integer, Value::Integer(_))
315 | (Self::Float, Value::Float(_))
316 | (Self::FloatSet, Value::FloatSet(_)) => true,
317 (Self::FloatRanges { values }, Value::Float(value)) => values
318 .ranges()
319 .iter()
320 .any(|(lower, upper)| tolerance.contains(*value, *lower, *upper)),
321 (Self::IntegerRanges { values }, Value::Integer(value)) => values.contains(*value),
322 (Self::BooleanValues { values }, Value::Boolean(value)) => values.contains(value),
323 (Self::FloatInterval { lower, upper }, Value::Float(value)) => {
324 tolerance.contains(*value, *lower, *upper)
325 }
326 (
327 Self::Fixed {
328 value: Value::Float(fixed),
329 },
330 Value::Float(value),
331 ) => tolerance.equal(*fixed, *value),
332 (Self::Interval { lower, upper }, Value::Integer(value)) => {
333 (*lower..=*upper).contains(value)
334 }
335 (Self::Enumeration { values }, Value::Integer(value)) => values.contains(value),
336 (Self::Fixed { value: fixed }, value) => fixed == value,
337 (Self::IntegerSet { upper }, Value::IntegerSet(value)) => {
338 upper.as_ref().is_none_or(|upper| value.is_subset(upper))
339 }
340 _ => false,
341 }
342 }
343}
344
345#[derive(Clone, Debug, Serialize, Deserialize)]
346#[serde(tag = "kind", content = "value", rename_all = "snake_case")]
347pub enum AssignmentValue {
348 Scalar(Value),
349 Array(Vec<Value>),
350}
351
352#[derive(Clone, Debug, Serialize, Deserialize)]
353#[serde(deny_unknown_fields)]
354pub struct AssignmentEntry {
355 pub name: String,
356 pub value: AssignmentValue,
357 pub location: Option<Location>,
358}
359
360#[derive(Clone, Debug, Default, Serialize, Deserialize)]
362#[serde(deny_unknown_fields)]
363pub struct Assignment {
364 pub entries: Vec<AssignmentEntry>,
365}
366
367#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
368#[serde(rename_all = "snake_case")]
369pub enum Status {
370 Valid,
371 Invalid,
372 Incomplete,
373}
374
375#[derive(Clone, Debug, Serialize)]
376#[serde(tag = "kind", rename_all = "snake_case")]
377pub enum CheckRef {
378 Domain {
379 variable: VariableRef,
380 domain: Domain,
381 },
382 Constraint {
383 constraint: ConstraintRef,
384 },
385}
386
387impl CheckRef {
388 pub fn location(&self) -> &Location {
389 match self {
390 Self::Domain { variable, .. } => &variable.location,
391 Self::Constraint { constraint } => &constraint.location,
392 }
393 }
394}
395
396#[derive(Clone, Debug, Serialize)]
397pub struct ArgumentValue {
398 pub variable: Option<Box<VariableRef>>,
399 pub value: Value,
400}
401
402#[derive(Clone, Debug, Serialize)]
403#[serde(tag = "kind", rename_all = "snake_case")]
404pub enum ViolationKind {
405 BinPacking {
406 finding: BinPackingFinding,
407 },
408 Rectangles {
409 finding: RectanglesFinding,
410 },
411 Scheduling {
412 finding: SchedulingFinding,
413 },
414 Automaton {
415 finding: AutomatonFinding,
416 },
417 Table {
418 tuple: Vec<ArgumentValue>,
419 table: TableData,
420 width: usize,
421 membership: bool,
422 condition: RelationConditionValue,
423 },
424 NumberTheory {
425 finding: NumberTheoryFinding,
426 },
427 Distance {
428 finding: DistanceFinding,
429 },
430 Circuit {
431 finding: CircuitFinding,
432 },
433 Ordering {
434 finding: OrderingFinding,
435 },
436 SetGlobal {
437 finding: SetGlobalFinding,
438 },
439 SetChannel {
440 finding: SetChannelFinding,
441 },
442 Count {
443 entries: Vec<ArgumentValue>,
444 selector: CountSelectorValue,
445 #[serde(serialize_with = "serialize_integer")]
446 calculated: i64,
447 supplied: ArgumentValue,
448 relation: IntegerRelation,
449 #[serde(serialize_with = "serialize_optional_integer")]
450 code: Option<i64>,
451 condition: RelationConditionValue,
452 },
453 Cardinality {
454 entries: Vec<ArgumentValue>,
455 counts: Vec<CountPosition>,
456 outside_cover: Vec<usize>,
457 closed: bool,
458 },
459 CountWindows {
460 entries: Vec<ArgumentValue>,
461 membership: Value,
462 #[serde(serialize_with = "serialize_integer")]
463 length: i64,
464 #[serde(serialize_with = "serialize_integer")]
465 lower: i64,
466 #[serde(serialize_with = "serialize_integer")]
467 upper: i64,
468 windows: Vec<WindowCount>,
469 },
470 ElementRange {
471 indices: Vec<Option<ArgumentValue>>,
472 layout: ElementLayout,
473 length: usize,
474 result: Option<ArgumentValue>,
475 },
476 ElementMismatch {
477 indices: Vec<ArgumentValue>,
478 layout: ElementLayout,
479 selected: ArgumentValue,
480 result: ArgumentValue,
481 },
482 ConditionalMismatch {
483 condition: ArgumentValue,
484 selected: ArgumentValue,
485 result: ArgumentValue,
486 },
487 FloatRelation {
488 relation: IntegerRelation,
489 left: ArgumentValue,
490 right: ArgumentValue,
491 condition: RelationConditionValue,
492 #[serde(
493 serialize_with = "serialize_optional_integer",
494 deserialize_with = "deserialize_optional_integer"
495 )]
496 code: Option<i64>,
497 },
498 FloatLinear {
499 relation: IntegerRelation,
500 coefficients: Vec<FiniteFloat>,
501 terms: Vec<ArgumentValue>,
502 bound: FiniteFloat,
503 condition: RelationConditionValue,
504 sum: FiniteFloat,
505 },
506 FloatArithmetic {
507 operation: FloatOperation,
508 inputs: Vec<ArgumentValue>,
509 result: ArgumentValue,
510 },
511 FloatIntegerPower {
512 base: ArgumentValue,
513 #[serde(
514 serialize_with = "serialize_integer",
515 deserialize_with = "deserialize_integer"
516 )]
517 exponent: i64,
518 result: ArgumentValue,
519 },
520 FloatArrayExtremum {
521 extremum: FloatExtremum,
522 inputs: Vec<ArgumentValue>,
523 result: ArgumentValue,
524 },
525 FloatConversion {
526 operation: FloatConversion,
527 input: ArgumentValue,
528 result: ArgumentValue,
529 },
530 FloatMembership {
531 membership: FloatMembership,
532 element: ArgumentValue,
533 intervals: Vec<(FiniteFloat, FiniteFloat)>,
534 },
535
536 BooleanRelation {
537 relation: IntegerRelation,
538 left: ArgumentValue,
539 right: ArgumentValue,
540 condition: RelationConditionValue,
541 },
542 BooleanLinear {
543 relation: IntegerRelation,
544 #[serde(serialize_with = "serialize_integers")]
545 coefficients: Vec<i64>,
546 terms: Vec<ArgumentValue>,
547 #[serde(serialize_with = "serialize_integer")]
548 sum: i64,
549 bound: ArgumentValue,
550 condition: RelationConditionValue,
551 },
552 BooleanOperation {
553 operation: BooleanOperation,
554 inputs: Vec<ArgumentValue>,
555 condition: RelationConditionValue,
556 },
557 BooleanClause {
558 positive: Vec<ArgumentValue>,
559 negative: Vec<ArgumentValue>,
560 condition: RelationConditionValue,
561 },
562 BooleanToInteger {
563 boolean: ArgumentValue,
564 integer: ArgumentValue,
565 },
566 IntegerRelation {
567 relation: IntegerRelation,
568 left: ArgumentValue,
569 right: ArgumentValue,
570 condition: RelationConditionValue,
571 },
572 LinearRelation {
573 relation: IntegerRelation,
574 #[serde(serialize_with = "serialize_integers")]
575 coefficients: Vec<i64>,
576 terms: Vec<ArgumentValue>,
577 #[serde(serialize_with = "serialize_integer")]
578 sum: i64,
579 #[serde(serialize_with = "serialize_integer")]
580 bound: i64,
581 condition: RelationConditionValue,
582 },
583 IntegerArithmetic {
584 operation: ArithmeticOperation,
585 inputs: Vec<ArgumentValue>,
586 result: ArgumentValue,
587 },
588 SetRelation {
589 relation: SetRelation,
590 left: ArgumentValue,
591 right: ArgumentValue,
592 condition: RelationConditionValue,
593 #[serde(serialize_with = "serialize_optional_integer")]
594 native_code: Option<i64>,
595 },
596 SetMembership {
597 element: ArgumentValue,
598 set: ArgumentValue,
599 condition: RelationConditionValue,
600 },
601 SetOperation {
602 operation: SetOperation,
603 left: ArgumentValue,
604 right: ArgumentValue,
605 result: ArgumentValue,
606 },
607 SetIn {
608 element: ArgumentValue,
609 set: ArgumentValue,
610 },
611 SetEqual {
612 left: ArgumentValue,
613 right: ArgumentValue,
614 },
615 SetSubset {
616 left: ArgumentValue,
617 right: ArgumentValue,
618 },
619 SetCardinality {
620 set: ArgumentValue,
621 cardinality: ArgumentValue,
622 },
623 SetUnion {
624 left: ArgumentValue,
625 right: ArgumentValue,
626 result: ArgumentValue,
627 },
628 SetIntersection {
629 left: ArgumentValue,
630 right: ArgumentValue,
631 result: ArgumentValue,
632 },
633 DisjunctiveStrict {
634 tasks: Vec<TaskArguments>,
635 conflicts: Vec<ConflictingPair>,
636 },
637 Domain {
638 value: Value,
639 },
640 Linear {
641 #[serde(serialize_with = "serialize_integers")]
642 coefficients: Vec<i64>,
643 terms: Vec<ArgumentValue>,
644 #[serde(serialize_with = "serialize_integer")]
645 sum: i64,
646 #[serde(serialize_with = "serialize_integer")]
647 bound: i64,
648 },
649 ReifiedLessEqual {
650 left: ArgumentValue,
651 right: ArgumentValue,
652 result: ArgumentValue,
653 },
654}
655
656#[derive(Clone, Debug, Serialize)]
657#[serde(tag = "kind", rename_all = "snake_case")]
658pub enum RelationConditionValue {
659 Plain,
660 Reified { result: ArgumentValue },
661 Implied { guard: ArgumentValue },
662}
663
664#[derive(Clone, Debug, Serialize)]
665pub struct TaskArguments {
666 pub position: usize,
668 pub start: ArgumentValue,
669 pub duration: ArgumentValue,
670}
671
672#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
673pub struct ConflictingPair {
674 pub first: usize,
675 pub second: usize,
676}
677
678#[derive(Clone, Debug, Serialize)]
679pub struct Violation {
680 pub check: CheckRef,
681 pub details: ViolationKind,
682}
683
684#[derive(Clone, Debug, Serialize)]
685pub struct BlockedCheck {
686 pub check: CheckRef,
687 pub missing: Vec<VariableRef>,
688}
689
690#[derive(Clone, Debug, Serialize)]
691pub struct Completeness {
692 pub complete: bool,
693 pub unresolved_variables: Vec<VariableRef>,
694 pub blocked_checks: Vec<BlockedCheck>,
695}
696
697#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
698#[serde(rename_all = "snake_case")]
699pub enum ObjectiveDirection {
700 Minimize,
701 Maximize,
702}
703
704#[derive(Clone, Debug, Serialize)]
705pub struct ObjectiveValue {
706 pub direction: ObjectiveDirection,
707 pub argument: ArgumentValue,
708}
709
710#[derive(Clone, Debug, Serialize)]
711pub struct CheckReport {
712 pub status: Status,
713 pub violations: Vec<Violation>,
714 pub completeness: Completeness,
715 pub objective: Option<ObjectiveValue>,
716}
717
718#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
719#[serde(rename_all = "snake_case")]
720pub enum ErrorKind {
721 Assignment,
722 Execution,
723}
724
725#[derive(Debug, Serialize)]
726pub struct CheckError {
727 pub kind: ErrorKind,
728 pub diagnostics: Vec<Diagnostic>,
729}
730
731#[derive(Clone, Debug, Serialize, Deserialize)]
732enum Operand {
733 Literal(Value),
734 Variable(usize),
735}
736
737impl Operand {
738 fn value<'a>(&'a self, values: &'a [Option<Value>]) -> Option<&'a Value> {
739 match self {
740 Self::Literal(value) => Some(value),
741 Self::Variable(slot) => values[*slot].as_ref(),
742 }
743 }
744}
745
746#[derive(Debug, Serialize, Deserialize)]
747struct Slot {
748 kind: ValueType,
749 default: Option<Value>,
750 reference: VariableRef,
751}
752
753#[derive(Clone, Debug, Serialize, Deserialize)]
754struct Binding {
755 elements: Vec<Operand>,
756 is_array: bool,
757 kind: ValueType,
758 assignable: bool,
759}
760
761#[derive(Debug, Serialize, Deserialize)]
762struct Variable {
763 reference: VariableRef,
764 slot: usize,
765 domains: Vec<Domain>,
766}
767
768#[derive(Debug, Serialize, Deserialize)]
769enum Predicate {
770 BinPacking(BinPacking),
771 Rectangles(Rectangles),
772 Scheduling(Scheduling),
773 Automaton(Automaton),
774 NumberTheory(NumberTheory),
775 Distance(Distance),
776 Circuit(Circuit),
777 Ordering(Ordering),
778 SetGlobal(SetGlobal),
779 SetChannel(SetChannel),
780 Counting(Counting),
781 Table(Table),
782 Element {
783 indices: Vec<Operand>,
784 elements: Vec<Operand>,
785 result: Operand,
786 layout: ElementLayout,
787 },
788 Conditional {
789 condition: Operand,
790 then_value: Operand,
791 else_value: Operand,
792 result: Operand,
793 },
794 FloatRelation {
795 relation: IntegerRelation,
796 left: Operand,
797 right: Operand,
798 condition: RelationCondition,
799 #[serde(
800 serialize_with = "serialize_optional_integer",
801 deserialize_with = "deserialize_optional_integer"
802 )]
803 code: Option<i64>,
804 },
805 FloatLinear {
806 relation: IntegerRelation,
807 coefficients: Vec<FiniteFloat>,
808 terms: Vec<Operand>,
809 bound: FiniteFloat,
810 condition: RelationCondition,
811 },
812 FloatArithmetic {
813 operation: FloatOperation,
814 inputs: Vec<Operand>,
815 result: Operand,
816 },
817 FloatIntegerPower {
818 base: Operand,
819 #[serde(
820 serialize_with = "serialize_integer",
821 deserialize_with = "deserialize_integer"
822 )]
823 exponent: i64,
824 result: Operand,
825 },
826 FloatArrayExtremum {
827 extremum: FloatExtremum,
828 inputs: Vec<Operand>,
829 result: Operand,
830 },
831 FloatConversion {
832 operation: FloatConversion,
833 input: Operand,
834 result: Operand,
835 },
836 FloatMembership {
837 membership: FloatMembership,
838 element: Operand,
839 intervals: Vec<(FiniteFloat, FiniteFloat)>,
840 },
841
842 BooleanRelation {
843 relation: IntegerRelation,
844 left: Operand,
845 right: Operand,
846 condition: RelationCondition,
847 },
848 BooleanLinear {
849 relation: IntegerRelation,
850 #[serde(
851 serialize_with = "serialize_integers",
852 deserialize_with = "deserialize_integers"
853 )]
854 coefficients: Vec<i64>,
855 terms: Vec<Operand>,
856 bound: Operand,
857 condition: RelationCondition,
858 },
859 BooleanOperation {
860 operation: BooleanOperation,
861 inputs: Vec<Operand>,
862 condition: RelationCondition,
863 },
864 BooleanClause {
865 positive: Vec<Operand>,
866 negative: Vec<Operand>,
867 condition: RelationCondition,
868 },
869 BooleanToInteger {
870 boolean: Operand,
871 integer: Operand,
872 },
873 IntegerRelation {
874 relation: IntegerRelation,
875 left: Operand,
876 right: Operand,
877 condition: RelationCondition,
878 },
879 LinearRelation {
880 relation: IntegerRelation,
881 #[serde(
882 serialize_with = "serialize_integers",
883 deserialize_with = "deserialize_integers"
884 )]
885 coefficients: Vec<i64>,
886 terms: Vec<Operand>,
887 #[serde(
888 serialize_with = "serialize_integer",
889 deserialize_with = "deserialize_integer"
890 )]
891 bound: i64,
892 condition: RelationCondition,
893 },
894 IntegerArithmetic {
895 operation: ArithmeticOperation,
896 inputs: Vec<Operand>,
897 result: Operand,
898 },
899 SetRelation {
900 relation: SetRelation,
901 left: Operand,
902 right: Operand,
903 condition: RelationCondition,
904 #[serde(
905 serialize_with = "serialize_optional_integer",
906 deserialize_with = "deserialize_optional_integer"
907 )]
908 native_code: Option<i64>,
909 },
910 SetMembership {
911 element: Operand,
912 set: Operand,
913 condition: RelationCondition,
914 },
915 SetOperation {
916 operation: SetOperation,
917 left: Operand,
918 right: Operand,
919 result: Operand,
920 },
921 SetIn {
922 element: Operand,
923 set: Operand,
924 },
925 SetEqual {
926 left: Operand,
927 right: Operand,
928 },
929 SetSubset {
930 left: Operand,
931 right: Operand,
932 },
933 SetCardinality {
934 set: Operand,
935 cardinality: Operand,
936 },
937 SetUnion {
938 left: Operand,
939 right: Operand,
940 result: Operand,
941 },
942 SetIntersection {
943 left: Operand,
944 right: Operand,
945 result: Operand,
946 },
947 DisjunctiveStrict {
948 starts: Vec<Operand>,
949 durations: Vec<Operand>,
950 },
951 Linear {
952 #[serde(
953 serialize_with = "serialize_integers",
954 deserialize_with = "deserialize_integers"
955 )]
956 coefficients: Vec<i64>,
957 terms: Vec<Operand>,
958 #[serde(
959 serialize_with = "serialize_integer",
960 deserialize_with = "deserialize_integer"
961 )]
962 bound: i64,
963 equality: bool,
964 },
965 ReifiedLessEqual {
966 left: Operand,
967 right: Operand,
968 result: Operand,
969 },
970}
971
972#[derive(Debug, Serialize, Deserialize)]
973enum RelationCondition {
974 Plain,
975 Reified { result: Operand },
976 Implied { guard: Operand },
977}
978
979impl RelationCondition {
980 fn mode(&self) -> RelationMode {
981 match self {
982 Self::Plain => RelationMode::Plain,
983 Self::Reified { .. } => RelationMode::Reified,
984 Self::Implied { .. } => RelationMode::Implied,
985 }
986 }
987
988 fn operand(&self) -> Option<&Operand> {
989 match self {
990 Self::Plain => None,
991 Self::Reified { result } => Some(result),
992 Self::Implied { guard } => Some(guard),
993 }
994 }
995
996 fn inactive(&self, values: &[Option<Value>]) -> bool {
997 matches!(self, Self::Implied { guard } if guard.value(values) == Some(&Value::Boolean(false)))
998 }
999
1000 fn satisfied(&self, relation: bool, values: &[Option<Value>]) -> bool {
1001 match self {
1002 Self::Plain => relation,
1003 Self::Reified { result } => result.value(values) == Some(&Value::Boolean(relation)),
1004 Self::Implied { .. } => self.inactive(values) || relation,
1005 }
1006 }
1007}
1008
1009impl Predicate {
1010 fn operands(&self) -> Vec<&Operand> {
1011 match self {
1012 Self::Automaton(automaton) => automaton.word.iter().collect(),
1013 Self::BinPacking(packing) => packing.operands(),
1014 Self::Rectangles(rectangles) => rectangles.operands(),
1015 Self::Scheduling(schedule) => schedule.operands(),
1016 Self::NumberTheory(arithmetic) => arithmetic.operands(),
1017 Self::Distance(distance) => distance.operands(),
1018 Self::Circuit(circuit) => circuit.operands(),
1019 Self::Ordering(ordering) => ordering.operands(),
1020 Self::SetGlobal(global) => global.operands(),
1021 Self::SetChannel(channel) => channel.operands(),
1022 Self::Counting(counting) => counting.operands(false),
1023 Self::Table(table) => table.operands(),
1024 Self::Element {
1025 indices,
1026 elements,
1027 result,
1028 ..
1029 } => indices
1030 .iter()
1031 .chain(elements)
1032 .chain(std::iter::once(result))
1033 .collect(),
1034 Self::Conditional {
1035 condition,
1036 then_value,
1037 else_value,
1038 result,
1039 } => vec![condition, then_value, else_value, result],
1040 Self::SetRelation {
1041 left,
1042 right,
1043 condition,
1044 ..
1045 }
1046 | Self::FloatRelation {
1047 left,
1048 right,
1049 condition,
1050 ..
1051 }
1052 | Self::BooleanRelation {
1053 left,
1054 right,
1055 condition,
1056 ..
1057 }
1058 | Self::IntegerRelation {
1059 left,
1060 right,
1061 condition,
1062 ..
1063 } => [left, right]
1064 .into_iter()
1065 .chain(condition.operand())
1066 .collect(),
1067 Self::BooleanLinear {
1068 terms,
1069 bound,
1070 condition,
1071 ..
1072 } => terms
1073 .iter()
1074 .chain(std::iter::once(bound))
1075 .chain(condition.operand())
1076 .collect(),
1077 Self::BooleanOperation {
1078 inputs, condition, ..
1079 } => inputs.iter().chain(condition.operand()).collect(),
1080 Self::BooleanClause {
1081 positive,
1082 negative,
1083 condition,
1084 } => positive
1085 .iter()
1086 .chain(negative)
1087 .chain(condition.operand())
1088 .collect(),
1089 Self::BooleanToInteger { boolean, integer } => vec![boolean, integer],
1090 Self::FloatLinear {
1091 terms, condition, ..
1092 }
1093 | Self::LinearRelation {
1094 terms, condition, ..
1095 } => terms.iter().chain(condition.operand()).collect(),
1096 Self::FloatArithmetic { inputs, result, .. }
1097 | Self::FloatArrayExtremum { inputs, result, .. }
1098 | Self::IntegerArithmetic { inputs, result, .. } => {
1099 inputs.iter().chain(std::iter::once(result)).collect()
1100 }
1101 Self::FloatIntegerPower { base, result, .. } => vec![base, result],
1102 Self::FloatConversion { input, result, .. } => vec![input, result],
1103 Self::FloatMembership { element, .. } => vec![element],
1104 Self::Linear { terms, .. } => terms.iter().collect(),
1105 Self::SetOperation {
1106 left,
1107 right,
1108 result,
1109 ..
1110 }
1111 | Self::ReifiedLessEqual {
1112 left,
1113 right,
1114 result,
1115 }
1116 | Self::SetUnion {
1117 left,
1118 right,
1119 result,
1120 }
1121 | Self::SetIntersection {
1122 left,
1123 right,
1124 result,
1125 } => vec![left, right, result],
1126 Self::SetMembership {
1127 element,
1128 set,
1129 condition,
1130 } => [element, set]
1131 .into_iter()
1132 .chain(condition.operand())
1133 .collect(),
1134 Self::SetIn { element, set } => vec![element, set],
1135 Self::SetEqual { left, right } | Self::SetSubset { left, right } => vec![left, right],
1136 Self::SetCardinality { set, cardinality } => vec![set, cardinality],
1137 Self::DisjunctiveStrict { starts, durations } => {
1138 starts.iter().chain(durations).collect()
1139 }
1140 }
1141 }
1142
1143 fn set_truth(&self, values: &[Option<Value>]) -> Option<bool> {
1144 match self {
1145 Self::SetRelation {
1146 relation,
1147 left,
1148 right,
1149 ..
1150 } => Some(relation.holds(left.value(values)?.set(), right.value(values)?.set())),
1151 Self::SetMembership { element, set, .. } => Some(
1152 set.value(values)?
1153 .set()
1154 .contains(element.value(values)?.membership_element()),
1155 ),
1156 _ => unreachable!("only conditioned set predicates calculate truth"),
1157 }
1158 }
1159
1160 fn required_operands(&self, values: &[Option<Value>]) -> Vec<&Operand> {
1161 match self {
1162 Self::BinPacking(packing) => packing.required_operands(values),
1163 Self::Rectangles(rectangles) => rectangles.required_operands(values),
1164 Self::Scheduling(schedule) => schedule.required_operands(values),
1165 Self::NumberTheory(arithmetic) => arithmetic.required_operands(values),
1166 Self::Distance(distance) => distance.required_operands(values),
1167 Self::Circuit(circuit) => circuit.required_operands(values),
1168 Self::Ordering(ordering) => ordering.required_operands(values),
1169 Self::SetGlobal(global) => global.required_operands(values),
1170 Self::SetChannel(channel) => channel.required_operands(values),
1171 Self::Counting(counting) => counting.operands(true),
1172 Self::Element {
1173 indices,
1174 elements,
1175 result,
1176 layout,
1177 } => match layout.position(indices, elements.len(), values) {
1178 SelectionPosition::Missing => indices.iter().collect(),
1179 SelectionPosition::OutOfRange => Vec::new(),
1180 SelectionPosition::Selected(position) => vec![&elements[position], result],
1181 },
1182 Self::Conditional {
1183 condition, result, ..
1184 } => match self.selected_operand(values) {
1185 Some(selected) => vec![selected, result],
1186 None => vec![condition],
1187 },
1188 _ => self.operands(),
1189 }
1190 }
1191
1192 fn inactive_implication(&self, values: &[Option<Value>]) -> bool {
1193 match self {
1194 Self::NumberTheory(arithmetic) => arithmetic.condition().inactive(values),
1195 Self::SetGlobal(global) => global.inactive(values),
1196 Self::Table(table) => table.condition.inactive(values),
1197 Self::Counting(Counting::Count { condition, .. }) => condition.inactive(values),
1198 Self::SetRelation { condition, .. }
1199 | Self::SetMembership { condition, .. }
1200 | Self::FloatRelation { condition, .. }
1201 | Self::FloatLinear { condition, .. }
1202 | Self::BooleanRelation { condition, .. }
1203 | Self::BooleanLinear { condition, .. }
1204 | Self::BooleanOperation { condition, .. }
1205 | Self::BooleanClause { condition, .. }
1206 | Self::IntegerRelation { condition, .. }
1207 | Self::LinearRelation { condition, .. } => condition.inactive(values),
1208 _ => false,
1209 }
1210 }
1211}
1212
1213#[derive(Debug, Serialize, Deserialize)]
1214struct Constraint {
1215 reference: ConstraintRef,
1216 predicate: Predicate,
1217}
1218
1219impl Constraint {
1220 fn execution_error(&self, message: &str) -> CheckError {
1221 CheckError {
1222 kind: ErrorKind::Execution,
1223 diagnostics: vec![Diagnostic {
1224 location: Some(self.reference.location.clone()),
1225 message: message.into(),
1226 }],
1227 }
1228 }
1229 fn linear_overflow(&self) -> CheckError {
1230 CheckError {
1231 kind: ErrorKind::Execution,
1232 diagnostics: vec![Diagnostic {
1233 location: Some(self.reference.location.clone()),
1234 message: "checked i64 overflow in linear constraint".into(),
1235 }],
1236 }
1237 }
1238}
1239
1240#[derive(Clone, Copy, Debug)]
1241enum DefinitionDirection {
1242 SetChannel,
1243 SetGlobal,
1244 BinPacking,
1245 Table,
1246 NumberTheory,
1247 Distance,
1248 Circuit,
1249 Ordering,
1250 Counting,
1251 Selection,
1252 FloatEqual { input: usize },
1253 FloatReified,
1254 FloatLinear { term: usize },
1255 FloatArithmetic,
1256 FloatIntegerPower,
1257 FloatArrayExtremum,
1258 FloatConversion,
1259 BooleanCopy { input: usize, complement: bool },
1260 BooleanResult,
1261 BooleanLinearBound,
1262 BooleanLinearTerm { term: usize },
1263 BooleanToInteger,
1264 IntegerToBoolean,
1265 IntegerEqual { input: usize },
1266 ReifiedRelation,
1267 IntegerArithmetic,
1268 Linear { term: usize },
1269 ReifiedLessEqual,
1270 SetEqual { input: usize },
1271 SetCardinality,
1272 SetUnion,
1273 SetIntersection,
1274 SetOperation,
1275 SetReified,
1276}
1277
1278#[derive(Debug)]
1279struct Definition {
1280 constraint: usize,
1281 output: usize,
1282 direction: DefinitionDirection,
1283}
1284
1285#[derive(Debug, Serialize)]
1288pub struct PreparedModel {
1289 float_tolerance: FloatTolerance,
1290 slots: Vec<Slot>,
1291 bindings: HashMap<String, Binding>,
1292 variables: Vec<Variable>,
1293 constraints: Vec<Constraint>,
1294 #[serde(skip)]
1295 definitions: Vec<Definition>,
1296 #[serde(skip)]
1297 dependents: Vec<Vec<usize>>,
1298 objective: Option<(ObjectiveDirection, Operand)>,
1299}
1300
1301impl PreparedModel {
1302 pub fn float_tolerance(&self) -> FloatTolerance {
1303 self.float_tolerance
1304 }
1305
1306 pub fn set_float_tolerance(&mut self, tolerance: FloatTolerance) {
1307 self.float_tolerance = tolerance;
1308 }
1309
1310 pub fn check(&self, assignment: &Assignment) -> Result<CheckReport, CheckError> {
1313 let mut values = self.assign(assignment)?;
1314 self.complete(&mut values)?;
1315 let unresolved_variables: Vec<_> = self
1316 .variables
1317 .iter()
1318 .filter(|variable| values[variable.slot].is_none())
1319 .map(|variable| variable.reference.clone())
1320 .collect();
1321 let mut violations = Vec::new();
1322 let mut blocked_checks = Vec::new();
1323 for variable in &self.variables {
1324 for domain in &variable.domains {
1325 let check = CheckRef::Domain {
1326 variable: variable.reference.clone(),
1327 domain: domain.clone(),
1328 };
1329 match &values[variable.slot] {
1330 Some(value) if !domain.contains_with(value, self.float_tolerance) => violations
1331 .push(Violation {
1332 check,
1333 details: ViolationKind::Domain {
1334 value: value.clone(),
1335 },
1336 }),
1337 None => blocked_checks.push(BlockedCheck {
1338 check,
1339 missing: vec![variable.reference.clone()],
1340 }),
1341 _ => {}
1342 }
1343 }
1344 }
1345 for constraint in &self.constraints {
1346 if constraint.predicate.inactive_implication(&values) {
1347 continue;
1348 }
1349 let check = CheckRef::Constraint {
1350 constraint: constraint.reference.clone(),
1351 };
1352 let missing = self.missing(&constraint.predicate, &values);
1353 if !missing.is_empty() {
1354 blocked_checks.push(BlockedCheck { check, missing });
1355 continue;
1356 }
1357 if let Some(details) = self.evaluate(constraint, &values)? {
1358 violations.push(Violation { check, details });
1359 }
1360 }
1361 violations.sort_by_key(|violation| violation.check.location().start);
1362 blocked_checks.sort_by_key(|blocked| blocked.check.location().start);
1363 let complete = unresolved_variables.is_empty() && blocked_checks.is_empty();
1364 let status = if !violations.is_empty() {
1365 Status::Invalid
1366 } else if !complete {
1367 Status::Incomplete
1368 } else {
1369 Status::Valid
1370 };
1371 let objective = self.objective.as_ref().and_then(|(direction, operand)| {
1372 self.argument(operand, &values)
1373 .map(|argument| ObjectiveValue {
1374 direction: *direction,
1375 argument,
1376 })
1377 });
1378 Ok(CheckReport {
1379 status,
1380 violations,
1381 completeness: Completeness {
1382 complete,
1383 unresolved_variables,
1384 blocked_checks,
1385 },
1386 objective,
1387 })
1388 }
1389
1390 fn assign(&self, assignment: &Assignment) -> Result<Vec<Option<Value>>, CheckError> {
1391 let mut values = vec![None; self.slots.len()];
1392 let mut names = HashSet::new();
1393 for entry in &assignment.entries {
1394 let fail = |message| CheckError {
1395 kind: ErrorKind::Assignment,
1396 diagnostics: vec![Diagnostic {
1397 location: entry.location.clone(),
1398 message,
1399 }],
1400 };
1401 if !names.insert(&entry.name) {
1402 return Err(fail(format!("duplicate assignment to '{}'", entry.name)));
1403 }
1404 let binding = self
1405 .bindings
1406 .get(&entry.name)
1407 .ok_or_else(|| fail(format!("unknown variable '{}'", entry.name)))?;
1408 if !binding.assignable {
1409 return Err(fail(format!(
1410 "'{}' is a parameter, not a candidate variable",
1411 entry.name
1412 )));
1413 }
1414 let supplied = match (&entry.value, binding.is_array) {
1415 (AssignmentValue::Scalar(value), false) => std::slice::from_ref(value),
1416 (AssignmentValue::Array(values), true) => values.as_slice(),
1417 _ => {
1418 return Err(fail(format!(
1419 "assignment shape does not match '{}'",
1420 entry.name
1421 )));
1422 }
1423 };
1424 if supplied.len() != binding.elements.len() {
1425 return Err(fail(format!(
1426 "'{}' expects {} values, got {}",
1427 entry.name,
1428 binding.elements.len(),
1429 supplied.len()
1430 )));
1431 }
1432 for (operand, value) in binding.elements.iter().zip(supplied) {
1433 if value.value_type() != binding.kind {
1434 return Err(fail(format!(
1435 "assignment type does not match '{}'",
1436 entry.name
1437 )));
1438 }
1439 match operand {
1440 Operand::Variable(slot) => {
1441 if values[*slot]
1442 .as_ref()
1443 .is_some_and(|previous| previous != value)
1444 {
1445 return Err(fail(format!(
1446 "contradictory assignments through alias '{}'",
1447 entry.name
1448 )));
1449 }
1450 values[*slot] = Some(value.clone());
1451 }
1452 Operand::Literal(_) => unreachable!("variable bindings contain value slots"),
1453 }
1454 }
1455 }
1456 for (value, slot) in values.iter_mut().zip(&self.slots) {
1457 if value.is_none() {
1458 *value = slot.default.clone();
1459 }
1460 }
1461 Ok(values)
1462 }
1463
1464 fn complete(&self, values: &mut [Option<Value>]) -> Result<(), CheckError> {
1465 let mut pending: VecDeque<_> = (0..self.definitions.len()).collect();
1466 while let Some(index) = pending.pop_front() {
1467 let definition = &self.definitions[index];
1468 if values[definition.output].is_some() {
1469 continue;
1470 }
1471 if let Some(value) = self.derive(definition, values)? {
1472 values[definition.output] = Some(value);
1473 pending.extend(self.dependents[definition.output].iter().copied());
1474 }
1475 }
1476 Ok(())
1477 }
1478
1479 fn derive(
1480 &self,
1481 definition: &Definition,
1482 values: &[Option<Value>],
1483 ) -> Result<Option<Value>, CheckError> {
1484 let constraint = &self.constraints[definition.constraint];
1485 match (&constraint.predicate, definition.direction) {
1486 (Predicate::BinPacking(packing), DefinitionDirection::BinPacking) => {
1487 packing.derive(definition.output, values, constraint)
1488 }
1489 (Predicate::Table(table), DefinitionDirection::Table) => {
1490 Ok(table.membership(values).map(Value::Boolean))
1491 }
1492 (Predicate::NumberTheory(arithmetic), DefinitionDirection::NumberTheory) => {
1493 arithmetic.derive(values, constraint)
1494 }
1495 (Predicate::Distance(distance), DefinitionDirection::Distance) => {
1496 Ok(distance.derive(values))
1497 }
1498 (Predicate::Circuit(circuit), DefinitionDirection::Circuit) => {
1499 circuit.derive(definition.output, values, constraint)
1500 }
1501 (Predicate::SetChannel(channel), DefinitionDirection::SetChannel) => {
1502 channel.derive(definition.output, values, constraint)
1503 }
1504 (Predicate::SetGlobal(global), DefinitionDirection::SetGlobal) => {
1505 global.derive(values, constraint)
1506 }
1507 (Predicate::Ordering(ordering), DefinitionDirection::Ordering) => {
1508 ordering.derive(definition.output, values, constraint)
1509 }
1510 (Predicate::Counting(counting), DefinitionDirection::Counting) => {
1511 counting.derive(definition.output, values, constraint)
1512 }
1513 (predicate, DefinitionDirection::Selection) => Ok(predicate
1514 .selected_operand(values)
1515 .and_then(|operand| operand.value(values))
1516 .cloned()),
1517 (
1518 Predicate::FloatRelation { left, right, .. },
1519 DefinitionDirection::FloatEqual { input },
1520 ) => Ok([left, right][input].value(values).cloned()),
1521 (
1522 Predicate::FloatRelation {
1523 relation,
1524 left,
1525 right,
1526 ..
1527 },
1528 DefinitionDirection::FloatReified,
1529 ) => {
1530 let (Some(left), Some(right)) = (left.value(values), right.value(values)) else {
1531 return Ok(None);
1532 };
1533 Ok(Some(Value::Boolean(self.float_tolerance.holds(
1534 *relation,
1535 left.float(),
1536 right.float(),
1537 ))))
1538 }
1539 (
1540 Predicate::FloatLinear {
1541 relation,
1542 coefficients,
1543 terms,
1544 bound,
1545 ..
1546 },
1547 DefinitionDirection::FloatReified,
1548 ) => Ok(self
1549 .float_sum(constraint, coefficients, terms, None, values)?
1550 .map(|sum| Value::Boolean(self.float_tolerance.holds(*relation, sum, *bound)))),
1551 (
1552 Predicate::FloatLinear {
1553 coefficients,
1554 terms,
1555 bound,
1556 ..
1557 },
1558 DefinitionDirection::FloatLinear { term },
1559 ) => {
1560 let Some(sum) =
1561 self.float_sum(constraint, coefficients, terms, Some(term), values)?
1562 else {
1563 return Ok(None);
1564 };
1565 let numerator = floats::finite_result(bound.get() - sum.get())
1566 .map_err(|message| constraint.execution_error(message))?;
1567 let value = floats::finite_result(numerator.get() / coefficients[term].get())
1568 .map_err(|message| constraint.execution_error(message))?;
1569 Ok(Some(Value::Float(value)))
1570 }
1571 (
1572 Predicate::FloatArithmetic {
1573 operation, inputs, ..
1574 },
1575 DefinitionDirection::FloatArithmetic,
1576 ) => {
1577 let Some(inputs) = inputs
1578 .iter()
1579 .map(|input| input.value(values).map(Value::float))
1580 .collect::<Option<Vec<_>>>()
1581 else {
1582 return Ok(None);
1583 };
1584 Ok(Some(Value::Float(
1585 operation
1586 .calculate(&inputs)
1587 .map_err(|message| constraint.execution_error(message))?,
1588 )))
1589 }
1590 (
1591 Predicate::FloatIntegerPower { base, exponent, .. },
1592 DefinitionDirection::FloatIntegerPower,
1593 ) => base
1594 .value(values)
1595 .map(|base| {
1596 floats::integer_power(base.float(), *exponent)
1597 .map(Value::Float)
1598 .map_err(|message| constraint.execution_error(message))
1599 })
1600 .transpose(),
1601 (
1602 Predicate::FloatArrayExtremum {
1603 extremum, inputs, ..
1604 },
1605 DefinitionDirection::FloatArrayExtremum,
1606 ) => Ok(inputs
1607 .iter()
1608 .map(|input| input.value(values).map(Value::float))
1609 .collect::<Option<Vec<_>>>()
1610 .map(|inputs| Value::Float(extremum.calculate(&inputs)))),
1611 (
1612 Predicate::FloatConversion {
1613 operation, input, ..
1614 },
1615 DefinitionDirection::FloatConversion,
1616 ) => input
1617 .value(values)
1618 .map(|input| {
1619 operation
1620 .calculate(input)
1621 .map_err(|message| constraint.execution_error(message))
1622 })
1623 .transpose(),
1624
1625 (
1626 Predicate::BooleanRelation { left, right, .. },
1627 DefinitionDirection::BooleanCopy { input, complement },
1628 ) => Ok([left, right][input]
1629 .value(values)
1630 .map(|value| Value::Boolean(value.boolean() ^ complement))),
1631 (
1632 Predicate::BooleanOperation {
1633 inputs, condition, ..
1634 },
1635 DefinitionDirection::BooleanCopy { input, complement },
1636 ) => {
1637 let operands: Vec<_> = inputs.iter().chain(condition.operand()).collect();
1638 Ok(operands[input]
1639 .value(values)
1640 .map(|value| Value::Boolean(value.boolean() ^ complement)))
1641 }
1642 (
1643 Predicate::BooleanRelation {
1644 relation,
1645 left,
1646 right,
1647 ..
1648 },
1649 DefinitionDirection::ReifiedRelation,
1650 ) => {
1651 let (Some(left), Some(right)) = (left.value(values), right.value(values)) else {
1652 return Ok(None);
1653 };
1654 Ok(Some(Value::Boolean(relation.holds(
1655 i64::from(left.boolean()),
1656 i64::from(right.boolean()),
1657 ))))
1658 }
1659 (
1660 Predicate::BooleanLinear {
1661 relation,
1662 coefficients,
1663 terms,
1664 bound,
1665 ..
1666 },
1667 DefinitionDirection::ReifiedRelation,
1668 ) => {
1669 let Some(bound) = bound.value(values) else {
1670 return Ok(None);
1671 };
1672 Ok(self
1673 .linear_sum(constraint, coefficients, terms, None, values)?
1674 .map(|sum| Value::Boolean(relation.holds(sum, bound.integer()))))
1675 }
1676 (
1677 Predicate::BooleanOperation {
1678 operation, inputs, ..
1679 },
1680 DefinitionDirection::BooleanResult,
1681 ) => Ok(boolean_values(inputs, values)
1682 .map(|inputs| Value::Boolean(operation.calculate(&inputs)))),
1683 (
1684 Predicate::BooleanClause {
1685 positive, negative, ..
1686 },
1687 DefinitionDirection::BooleanResult,
1688 ) => {
1689 let (Some(positive), Some(negative)) = (
1690 boolean_values(positive, values),
1691 boolean_values(negative, values),
1692 ) else {
1693 return Ok(None);
1694 };
1695 Ok(Some(Value::Boolean(boolean::clause(&positive, &negative))))
1696 }
1697 (
1698 Predicate::BooleanLinear {
1699 coefficients,
1700 terms,
1701 ..
1702 },
1703 DefinitionDirection::BooleanLinearBound,
1704 ) => Ok(self
1705 .linear_sum(constraint, coefficients, terms, None, values)?
1706 .map(Value::Integer)),
1707 (
1708 Predicate::BooleanLinear {
1709 coefficients,
1710 terms,
1711 bound,
1712 ..
1713 },
1714 DefinitionDirection::BooleanLinearTerm { term },
1715 ) => {
1716 let Some(bound) = bound.value(values) else {
1717 return Ok(None);
1718 };
1719 let Some(sum) =
1720 self.linear_sum(constraint, coefficients, terms, Some(term), values)?
1721 else {
1722 return Ok(None);
1723 };
1724 let numerator = bound
1725 .integer()
1726 .checked_sub(sum)
1727 .ok_or_else(|| constraint.linear_overflow())?;
1728 let coefficient = coefficients[term];
1729 let remainder = numerator
1730 .checked_rem(coefficient)
1731 .ok_or_else(|| constraint.linear_overflow())?;
1732 if remainder != 0 {
1733 return Ok(None);
1734 }
1735 let value = numerator
1736 .checked_div(coefficient)
1737 .ok_or_else(|| constraint.linear_overflow())?;
1738 Ok(boolean::from_integer(value).map(Value::Boolean))
1739 }
1740 (
1741 Predicate::BooleanToInteger { boolean, .. },
1742 DefinitionDirection::BooleanToInteger,
1743 ) => Ok(boolean
1744 .value(values)
1745 .map(|value| Value::Integer(i64::from(value.boolean())))),
1746 (
1747 Predicate::BooleanToInteger { integer, .. },
1748 DefinitionDirection::IntegerToBoolean,
1749 ) => Ok(integer
1750 .value(values)
1751 .and_then(|value| boolean::from_integer(value.integer()))
1752 .map(Value::Boolean)),
1753
1754 (
1755 Predicate::IntegerRelation { left, right, .. },
1756 DefinitionDirection::IntegerEqual { input },
1757 ) => Ok([left, right][input].value(values).cloned()),
1758 (
1759 Predicate::IntegerRelation {
1760 relation,
1761 left,
1762 right,
1763 ..
1764 },
1765 DefinitionDirection::ReifiedRelation,
1766 ) => {
1767 let (Some(left), Some(right)) = (left.value(values), right.value(values)) else {
1768 return Ok(None);
1769 };
1770 Ok(Some(Value::Boolean(
1771 relation.holds(left.integer(), right.integer()),
1772 )))
1773 }
1774 (
1775 Predicate::LinearRelation {
1776 relation,
1777 coefficients,
1778 terms,
1779 bound,
1780 ..
1781 },
1782 DefinitionDirection::ReifiedRelation,
1783 ) => Ok(self
1784 .linear_sum(constraint, coefficients, terms, None, values)?
1785 .map(|sum| Value::Boolean(relation.holds(sum, *bound)))),
1786 (
1787 Predicate::IntegerArithmetic {
1788 operation, inputs, ..
1789 },
1790 DefinitionDirection::IntegerArithmetic,
1791 ) => {
1792 let Some(inputs) = inputs
1793 .iter()
1794 .map(|input| input.value(values).map(Value::integer))
1795 .collect::<Option<Vec<_>>>()
1796 else {
1797 return Ok(None);
1798 };
1799 let value = operation
1800 .calculate(&inputs)
1801 .map_err(|message| constraint.execution_error(message))?;
1802 Ok(Some(Value::Integer(value)))
1803 }
1804 (
1805 Predicate::Linear {
1806 coefficients,
1807 terms,
1808 bound,
1809 ..
1810 }
1811 | Predicate::LinearRelation {
1812 coefficients,
1813 terms,
1814 bound,
1815 ..
1816 },
1817 DefinitionDirection::Linear { term: output_term },
1818 ) => {
1819 let Some(sum) =
1820 self.linear_sum(constraint, coefficients, terms, Some(output_term), values)?
1821 else {
1822 return Ok(None);
1823 };
1824 let numerator = bound
1825 .checked_sub(sum)
1826 .ok_or_else(|| constraint.linear_overflow())?;
1827 let coefficient = coefficients[output_term];
1828 let remainder = numerator
1829 .checked_rem(coefficient)
1830 .ok_or_else(|| constraint.linear_overflow())?;
1831 if remainder != 0 {
1832 return Ok(None);
1833 }
1834 let value = numerator
1835 .checked_div(coefficient)
1836 .ok_or_else(|| constraint.linear_overflow())?;
1837 Ok(Some(Value::Integer(value)))
1838 }
1839 (
1840 Predicate::ReifiedLessEqual { left, right, .. },
1841 DefinitionDirection::ReifiedLessEqual,
1842 ) => {
1843 let (Some(left), Some(right)) = (left.value(values), right.value(values)) else {
1844 return Ok(None);
1845 };
1846 let (Value::Integer(left), Value::Integer(right)) = (left, right) else {
1847 unreachable!("preparation validates reified operands")
1848 };
1849 Ok(Some(Value::Boolean(left <= right)))
1850 }
1851 (
1852 Predicate::SetRelation { .. } | Predicate::SetMembership { .. },
1853 DefinitionDirection::SetReified,
1854 ) => Ok(constraint.predicate.set_truth(values).map(Value::Boolean)),
1855 (
1856 Predicate::SetOperation {
1857 operation,
1858 left,
1859 right,
1860 ..
1861 },
1862 DefinitionDirection::SetOperation,
1863 ) => {
1864 let (Some(left), Some(right)) = (left.value(values), right.value(values)) else {
1865 return Ok(None);
1866 };
1867 Ok(Some(Value::IntegerSet(
1868 operation.calculate(left.set(), right.set()),
1869 )))
1870 }
1871 (Predicate::SetEqual { left, right }, DefinitionDirection::SetEqual { input }) => {
1872 Ok([left, right][input].value(values).cloned())
1873 }
1874 (Predicate::SetCardinality { set, .. }, DefinitionDirection::SetCardinality) => set
1875 .value(values)
1876 .map(|value| {
1877 value
1878 .set()
1879 .cardinality()
1880 .map(Value::Integer)
1881 .ok_or_else(|| {
1882 constraint.execution_error("checked i64 overflow in set cardinality")
1883 })
1884 })
1885 .transpose(),
1886 (Predicate::SetUnion { left, right, .. }, DefinitionDirection::SetUnion)
1887 | (
1888 Predicate::SetIntersection { left, right, .. },
1889 DefinitionDirection::SetIntersection,
1890 ) => {
1891 let (Some(left), Some(right)) = (left.value(values), right.value(values)) else {
1892 return Ok(None);
1893 };
1894 let set = if matches!(definition.direction, DefinitionDirection::SetUnion) {
1895 left.set().union(right.set())
1896 } else {
1897 left.set().intersection(right.set())
1898 };
1899 Ok(Some(Value::IntegerSet(set)))
1900 }
1901 _ => unreachable!("preparation selects supported definition directions"),
1902 }
1903 }
1904
1905 fn argument(&self, operand: &Operand, values: &[Option<Value>]) -> Option<ArgumentValue> {
1906 let value = operand.value(values)?;
1907 Some(ArgumentValue {
1908 variable: match operand {
1909 Operand::Literal(_) => None,
1910 Operand::Variable(slot) => Some(Box::new(self.slots[*slot].reference.clone())),
1911 },
1912 value: value.clone(),
1913 })
1914 }
1915
1916 fn float_sum(
1917 &self,
1918 constraint: &Constraint,
1919 coefficients: &[FiniteFloat],
1920 terms: &[Operand],
1921 skip: Option<usize>,
1922 values: &[Option<Value>],
1923 ) -> Result<Option<FiniteFloat>, CheckError> {
1924 let terms = coefficients
1925 .iter()
1926 .zip(terms)
1927 .enumerate()
1928 .filter(|(index, _)| Some(*index) != skip)
1929 .map(|(_, (&coefficient, term))| {
1930 term.value(values).map(|value| (coefficient, value.float()))
1931 })
1932 .collect::<Option<Vec<_>>>();
1933 terms
1934 .map(|terms| floats::sum(terms).map_err(|message| constraint.execution_error(message)))
1935 .transpose()
1936 }
1937
1938 fn linear_sum(
1939 &self,
1940 constraint: &Constraint,
1941 coefficients: &[i64],
1942 terms: &[Operand],
1943 skip: Option<usize>,
1944 values: &[Option<Value>],
1945 ) -> Result<Option<i64>, CheckError> {
1946 let terms = coefficients
1947 .iter()
1948 .zip(terms)
1949 .enumerate()
1950 .filter(|(index, _)| Some(*index) != skip)
1951 .map(|(_, (&coefficient, term))| {
1952 term.value(values).map(|value| {
1953 (
1954 coefficient,
1955 match value {
1956 Value::Integer(value) => *value,
1957 Value::Boolean(value) => i64::from(*value),
1958 Value::IntegerSet(_) | Value::Float(_) | Value::FloatSet(_) => {
1959 unreachable!("admission validates linear terms")
1960 }
1961 },
1962 )
1963 })
1964 })
1965 .collect::<Option<Vec<_>>>();
1966 terms
1967 .map(|terms| checked_sum(terms).ok_or_else(|| constraint.linear_overflow()))
1968 .transpose()
1969 }
1970
1971 fn condition_value(
1972 &self,
1973 condition: &RelationCondition,
1974 values: &[Option<Value>],
1975 ) -> RelationConditionValue {
1976 match condition {
1977 RelationCondition::Plain => RelationConditionValue::Plain,
1978 RelationCondition::Reified { result } => RelationConditionValue::Reified {
1979 result: self
1980 .argument(result, values)
1981 .expect("available reification result"),
1982 },
1983 RelationCondition::Implied { guard } => RelationConditionValue::Implied {
1984 guard: self
1985 .argument(guard, values)
1986 .expect("available implication guard"),
1987 },
1988 }
1989 }
1990
1991 fn selected_matches_result(
1992 &self,
1993 selected: &Operand,
1994 result: &Operand,
1995 values: &[Option<Value>],
1996 ) -> bool {
1997 let selected = selected.value(values).expect("available selected input");
1998 let result = result.value(values).expect("available selection result");
1999 match (selected, result) {
2000 (Value::Float(left), Value::Float(right)) => {
2001 self.float_tolerance
2002 .holds(IntegerRelation::Equal, *left, *right)
2003 }
2004 _ => selected == result,
2005 }
2006 }
2007
2008 fn missing(&self, predicate: &Predicate, values: &[Option<Value>]) -> Vec<VariableRef> {
2009 let operands = predicate.required_operands(values);
2010 let mut slots = HashSet::new();
2011 operands
2012 .iter()
2013 .filter_map(|operand| match operand {
2014 Operand::Variable(slot) if values[*slot].is_none() && slots.insert(*slot) => {
2015 Some(self.slots[*slot].reference.clone())
2016 }
2017 _ => None,
2018 })
2019 .collect()
2020 }
2021
2022 fn evaluate_disjunctive(
2023 &self,
2024 constraint: &Constraint,
2025 starts: &[Operand],
2026 durations: &[Operand],
2027 values: &[Option<Value>],
2028 ) -> Result<Option<ViolationKind>, CheckError> {
2029 let integer = |operand: &Operand| {
2030 operand
2031 .value(values)
2032 .expect("available global operand")
2033 .integer()
2034 };
2035 let ends: Vec<_> = starts
2036 .iter()
2037 .zip(durations)
2038 .map(|(start, duration)| {
2039 integer(start)
2040 .checked_add(integer(duration))
2041 .ok_or_else(|| {
2042 constraint
2043 .execution_error("checked i64 overflow in strict disjunctive endpoint")
2044 })
2045 })
2046 .collect::<Result<_, _>>()?;
2047 let mut conflicts = Vec::new();
2048 for (first, a) in starts.iter().enumerate() {
2049 for (second, b) in starts.iter().enumerate().skip(first + 1) {
2050 if ends[first] > integer(b) && ends[second] > integer(a) {
2051 conflicts.push(ConflictingPair {
2052 first: first + 1,
2053 second: second + 1,
2054 });
2055 }
2056 }
2057 }
2058 Ok((!conflicts.is_empty()).then(|| {
2059 let tasks = starts
2060 .iter()
2061 .zip(durations)
2062 .enumerate()
2063 .map(|(index, (start, duration))| TaskArguments {
2064 position: index + 1,
2065 start: self
2066 .argument(start, values)
2067 .expect("available global start"),
2068 duration: self
2069 .argument(duration, values)
2070 .expect("available global duration"),
2071 })
2072 .collect();
2073 ViolationKind::DisjunctiveStrict { tasks, conflicts }
2074 }))
2075 }
2076
2077 fn evaluate(
2078 &self,
2079 constraint: &Constraint,
2080 values: &[Option<Value>],
2081 ) -> Result<Option<ViolationKind>, CheckError> {
2082 let argument = |operand| {
2083 self.argument(operand, values)
2084 .expect("blocked constraints are excluded before evaluation")
2085 };
2086 match &constraint.predicate {
2087 Predicate::BinPacking(packing) => self.evaluate_packing(constraint, packing, values),
2088 Predicate::Rectangles(rectangles) => {
2089 self.evaluate_rectangles(constraint, rectangles, values)
2090 }
2091 Predicate::Scheduling(schedule) => self.evaluate_schedule(constraint, schedule, values),
2092 Predicate::NumberTheory(arithmetic) => {
2093 self.evaluate_number_theory(constraint, arithmetic, values)
2094 }
2095 Predicate::Distance(distance) => self.evaluate_distance(constraint, distance, values),
2096 Predicate::Circuit(circuit) => self.evaluate_circuit(constraint, circuit, values),
2097 Predicate::Ordering(ordering) => self.evaluate_ordering(constraint, ordering, values),
2098 Predicate::SetGlobal(global) => self.evaluate_set_global(constraint, global, values),
2099 Predicate::SetChannel(channel) => {
2100 self.evaluate_set_channel(constraint, channel, values)
2101 }
2102 Predicate::Counting(counting) => self.evaluate_counting(constraint, counting, values),
2103 Predicate::Automaton(automaton) => Ok(self.evaluate_automaton(automaton, values)),
2104 Predicate::Table(table) => Ok(self.evaluate_table(table, values)),
2105 Predicate::Element {
2106 indices,
2107 elements,
2108 result,
2109 layout,
2110 } => {
2111 if matches!(
2112 layout.position(indices, elements.len(), values),
2113 SelectionPosition::OutOfRange
2114 ) {
2115 return Ok(Some(ViolationKind::ElementRange {
2116 indices: indices
2117 .iter()
2118 .map(|index| self.argument(index, values))
2119 .collect(),
2120 layout: layout.clone(),
2121 length: elements.len(),
2122 result: self.argument(result, values),
2123 }));
2124 }
2125 let selected = constraint
2126 .predicate
2127 .selected_operand(values)
2128 .expect("available valid selector");
2129 Ok(
2130 (!self.selected_matches_result(selected, result, values)).then(|| {
2131 ViolationKind::ElementMismatch {
2132 indices: indices.iter().map(argument).collect(),
2133 layout: layout.clone(),
2134 selected: argument(selected),
2135 result: argument(result),
2136 }
2137 }),
2138 )
2139 }
2140 Predicate::Conditional {
2141 condition, result, ..
2142 } => {
2143 let selected = constraint
2144 .predicate
2145 .selected_operand(values)
2146 .expect("available condition");
2147 Ok(
2148 (!self.selected_matches_result(selected, result, values)).then(|| {
2149 ViolationKind::ConditionalMismatch {
2150 condition: argument(condition),
2151 selected: argument(selected),
2152 result: argument(result),
2153 }
2154 }),
2155 )
2156 }
2157 Predicate::FloatRelation {
2158 relation,
2159 left,
2160 right,
2161 condition,
2162 code,
2163 } => {
2164 let holds = self.float_tolerance.holds(
2165 *relation,
2166 left.value(values).expect("available operand").float(),
2167 right.value(values).expect("available operand").float(),
2168 );
2169 Ok(
2170 (!condition.satisfied(holds, values)).then(|| ViolationKind::FloatRelation {
2171 relation: *relation,
2172 left: argument(left),
2173 right: argument(right),
2174 condition: self.condition_value(condition, values),
2175 code: *code,
2176 }),
2177 )
2178 }
2179 Predicate::FloatLinear {
2180 relation,
2181 coefficients,
2182 terms,
2183 bound,
2184 condition,
2185 } => {
2186 let sum = self
2187 .float_sum(constraint, coefficients, terms, None, values)?
2188 .expect("available terms");
2189 let holds = self.float_tolerance.holds(*relation, sum, *bound);
2190 Ok(
2191 (!condition.satisfied(holds, values)).then(|| ViolationKind::FloatLinear {
2192 relation: *relation,
2193 coefficients: coefficients.clone(),
2194 terms: terms.iter().map(argument).collect(),
2195 bound: *bound,
2196 condition: self.condition_value(condition, values),
2197 sum,
2198 }),
2199 )
2200 }
2201 Predicate::FloatArithmetic {
2202 operation,
2203 inputs,
2204 result,
2205 } => {
2206 let inputs_values: Vec<_> = inputs
2207 .iter()
2208 .map(|input| input.value(values).expect("available operand").float())
2209 .collect();
2210 let expected = operation
2211 .calculate(&inputs_values)
2212 .map_err(|message| constraint.execution_error(message))?;
2213 Ok((!self.float_tolerance.equal(
2214 expected,
2215 result.value(values).expect("available operand").float(),
2216 ))
2217 .then(|| ViolationKind::FloatArithmetic {
2218 operation: *operation,
2219 inputs: inputs.iter().map(argument).collect(),
2220 result: argument(result),
2221 }))
2222 }
2223 Predicate::FloatIntegerPower {
2224 base,
2225 exponent,
2226 result,
2227 } => {
2228 let expected = floats::integer_power(
2229 base.value(values).expect("available operand").float(),
2230 *exponent,
2231 )
2232 .map_err(|message| constraint.execution_error(message))?;
2233 Ok((!self.float_tolerance.equal(
2234 expected,
2235 result.value(values).expect("available operand").float(),
2236 ))
2237 .then(|| ViolationKind::FloatIntegerPower {
2238 base: argument(base),
2239 exponent: *exponent,
2240 result: argument(result),
2241 }))
2242 }
2243 Predicate::FloatArrayExtremum {
2244 extremum,
2245 inputs,
2246 result,
2247 } => {
2248 let input_values: Vec<_> = inputs
2249 .iter()
2250 .map(|input| input.value(values).expect("available operand").float())
2251 .collect();
2252 let expected = extremum.calculate(&input_values);
2253 Ok((!self.float_tolerance.equal(
2254 expected,
2255 result.value(values).expect("available operand").float(),
2256 ))
2257 .then(|| ViolationKind::FloatArrayExtremum {
2258 extremum: *extremum,
2259 inputs: inputs.iter().map(argument).collect(),
2260 result: argument(result),
2261 }))
2262 }
2263 Predicate::FloatConversion {
2264 operation,
2265 input,
2266 result,
2267 } => {
2268 let expected = operation
2269 .calculate(input.value(values).expect("available operand"))
2270 .map_err(|message| constraint.execution_error(message))?;
2271 let actual = result.value(values).expect("available operand");
2272 let equal = match (&expected, actual) {
2273 (Value::Float(a), Value::Float(b)) => self.float_tolerance.equal(*a, *b),
2274 _ => expected == *actual,
2275 };
2276 Ok((!equal).then(|| ViolationKind::FloatConversion {
2277 operation: *operation,
2278 input: argument(input),
2279 result: argument(result),
2280 }))
2281 }
2282 Predicate::FloatMembership {
2283 membership,
2284 element,
2285 intervals,
2286 } => {
2287 let value = element.value(values).expect("available operand").float();
2288 let holds = intervals
2289 .iter()
2290 .any(|&(lower, upper)| self.float_tolerance.contains(value, lower, upper));
2291 Ok((!holds).then(|| ViolationKind::FloatMembership {
2292 membership: *membership,
2293 element: argument(element),
2294 intervals: intervals.clone(),
2295 }))
2296 }
2297
2298 Predicate::BooleanRelation {
2299 relation,
2300 left,
2301 right,
2302 condition,
2303 } => {
2304 let holds = relation.holds(
2305 i64::from(left.value(values).expect("available operand").boolean()),
2306 i64::from(right.value(values).expect("available operand").boolean()),
2307 );
2308 Ok(
2309 (!condition.satisfied(holds, values)).then(|| ViolationKind::BooleanRelation {
2310 relation: *relation,
2311 left: argument(left),
2312 right: argument(right),
2313 condition: self.condition_value(condition, values),
2314 }),
2315 )
2316 }
2317 Predicate::BooleanLinear {
2318 relation,
2319 coefficients,
2320 terms,
2321 bound,
2322 condition,
2323 } => {
2324 let sum = self
2325 .linear_sum(constraint, coefficients, terms, None, values)?
2326 .expect("available linear terms");
2327 let holds =
2328 relation.holds(sum, bound.value(values).expect("available bound").integer());
2329 Ok(
2330 (!condition.satisfied(holds, values)).then(|| ViolationKind::BooleanLinear {
2331 relation: *relation,
2332 coefficients: coefficients.clone(),
2333 terms: terms.iter().map(argument).collect(),
2334 sum,
2335 bound: argument(bound),
2336 condition: self.condition_value(condition, values),
2337 }),
2338 )
2339 }
2340 Predicate::BooleanOperation {
2341 operation,
2342 inputs,
2343 condition,
2344 } => {
2345 let inputs_values =
2346 boolean_values(inputs, values).expect("available Boolean inputs");
2347 Ok(
2348 (!condition.satisfied(operation.calculate(&inputs_values), values)).then(
2349 || ViolationKind::BooleanOperation {
2350 operation: *operation,
2351 inputs: inputs.iter().map(argument).collect(),
2352 condition: self.condition_value(condition, values),
2353 },
2354 ),
2355 )
2356 }
2357 Predicate::BooleanClause {
2358 positive,
2359 negative,
2360 condition,
2361 } => {
2362 let holds = boolean::clause(
2363 &boolean_values(positive, values).expect("available positive inputs"),
2364 &boolean_values(negative, values).expect("available negative inputs"),
2365 );
2366 Ok(
2367 (!condition.satisfied(holds, values)).then(|| ViolationKind::BooleanClause {
2368 positive: positive.iter().map(argument).collect(),
2369 negative: negative.iter().map(argument).collect(),
2370 condition: self.condition_value(condition, values),
2371 }),
2372 )
2373 }
2374 Predicate::BooleanToInteger { boolean, integer } => {
2375 let holds = i64::from(
2376 boolean
2377 .value(values)
2378 .expect("available Boolean input")
2379 .boolean(),
2380 ) == integer
2381 .value(values)
2382 .expect("available integer input")
2383 .integer();
2384 Ok((!holds).then(|| ViolationKind::BooleanToInteger {
2385 boolean: argument(boolean),
2386 integer: argument(integer),
2387 }))
2388 }
2389
2390 Predicate::IntegerRelation {
2391 relation,
2392 left,
2393 right,
2394 condition,
2395 } => {
2396 let holds = relation.holds(
2397 left.value(values).expect("available operand").integer(),
2398 right.value(values).expect("available operand").integer(),
2399 );
2400 Ok(
2401 (!condition.satisfied(holds, values)).then(|| ViolationKind::IntegerRelation {
2402 relation: *relation,
2403 left: argument(left),
2404 right: argument(right),
2405 condition: self.condition_value(condition, values),
2406 }),
2407 )
2408 }
2409 Predicate::LinearRelation {
2410 relation,
2411 coefficients,
2412 terms,
2413 bound,
2414 condition,
2415 } => {
2416 let sum = self
2417 .linear_sum(constraint, coefficients, terms, None, values)?
2418 .expect("available linear terms");
2419 Ok(
2420 (!condition.satisfied(relation.holds(sum, *bound), values)).then(|| {
2421 ViolationKind::LinearRelation {
2422 relation: *relation,
2423 coefficients: coefficients.clone(),
2424 terms: terms.iter().map(argument).collect(),
2425 sum,
2426 bound: *bound,
2427 condition: self.condition_value(condition, values),
2428 }
2429 }),
2430 )
2431 }
2432 Predicate::IntegerArithmetic {
2433 operation,
2434 inputs,
2435 result,
2436 } => {
2437 let input_values: Vec<_> = inputs
2438 .iter()
2439 .map(|input| input.value(values).expect("available operand").integer())
2440 .collect();
2441 let expected = operation
2442 .calculate(&input_values)
2443 .map_err(|message| constraint.execution_error(message))?;
2444 let actual = result.value(values).expect("available operand").integer();
2445 Ok(
2446 (expected != actual).then(|| ViolationKind::IntegerArithmetic {
2447 operation: *operation,
2448 inputs: inputs.iter().map(argument).collect(),
2449 result: argument(result),
2450 }),
2451 )
2452 }
2453 Predicate::SetRelation {
2454 relation,
2455 left,
2456 right,
2457 condition,
2458 native_code,
2459 } => {
2460 let truth = constraint
2461 .predicate
2462 .set_truth(values)
2463 .expect("available operands");
2464 Ok(
2465 (!condition.satisfied(truth, values)).then(|| ViolationKind::SetRelation {
2466 relation: *relation,
2467 left: argument(left),
2468 right: argument(right),
2469 condition: self.condition_value(condition, values),
2470 native_code: *native_code,
2471 }),
2472 )
2473 }
2474 Predicate::SetMembership {
2475 element,
2476 set,
2477 condition,
2478 } => {
2479 let truth = constraint
2480 .predicate
2481 .set_truth(values)
2482 .expect("available operands");
2483 Ok(
2484 (!condition.satisfied(truth, values)).then(|| ViolationKind::SetMembership {
2485 element: argument(element),
2486 set: argument(set),
2487 condition: self.condition_value(condition, values),
2488 }),
2489 )
2490 }
2491 Predicate::SetOperation {
2492 operation,
2493 left,
2494 right,
2495 result,
2496 } => {
2497 let expected = operation.calculate(
2498 left.value(values).expect("available operand").set(),
2499 right.value(values).expect("available operand").set(),
2500 );
2501 Ok(
2502 (expected != *result.value(values).expect("available operand").set()).then(
2503 || ViolationKind::SetOperation {
2504 operation: *operation,
2505 left: argument(left),
2506 right: argument(right),
2507 result: argument(result),
2508 },
2509 ),
2510 )
2511 }
2512 Predicate::SetIn { element, set } => {
2513 let element_value = element
2514 .value(values)
2515 .expect("available operand")
2516 .membership_element();
2517 let set_value = set.value(values).expect("available operand").set();
2518 Ok(
2519 (!set_value.contains(element_value)).then(|| ViolationKind::SetIn {
2520 element: argument(element),
2521 set: argument(set),
2522 }),
2523 )
2524 }
2525 Predicate::SetEqual { left, right } | Predicate::SetSubset { left, right } => {
2526 let left_value = left.value(values).expect("available operand").set();
2527 let right_value = right.value(values).expect("available operand").set();
2528 let equal = matches!(constraint.predicate, Predicate::SetEqual { .. });
2529 let satisfied = if equal {
2530 left_value == right_value
2531 } else {
2532 left_value.is_subset(right_value)
2533 };
2534 Ok((!satisfied).then(|| {
2535 if equal {
2536 ViolationKind::SetEqual {
2537 left: argument(left),
2538 right: argument(right),
2539 }
2540 } else {
2541 ViolationKind::SetSubset {
2542 left: argument(left),
2543 right: argument(right),
2544 }
2545 }
2546 }))
2547 }
2548 Predicate::SetCardinality { set, cardinality } => {
2549 let size = set
2550 .value(values)
2551 .expect("available operand")
2552 .set()
2553 .cardinality()
2554 .ok_or_else(|| {
2555 constraint.execution_error("checked i64 overflow in set cardinality")
2556 })?;
2557 let expected = cardinality
2558 .value(values)
2559 .expect("available operand")
2560 .integer();
2561 Ok((size != expected).then(|| ViolationKind::SetCardinality {
2562 set: argument(set),
2563 cardinality: argument(cardinality),
2564 }))
2565 }
2566 Predicate::SetUnion {
2567 left,
2568 right,
2569 result,
2570 }
2571 | Predicate::SetIntersection {
2572 left,
2573 right,
2574 result,
2575 } => {
2576 let left_value = left.value(values).expect("available operand").set();
2577 let right_value = right.value(values).expect("available operand").set();
2578 let union = matches!(constraint.predicate, Predicate::SetUnion { .. });
2579 let expected = if union {
2580 left_value.union(right_value)
2581 } else {
2582 left_value.intersection(right_value)
2583 };
2584 let actual = result.value(values).expect("available operand").set();
2585 Ok((expected != *actual).then(|| {
2586 if union {
2587 ViolationKind::SetUnion {
2588 left: argument(left),
2589 right: argument(right),
2590 result: argument(result),
2591 }
2592 } else {
2593 ViolationKind::SetIntersection {
2594 left: argument(left),
2595 right: argument(right),
2596 result: argument(result),
2597 }
2598 }
2599 }))
2600 }
2601 Predicate::DisjunctiveStrict { starts, durations } => {
2602 self.evaluate_disjunctive(constraint, starts, durations, values)
2603 }
2604 Predicate::Linear {
2605 coefficients,
2606 terms,
2607 bound,
2608 equality,
2609 } => {
2610 let sum = self
2611 .linear_sum(constraint, coefficients, terms, None, values)?
2612 .expect("available linear terms");
2613 let terms: Vec<_> = terms.iter().map(argument).collect();
2614 let satisfied = if *equality {
2615 sum == *bound
2616 } else {
2617 sum <= *bound
2618 };
2619 Ok((!satisfied).then(|| ViolationKind::Linear {
2620 coefficients: coefficients.clone(),
2621 terms,
2622 sum,
2623 bound: *bound,
2624 }))
2625 }
2626 Predicate::ReifiedLessEqual {
2627 left,
2628 right,
2629 result,
2630 } => {
2631 let (left, right, result) = (argument(left), argument(right), argument(result));
2632 let (Value::Integer(x), Value::Integer(y), Value::Boolean(b)) =
2633 (&left.value, &right.value, &result.value)
2634 else {
2635 unreachable!("preparation validates reified operands")
2636 };
2637 Ok(((x <= y) != *b).then_some(ViolationKind::ReifiedLessEqual {
2638 left,
2639 right,
2640 result,
2641 }))
2642 }
2643 }
2644 }
2645}
2646
2647fn serialize_optional_integer<S: serde::Serializer>(
2648 value: &Option<i64>,
2649 serializer: S,
2650) -> Result<S::Ok, S::Error> {
2651 value.map(|value| value.to_string()).serialize(serializer)
2652}
2653
2654fn deserialize_optional_integer<'de, D: serde::Deserializer<'de>>(
2655 deserializer: D,
2656) -> Result<Option<i64>, D::Error> {
2657 Option::<String>::deserialize(deserializer)?
2658 .map(|value| value.parse().map_err(serde::de::Error::custom))
2659 .transpose()
2660}
2661
2662fn serialize_integer<S: serde::Serializer>(value: &i64, serializer: S) -> Result<S::Ok, S::Error> {
2663 serializer.collect_str(value)
2664}
2665
2666fn serialize_integers<S: serde::Serializer>(
2667 values: &[i64],
2668 serializer: S,
2669) -> Result<S::Ok, S::Error> {
2670 use serde::ser::SerializeSeq;
2671 let mut sequence = serializer.serialize_seq(Some(values.len()))?;
2672 for value in values {
2673 sequence.serialize_element(&value.to_string())?;
2674 }
2675 sequence.end()
2676}
2677
2678fn deserialize_integer<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<i64, D::Error> {
2679 String::deserialize(deserializer)?
2680 .parse()
2681 .map_err(serde::de::Error::custom)
2682}
2683
2684fn deserialize_integers<'de, D: serde::Deserializer<'de>>(
2685 deserializer: D,
2686) -> Result<Vec<i64>, D::Error> {
2687 Vec::<String>::deserialize(deserializer)?
2688 .into_iter()
2689 .map(|value| value.parse().map_err(serde::de::Error::custom))
2690 .collect()
2691}
2692
2693impl PreparedModel {
2694 fn link_aliases(&mut self) {
2695 let mut aliases = vec![Vec::new(); self.slots.len()];
2696 for variable in &self.variables {
2697 aliases[variable.slot].push(VariableAlias {
2698 name: variable.reference.name.clone(),
2699 position: variable.reference.position,
2700 });
2701 }
2702 let link = |reference: &mut VariableRef, slot: usize| {
2703 reference.aliases = aliases[slot]
2704 .iter()
2705 .filter(|alias| {
2706 alias.name != reference.name || alias.position != reference.position
2707 })
2708 .cloned()
2709 .collect();
2710 };
2711 for variable in &mut self.variables {
2712 link(&mut variable.reference, variable.slot);
2713 }
2714 for (slot, value) in self.slots.iter_mut().enumerate() {
2715 link(&mut value.reference, slot);
2716 }
2717 }
2718
2719 fn definition_targets(&self, constraint: &Constraint) -> Result<Vec<usize>, Diagnostic> {
2720 let fail = |message: &str| Diagnostic {
2721 location: Some(constraint.reference.location.clone()),
2722 message: message.into(),
2723 };
2724 let Some(target) = &constraint.reference.metadata.defines else {
2725 return Ok(Vec::new());
2726 };
2727 let names: Vec<_> = match target {
2728 DefinitionTarget::Name(name) => vec![name],
2729 DefinitionTarget::Elements(names) => names.iter().collect(),
2730 };
2731 let mut slots = Vec::new();
2732 let mut target_kinds = Vec::new();
2733 let mut array_target = matches!(target, DefinitionTarget::Elements(_));
2734 for name in names {
2735 let binding = self
2736 .bindings
2737 .get(name)
2738 .ok_or_else(|| fail("defines_var names an unknown variable"))?;
2739 if !binding.assignable
2740 || (matches!(target, DefinitionTarget::Elements(_)) && binding.is_array)
2741 {
2742 return Err(fail("defines_var needs an assignable variable target"));
2743 }
2744 array_target |= binding.is_array;
2745 target_kinds.push(binding.kind);
2746 for operand in &binding.elements {
2747 let Operand::Variable(slot) = operand else {
2748 return Err(fail("defines_var needs variable slots"));
2749 };
2750 if self
2751 .slots
2752 .get(*slot)
2753 .is_none_or(|entry| entry.kind != binding.kind)
2754 {
2755 return Err(fail("defines_var target has an invalid slot"));
2756 }
2757 slots.push(*slot);
2758 }
2759 }
2760 if array_target {
2761 let outputs: Vec<(Vec<&Operand>, ValueType)> = match &constraint.predicate {
2762 Predicate::BinPacking(packing) => {
2763 vec![(packing.loads.iter().collect(), ValueType::Integer)]
2764 }
2765 Predicate::Counting(Counting::Cardinality {
2766 counts: counting::CardinalityCounts::Exact(counts),
2767 ..
2768 }) => vec![(counts.iter().collect(), ValueType::Integer)],
2769 Predicate::Circuit(circuit) => circuit
2770 .array_outputs()
2771 .into_iter()
2772 .map(|outputs| (outputs, ValueType::Integer))
2773 .collect(),
2774 Predicate::SetChannel(channel) => channel
2775 .array_outputs()
2776 .into_iter()
2777 .map(|(outputs, kind)| (outputs.iter().collect(), kind))
2778 .collect(),
2779 Predicate::Ordering(ordering) => ordering
2780 .array_outputs()
2781 .into_iter()
2782 .map(|(outputs, kind)| (outputs.iter().collect(), kind))
2783 .collect(),
2784 _ => Vec::new(),
2785 };
2786 let mut targets = slots.clone();
2788 targets.sort_unstable();
2789 let matches = outputs.iter().any(|(outputs, kind)| {
2790 if target_kinds.iter().any(|target| target != kind) {
2791 return false;
2792 }
2793 let Some(mut outputs) = outputs
2794 .iter()
2795 .map(|operand| match operand {
2796 Operand::Variable(slot) => Some(*slot),
2797 Operand::Literal(_) => None,
2798 })
2799 .collect::<Option<Vec<_>>>()
2800 else {
2801 return false;
2802 };
2803 outputs.sort_unstable();
2804 outputs == targets
2805 });
2806 if !matches {
2807 return Err(fail(
2808 "array defines_var target must match a supported complete output array",
2809 ));
2810 }
2811 } else if slots.len() != 1 {
2812 return Err(fail("defines_var needs a scalar variable"));
2813 }
2814 Ok(slots)
2815 }
2816
2817 fn prepare_definitions(&mut self) -> Result<(), Diagnostic> {
2818 let mut defined = HashSet::new();
2819 self.definitions.clear();
2820 self.dependents = vec![Vec::new(); self.slots.len()];
2821 for (constraint_index, constraint) in self.constraints.iter().enumerate() {
2822 if constraint.reference.metadata.defines.is_none() {
2823 continue;
2824 }
2825 let fail = |message: &str| Diagnostic {
2826 location: Some(constraint.reference.location.clone()),
2827 message: message.into(),
2828 };
2829 let targets = self.definition_targets(constraint)?;
2830 let mut unique_targets = HashSet::new();
2831 for slot in &targets {
2832 if !unique_targets.insert(*slot) {
2833 continue;
2834 }
2835 if !defined.insert(*slot) {
2836 return Err(fail("a variable has multiple defines_var annotations"));
2837 }
2838 let direction = definition_direction(constraint, *slot)?;
2839 self.slots[*slot].default = None;
2841 if let Some(direction) = direction {
2842 let inputs = constraint.predicate.operands();
2843 let definition_index = self.definitions.len();
2844 let mut inputs_seen = HashSet::new();
2845 for operand in inputs {
2846 if let Operand::Variable(input) = operand
2847 && input != slot
2848 && inputs_seen.insert(*input)
2849 {
2850 self.dependents[*input].push(definition_index);
2851 }
2852 }
2853 self.definitions.push(Definition {
2854 constraint: constraint_index,
2855 output: *slot,
2856 direction,
2857 });
2858 }
2859 }
2860 }
2861 for variable in &self.variables {
2863 if defined.contains(&variable.slot) {
2864 for domain in &variable.domains {
2865 if let Domain::Fixed { value } = domain {
2866 self.slots[variable.slot].default = Some(value.clone());
2867 }
2868 }
2869 }
2870 }
2871 Ok(())
2872 }
2873}
2874
2875fn definition_direction(
2876 constraint: &Constraint,
2877 output: usize,
2878) -> Result<Option<DefinitionDirection>, Diagnostic> {
2879 let absent = || Diagnostic {
2880 location: Some(constraint.reference.location.clone()),
2881 message: "defines_var target does not occur in its relation".into(),
2882 };
2883 let operands = constraint.predicate.operands();
2884 let occurrences: Vec<_> = operands
2885 .iter()
2886 .enumerate()
2887 .filter_map(|(index, operand)| {
2888 matches!(operand, Operand::Variable(slot) if *slot == output).then_some(index)
2889 })
2890 .collect();
2891 if occurrences.is_empty() {
2892 return Err(absent());
2893 }
2894 match &constraint.predicate {
2895 Predicate::BinPacking(packing) => Ok(packing
2896 .can_define(output)
2897 .then_some(DefinitionDirection::BinPacking)),
2898 Predicate::Table(table) => Ok(table
2899 .can_define(output)
2900 .then_some(DefinitionDirection::Table)),
2901 Predicate::NumberTheory(arithmetic) => Ok(arithmetic
2902 .can_define(output)
2903 .then_some(DefinitionDirection::NumberTheory)),
2904 Predicate::Distance(distance) => Ok(distance
2905 .can_define(output)
2906 .then_some(DefinitionDirection::Distance)),
2907 Predicate::Circuit(circuit) => Ok(circuit
2908 .can_define(output)
2909 .then_some(DefinitionDirection::Circuit)),
2910 Predicate::SetChannel(channel) => Ok(channel
2911 .can_define(output)
2912 .then_some(DefinitionDirection::SetChannel)),
2913 Predicate::SetGlobal(global) => Ok(global
2914 .can_define(output)
2915 .then_some(DefinitionDirection::SetGlobal)),
2916 Predicate::Ordering(ordering) => Ok(ordering
2917 .can_define(output)
2918 .then_some(DefinitionDirection::Ordering)),
2919 Predicate::Counting(counting) => Ok(counting
2920 .can_define(output)
2921 .then_some(DefinitionDirection::Counting)),
2922 Predicate::Element { result, .. } | Predicate::Conditional { result, .. } => {
2923 Ok(matches!(result, Operand::Variable(slot) if *slot == output)
2924 .then_some(DefinitionDirection::Selection))
2925 }
2926 Predicate::FloatRelation {
2927 relation,
2928 condition,
2929 ..
2930 } => Ok(match condition {
2931 RelationCondition::Plain
2932 if *relation == IntegerRelation::Equal && occurrences.len() == 1 =>
2933 {
2934 Some(DefinitionDirection::FloatEqual {
2935 input: 1 - occurrences[0],
2936 })
2937 }
2938 RelationCondition::Reified { .. } if occurrences.as_slice() == [2] => {
2939 Some(DefinitionDirection::FloatReified)
2940 }
2941 _ => None,
2942 }),
2943 Predicate::FloatLinear {
2944 relation,
2945 coefficients,
2946 terms,
2947 condition,
2948 ..
2949 } => Ok(match condition {
2950 RelationCondition::Plain
2951 if *relation == IntegerRelation::Equal
2952 && occurrences.len() == 1
2953 && coefficients[occurrences[0]].get() != 0.0 =>
2954 {
2955 Some(DefinitionDirection::FloatLinear {
2956 term: occurrences[0],
2957 })
2958 }
2959 RelationCondition::Reified { .. } if occurrences.as_slice() == [terms.len()] => {
2960 Some(DefinitionDirection::FloatReified)
2961 }
2962 _ => None,
2963 }),
2964 Predicate::FloatArithmetic { inputs, .. } => Ok((occurrences.as_slice() == [inputs.len()])
2965 .then_some(DefinitionDirection::FloatArithmetic)),
2966 Predicate::FloatIntegerPower { .. } => {
2967 Ok((occurrences.as_slice() == [1]).then_some(DefinitionDirection::FloatIntegerPower))
2968 }
2969 Predicate::FloatArrayExtremum { inputs, .. } => Ok((occurrences.as_slice()
2970 == [inputs.len()])
2971 .then_some(DefinitionDirection::FloatArrayExtremum)),
2972 Predicate::FloatConversion { .. } => {
2973 Ok((occurrences.as_slice() == [1]).then_some(DefinitionDirection::FloatConversion))
2974 }
2975 Predicate::FloatMembership { .. } => Ok(None),
2976
2977 Predicate::BooleanRelation {
2978 relation,
2979 condition,
2980 ..
2981 } => Ok(match condition {
2982 RelationCondition::Plain
2983 if occurrences.len() == 1
2984 && matches!(relation, IntegerRelation::Equal | IntegerRelation::NotEqual) =>
2985 {
2986 Some(DefinitionDirection::BooleanCopy {
2987 input: 1 - occurrences[0],
2988 complement: *relation == IntegerRelation::NotEqual,
2989 })
2990 }
2991 RelationCondition::Reified { .. } if occurrences.as_slice() == [2] => {
2992 Some(DefinitionDirection::ReifiedRelation)
2993 }
2994 _ => None,
2995 }),
2996 Predicate::BooleanLinear {
2997 relation,
2998 coefficients,
2999 terms,
3000 condition,
3001 ..
3002 } => {
3003 let position = occurrences[0];
3004 Ok(match condition {
3005 RelationCondition::Plain
3006 if *relation == IntegerRelation::Equal && occurrences.len() == 1 =>
3007 {
3008 if position == terms.len() {
3009 Some(DefinitionDirection::BooleanLinearBound)
3010 } else if coefficients[position] != 0 {
3011 Some(DefinitionDirection::BooleanLinearTerm { term: position })
3012 } else {
3013 None
3014 }
3015 }
3016 RelationCondition::Reified { .. }
3017 if occurrences.as_slice() == [terms.len() + 1] =>
3018 {
3019 Some(DefinitionDirection::ReifiedRelation)
3020 }
3021 _ => None,
3022 })
3023 }
3024 Predicate::BooleanOperation {
3025 operation,
3026 inputs,
3027 condition,
3028 } => Ok(match condition {
3029 RelationCondition::Reified { .. }
3030 if *operation == BooleanOperation::Not && occurrences.len() == 1 =>
3031 {
3032 Some(DefinitionDirection::BooleanCopy {
3033 input: 1 - occurrences[0],
3034 complement: true,
3035 })
3036 }
3037 RelationCondition::Plain
3038 if *operation == BooleanOperation::Xor
3039 && inputs.len() == 2
3040 && occurrences.len() == 1
3041 && matches!(
3042 BooleanName::from_name(&constraint.reference.predicate)
3043 .map(|name| name.kind),
3044 Some(BooleanKind::Scalar(_))
3045 ) =>
3046 {
3047 Some(DefinitionDirection::BooleanCopy {
3048 input: 1 - occurrences[0],
3049 complement: true,
3050 })
3051 }
3052 RelationCondition::Reified { .. } if occurrences.as_slice() == [inputs.len()] => {
3053 Some(DefinitionDirection::BooleanResult)
3054 }
3055 _ => None,
3056 }),
3057 Predicate::BooleanClause {
3058 positive,
3059 negative,
3060 condition,
3061 } => Ok((matches!(condition, RelationCondition::Reified { .. })
3062 && occurrences.as_slice() == [positive.len() + negative.len()])
3063 .then_some(DefinitionDirection::BooleanResult)),
3064 Predicate::BooleanToInteger { .. } => Ok(if occurrences.len() == 1 {
3065 Some(if occurrences[0] == 0 {
3066 DefinitionDirection::IntegerToBoolean
3067 } else {
3068 DefinitionDirection::BooleanToInteger
3069 })
3070 } else {
3071 None
3072 }),
3073
3074 Predicate::IntegerRelation {
3075 relation,
3076 condition,
3077 ..
3078 } => Ok(match condition {
3079 RelationCondition::Plain
3080 if *relation == IntegerRelation::Equal && occurrences.len() == 1 =>
3081 {
3082 Some(DefinitionDirection::IntegerEqual {
3083 input: 1 - occurrences[0],
3084 })
3085 }
3086 RelationCondition::Reified { .. } if occurrences.as_slice() == [2] => {
3087 Some(DefinitionDirection::ReifiedRelation)
3088 }
3089 _ => None,
3090 }),
3091 Predicate::LinearRelation {
3092 relation,
3093 coefficients,
3094 terms,
3095 condition,
3096 ..
3097 } => {
3098 let term = occurrences[0];
3099 Ok(match condition {
3100 RelationCondition::Plain
3101 if *relation == IntegerRelation::Equal
3102 && occurrences.len() == 1
3103 && coefficients[term] != 0 =>
3104 {
3105 Some(DefinitionDirection::Linear { term })
3106 }
3107 RelationCondition::Reified { .. } if occurrences.as_slice() == [terms.len()] => {
3108 Some(DefinitionDirection::ReifiedRelation)
3109 }
3110 _ => None,
3111 })
3112 }
3113 Predicate::IntegerArithmetic { inputs, .. } => {
3114 let is_final_output = occurrences.as_slice() == [inputs.len()];
3115 Ok(is_final_output.then_some(DefinitionDirection::IntegerArithmetic))
3116 }
3117 Predicate::SetRelation { condition, .. } | Predicate::SetMembership { condition, .. } => {
3118 Ok((matches!(condition, RelationCondition::Reified { .. })
3119 && occurrences.as_slice() == [2])
3120 .then_some(DefinitionDirection::SetReified))
3121 }
3122 Predicate::SetOperation { .. } => {
3123 Ok((occurrences.as_slice() == [2]).then_some(DefinitionDirection::SetOperation))
3124 }
3125 Predicate::SetEqual { .. } => {
3126 Ok(
3127 (occurrences.len() == 1).then(|| DefinitionDirection::SetEqual {
3128 input: 1 - occurrences[0],
3129 }),
3130 )
3131 }
3132 Predicate::SetCardinality { .. } => {
3133 Ok((occurrences.as_slice() == [1]).then_some(DefinitionDirection::SetCardinality))
3134 }
3135 Predicate::SetUnion { .. } => {
3136 Ok((occurrences.as_slice() == [2]).then_some(DefinitionDirection::SetUnion))
3137 }
3138 Predicate::SetIntersection { .. } => {
3139 Ok((occurrences.as_slice() == [2]).then_some(DefinitionDirection::SetIntersection))
3140 }
3141 Predicate::Automaton(_)
3142 | Predicate::Rectangles(_)
3143 | Predicate::Scheduling(_)
3144 | Predicate::SetIn { .. }
3145 | Predicate::SetSubset { .. }
3146 | Predicate::DisjunctiveStrict { .. } => Ok(None),
3147 Predicate::Linear {
3148 coefficients,
3149 equality,
3150 ..
3151 } => {
3152 let term = occurrences[0];
3153 Ok(
3154 (*equality && occurrences.len() == 1 && coefficients[term] != 0)
3155 .then_some(DefinitionDirection::Linear { term }),
3156 )
3157 }
3158 Predicate::ReifiedLessEqual { result, .. } => {
3159 Ok(matches!(result, Operand::Variable(slot) if *slot == output)
3160 .then_some(DefinitionDirection::ReifiedLessEqual))
3161 }
3162 }
3163}
3164
3165impl Domain {
3166 fn singleton(&self) -> Option<Value> {
3167 match self {
3168 Self::FloatRanges { values } => match values.ranges() {
3169 [(lower, upper)] if lower == upper => Some(Value::Float(*lower)),
3170 _ => None,
3171 },
3172 Self::IntegerRanges { values } if values.cardinality() == Some(1) => {
3173 values.minimum().map(Value::Integer)
3174 }
3175 Self::BooleanValues { values } if values.len() == 1 => Some(Value::Boolean(values[0])),
3176 Self::FloatInterval { lower, upper } if lower == upper => Some(Value::Float(*lower)),
3177 Self::Interval { lower, upper } if lower == upper => Some(Value::Integer(*lower)),
3178 Self::Enumeration { values } if values.len() == 1 => Some(Value::Integer(values[0])),
3179 Self::Fixed { value } => Some(value.clone()),
3180 Self::IntegerSet { upper: Some(upper) } if upper.is_empty() => {
3181 Some(Value::IntegerSet(IntegerSet::empty()))
3182 }
3183 _ => None,
3184 }
3185 }
3186}
3187
3188fn boolean_values(operands: &[Operand], values: &[Option<Value>]) -> Option<Vec<bool>> {
3189 operands
3190 .iter()
3191 .map(|operand| operand.value(values).map(Value::boolean))
3192 .collect()
3193}