Skip to main content

zincite_check/
lib.rs

1//! Check repeated candidates against a prepared FlatZinc model.
2//! Preparation is optional; checking performs no I/O and starts no external tools.
3
4use 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/// Mathematical integers use checked i64 arithmetic. JSON writes decimal strings.
92#[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/// The declared name or explicit scalar names supplied to defines_var.
218#[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    /// One-based FlatZinc position for an array element.
244    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/// Entries keep their written order so duplicate names can be diagnosed.
361#[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    /// One-based position in the global's arrays.
667    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/// An executable model. Its fields are private so checking uses validated inputs.
1286/// Export with `to_json`; `from_json` validates the executable model before use.
1287#[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    /// Check every available domain and relation using fresh candidate values.
1311    /// Missing values produce a normal report, including any known violations.
1312    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            // Annotation order identifies slots; predicate positions own the calculation.
2787            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                // Domain singletons must not preempt a definition's output.
2840                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        // Literal initializers supply known values even for definition targets.
2862        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}