1use std::borrow::Cow;
2use std::collections::{BTreeSet, HashSet, VecDeque};
3use std::fmt::{Display, Formatter};
4use std::hash::{DefaultHasher, Hash, Hasher};
5use std::sync::atomic::{AtomicU64, Ordering};
6
7static HASH_HITS: AtomicU64 = AtomicU64::new(0);
8static HASH_MISSES: AtomicU64 = AtomicU64::new(0);
9
10pub fn print_hash_stats() {
11 println!(
12 "Expression content hash stats: hits={}, misses={}",
13 HASH_HITS.load(Ordering::Relaxed),
14 HASH_MISSES.load(Ordering::Relaxed)
15 );
16}
17use tracing::trace;
18
19use conjure_cp_enum_compatibility_macro::{document_compatibility, generate_discriminants};
20use itertools::Itertools;
21use serde::{Deserialize, Serialize};
22use ustr::Ustr;
23
24use polyquine::Quine;
25use uniplate::{Biplate, Uniplate};
26
27use crate::ast::FuncAttr;
28use crate::ast::metadata::NO_HASH;
29use crate::bug;
30
31use super::ac_operators::ACOperatorKind;
32use super::categories::{Category, CategoryOf};
33use super::comprehension::{Comprehension, ComprehensionQualifier};
34use super::declaration::DeclarationKind;
35use super::domains::HasDomain as _;
36use super::eval::{eval_constant, factorial_i32};
37use super::pretty::{pretty_expression_domain_annotation, pretty_expression_type_annotation};
38use super::pretty::{pretty_expressions_as_top_level, pretty_vec};
39use super::records::Field;
40use super::sat_encoding::SATIntEncoding;
41use super::{
42 AbstractLiteral, Atom, DeclarationPtr, Domain, DomainPtr, GroundDomain, IntVal, JectivityAttr,
43 Literal, MSetAttr, Metadata, Model, Moo, Name, PartialityAttr, Range, Reference, RelAttr,
44 ReturnType, SetAttr, SymbolTable, SymbolTablePtr, Typeable, UnresolvedDomain, matrix,
45};
46
47static_assertions::const_assert!(std::mem::size_of::<Expression>() <= 152);
71
72#[generate_discriminants]
77#[document_compatibility]
78#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Uniplate, Quine)]
79#[biplate(to=AbstractLiteral<Expression>)]
80#[biplate(to=AbstractLiteral<Literal>)]
81#[biplate(to=Atom)]
82#[biplate(to=Comprehension)]
83#[biplate(to=DeclarationPtr)]
84#[biplate(to=DomainPtr)]
85#[biplate(to=Literal)]
86#[biplate(to=Metadata)]
87#[biplate(to=Name)]
88#[biplate(to=Option<Expression>)]
89#[biplate(to=Field<Expression>)]
90#[biplate(to=Field<Literal>)]
91#[biplate(to=Reference)]
92#[biplate(to=Model)]
93#[biplate(to=SymbolTable)]
94#[biplate(to=SymbolTablePtr)]
95#[biplate(to=Vec<Expression>)]
96#[path_prefix(conjure_cp::ast)]
97pub enum Expression {
98 AbstractLiteral(Metadata, AbstractLiteral<Expression>),
99 Root(Metadata, Vec<Expression>),
101
102 Bubble(Metadata, Moo<Expression>, Moo<Expression>),
105
106 #[polyquine_skip]
112 Comprehension(Metadata, Moo<Comprehension>),
113
114 DominanceRelation(Metadata, Moo<Expression>),
116 FromSolution(Metadata, Moo<Atom>),
118
119 #[polyquine_with(arm = (_, name) => {
120 let ident = proc_macro2::Ident::new(name.as_str(), proc_macro2::Span::call_site());
121 quote::quote! { #ident.clone().into() }
122 })]
123 Metavar(Metadata, Ustr),
124
125 Atomic(Metadata, Atom),
126
127 TypeAnnotation(Metadata, Moo<Expression>, DomainPtr),
129
130 DomainAnnotation(Metadata, Moo<Expression>, DomainPtr),
132
133 #[compatible(JsonInput)]
136 Active(Metadata, Moo<Expression>, Name),
137
138 #[compatible(JsonInput)]
141 RecordField(Metadata, Moo<Expression>, Name),
142
143 #[compatible(JsonInput)]
147 UnsafeIndex(Metadata, Moo<Expression>, Vec<Expression>),
148
149 #[compatible(SMT)]
153 SafeIndex(Metadata, Moo<Expression>, Vec<Expression>),
154
155 #[compatible(JsonInput)]
165 UnsafeSlice(Metadata, Moo<Expression>, Vec<Option<Expression>>),
166
167 SafeSlice(Metadata, Moo<Expression>, Vec<Option<Expression>>),
171
172 InDomain(Metadata, Moo<Expression>, DomainPtr),
178
179 #[compatible(SMT)]
185 ToInt(Metadata, Moo<Expression>),
186
187 #[compatible(JsonInput, SMT)]
189 Abs(Metadata, Moo<Expression>),
190
191 #[compatible(JsonInput, SMT)]
193 Sum(Metadata, Moo<Expression>),
194
195 #[compatible(JsonInput, SMT)]
197 Product(Metadata, Moo<Expression>),
198
199 #[compatible(JsonInput, SMT)]
201 Min(Metadata, Moo<Expression>),
202
203 #[compatible(JsonInput, SMT)]
205 Max(Metadata, Moo<Expression>),
206
207 #[compatible(JsonInput, SAT, SMT)]
209 Not(Metadata, Moo<Expression>),
210
211 #[compatible(JsonInput, SAT, SMT)]
213 Or(Metadata, Moo<Expression>),
214
215 #[compatible(JsonInput, SAT, SMT)]
217 And(Metadata, Moo<Expression>),
218
219 #[compatible(JsonInput, SMT)]
221 Imply(Metadata, Moo<Expression>, Moo<Expression>),
222
223 #[compatible(JsonInput, SMT)]
225 Iff(Metadata, Moo<Expression>, Moo<Expression>),
226
227 #[compatible(JsonInput)]
228 Union(Metadata, Moo<Expression>, Moo<Expression>),
229
230 #[compatible(JsonInput)]
231 In(Metadata, Moo<Expression>, Moo<Expression>),
232
233 #[compatible(JsonInput)]
234 Intersect(Metadata, Moo<Expression>, Moo<Expression>),
235
236 #[compatible(JsonInput)]
242 Difference(Metadata, Moo<Expression>, Moo<Expression>),
243
244 #[compatible(JsonInput)]
245 Supset(Metadata, Moo<Expression>, Moo<Expression>),
246
247 #[compatible(JsonInput)]
248 SupsetEq(Metadata, Moo<Expression>, Moo<Expression>),
249
250 #[compatible(JsonInput)]
251 Subset(Metadata, Moo<Expression>, Moo<Expression>),
252
253 #[compatible(JsonInput)]
254 SubsetEq(Metadata, Moo<Expression>, Moo<Expression>),
255
256 #[compatible(JsonInput, SMT)]
257 Eq(Metadata, Moo<Expression>, Moo<Expression>),
258
259 #[compatible(JsonInput, SMT)]
260 Neq(Metadata, Moo<Expression>, Moo<Expression>),
261
262 #[compatible(JsonInput, SMT)]
263 Geq(Metadata, Moo<Expression>, Moo<Expression>),
264
265 #[compatible(JsonInput, SMT)]
266 Leq(Metadata, Moo<Expression>, Moo<Expression>),
267
268 #[compatible(JsonInput, SMT)]
269 Gt(Metadata, Moo<Expression>, Moo<Expression>),
270
271 #[compatible(JsonInput, SMT)]
272 Lt(Metadata, Moo<Expression>, Moo<Expression>),
273
274 #[compatible(JsonInput)]
277 Subsequence(Metadata, Moo<Expression>, Moo<Expression>),
278
279 #[compatible(JsonInput)]
282 Substring(Metadata, Moo<Expression>, Moo<Expression>),
283
284 #[compatible(JsonInput)]
289 CatchUndef(Metadata, Moo<Expression>, Moo<Expression>),
290
291 #[compatible(SMT)]
293 SafeDiv(Metadata, Moo<Expression>, Moo<Expression>),
294
295 #[compatible(JsonInput)]
297 UnsafeDiv(Metadata, Moo<Expression>, Moo<Expression>),
298
299 #[compatible(SMT)]
301 SafeMod(Metadata, Moo<Expression>, Moo<Expression>),
302
303 #[compatible(JsonInput)]
305 UnsafeMod(Metadata, Moo<Expression>, Moo<Expression>),
306
307 #[compatible(JsonInput, SMT)]
309 Neg(Metadata, Moo<Expression>),
310
311 #[compatible(JsonInput)]
313 Factorial(Metadata, Moo<Expression>),
314
315 #[compatible(JsonInput)]
317 Defined(Metadata, Moo<Expression>),
318
319 #[compatible(JsonInput)]
321 Range(Metadata, Moo<Expression>),
322
323 #[compatible(JsonInput)]
324 ToSet(Metadata, Moo<Expression>),
325
326 #[compatible(JsonInput)]
327 ToMSet(Metadata, Moo<Expression>),
328
329 #[compatible(JsonInput)]
330 ToRelation(Metadata, Moo<Expression>),
331
332 #[compatible(JsonInput)]
336 UnsafePow(Metadata, Moo<Expression>, Moo<Expression>),
337
338 SafePow(Metadata, Moo<Expression>, Moo<Expression>),
340
341 Flatten(Metadata, Option<Moo<Expression>>, Moo<Expression>),
345
346 AttributeAsConstraint(Metadata, Moo<Expression>, Ustr, Option<Moo<Expression>>),
350
351 #[compatible(JsonInput)]
353 AllDiff(Metadata, Moo<Expression>),
354
355 #[compatible(SMT)]
363 SmtDistinct(Metadata, Moo<Expression>),
364
365 #[compatible(JsonInput)]
367 AllDifferentExcept(Metadata, Moo<Expression>, Moo<Expression>),
368
369 ElementId(Metadata, Moo<Expression>, Moo<Expression>),
371
372 #[compatible(JsonInput)]
377 Table(Metadata, Moo<Expression>, Moo<Expression>),
378
379 #[compatible(JsonInput)]
384 NegativeTable(Metadata, Moo<Expression>, Moo<Expression>),
385
386 #[compatible(JsonInput)]
390 AtLeast(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
391
392 #[compatible(JsonInput)]
396 AtMost(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
397
398 #[compatible(JsonInput)]
403 Gcc(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
404
405 #[compatible(Minion)]
407 GccWeak(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
408
409 #[compatible(JsonInput)]
415 Minus(Metadata, Moo<Expression>, Moo<Expression>),
416
417 #[compatible(JsonInput)]
421 Apart(Metadata, Moo<Expression>, Moo<Expression>),
422
423 #[compatible(JsonInput)]
426 Participants(Metadata, Moo<Expression>),
427
428 #[compatible(JsonInput)]
432 Party(Metadata, Moo<Expression>, Moo<Expression>),
433
434 #[compatible(JsonInput)]
437 Parts(Metadata, Moo<Expression>),
438
439 #[compatible(JsonInput)]
443 Together(Metadata, Moo<Expression>, Moo<Expression>),
444
445 #[compatible(Minion)]
453 FlatAbsEq(Metadata, Moo<Atom>, Moo<Atom>),
454
455 #[compatible(Minion)]
463 FlatAllDiff(Metadata, Vec<Atom>),
464
465 #[compatible(Minion)]
474 FlatMinEq(Metadata, Vec<Atom>, Atom),
475
476 #[compatible(Minion)]
484 FlatSumGeq(Metadata, Vec<Atom>, Atom),
485
486 #[compatible(Minion)]
494 FlatSumLeq(Metadata, Vec<Atom>, Atom),
495
496 #[compatible(Minion)]
504 FlatIneq(Metadata, Moo<Atom>, Moo<Atom>, Box<Literal>),
505
506 #[compatible(Minion)]
519 #[polyquine_skip]
520 FlatWatchedLiteral(Metadata, Reference, Literal),
521
522 FlatWeightedSumLeq(Metadata, Vec<Literal>, Vec<Atom>, Moo<Atom>),
534
535 FlatWeightedSumGeq(Metadata, Vec<Literal>, Vec<Atom>, Moo<Atom>),
547
548 #[compatible(Minion)]
556 FlatMinusEq(Metadata, Moo<Atom>, Moo<Atom>),
557
558 #[compatible(Minion)]
566 FlatProductEq(Metadata, Moo<Atom>, Moo<Atom>, Moo<Atom>),
567
568 #[compatible(Minion)]
576 MinionDivEqUndefZero(Metadata, Moo<Atom>, Moo<Atom>, Moo<Atom>),
577
578 #[compatible(Minion)]
586 MinionModuloEqUndefZero(Metadata, Moo<Atom>, Moo<Atom>, Moo<Atom>),
587
588 MinionPow(Metadata, Moo<Atom>, Moo<Atom>, Moo<Atom>),
600
601 #[compatible(Minion)]
610 MinionReify(Metadata, Moo<Expression>, Atom),
611
612 #[compatible(Minion)]
621 MinionReifyImply(Metadata, Moo<Expression>, Atom),
622
623 #[compatible(Minion)]
634 MinionWInIntervalSet(Metadata, Atom, Vec<i32>),
635
636 #[compatible(Minion)]
648 MinionWInSet(Metadata, Atom, Vec<i32>),
649
650 #[compatible(Minion)]
659 MinionElementOne(Metadata, Vec<Atom>, Moo<Atom>, Moo<Atom>),
660
661 #[compatible(Minion)]
665 #[polyquine_skip]
666 AuxDeclaration(Metadata, Reference, Moo<Expression>),
667
668 #[compatible(SAT)]
670 SATInt(Metadata, SATIntEncoding, Moo<Expression>, (i32, i32)),
671
672 #[compatible(SMT)]
675 PairwiseSum(Metadata, Moo<Expression>, Moo<Expression>),
676
677 #[compatible(SMT)]
680 PairwiseProduct(Metadata, Moo<Expression>, Moo<Expression>),
681
682 #[compatible(JsonInput)]
683 Image(Metadata, Moo<Expression>, Moo<Expression>),
684
685 #[compatible(JsonInput)]
686 ImageSet(Metadata, Moo<Expression>, Moo<Expression>),
687
688 #[compatible(JsonInput)]
689 PreImage(Metadata, Moo<Expression>, Moo<Expression>),
690
691 #[compatible(JsonInput)]
692 Inverse(Metadata, Moo<Expression>, Moo<Expression>),
693
694 #[compatible(JsonInput)]
698 PermInverse(Metadata, Moo<Expression>),
699
700 #[compatible(JsonInput)]
703 Compose(Metadata, Moo<Expression>, Moo<Expression>),
704
705 #[compatible(JsonInput)]
706 Restrict(Metadata, Moo<Expression>, Moo<Expression>),
707
708 LexLt(Metadata, Moo<Expression>, Moo<Expression>),
717
718 LexLeq(Metadata, Moo<Expression>, Moo<Expression>),
720
721 LexGt(Metadata, Moo<Expression>, Moo<Expression>),
724
725 LexGeq(Metadata, Moo<Expression>, Moo<Expression>),
728
729 FlatLexLt(Metadata, Vec<Atom>, Vec<Atom>),
731
732 FlatLexLeq(Metadata, Vec<Atom>, Vec<Atom>),
734
735 #[compatible(JsonInput)]
737 RelationProj(Metadata, Moo<Expression>, Vec<Option<Expression>>),
738
739 #[compatible(JsonInput)]
741 Card(Metadata, Moo<Expression>),
742}
743
744fn bounded_i32_domain_for_matrix_literal_monotonic(
751 e: &Expression,
752 op: fn(i32, i32) -> Option<i32>,
753) -> Option<DomainPtr> {
754 let (mut exprs, _) = e.clone().unwrap_matrix_unchecked()?;
756 let expr = exprs.pop()?;
771 let dom = expr.domain_of()?;
772 let resolved = dom.resolve().ok()?;
773 let GroundDomain::Int(ranges) = resolved.as_ref() else {
774 return None;
775 };
776
777 let (mut current_min, mut current_max) = range_vec_bounds_i32(ranges)?;
778
779 for expr in exprs {
780 let dom = expr.domain_of()?;
781 let resolved = dom.resolve().ok()?;
782 let GroundDomain::Int(ranges) = resolved.as_ref() else {
783 return None;
784 };
785
786 let (min, max) = range_vec_bounds_i32(ranges)?;
787
788 let minmax = op(min, current_max)?;
790 let minmin = op(min, current_min)?;
791 let maxmin = op(max, current_min)?;
792 let maxmax = op(max, current_max)?;
793 let vals = [minmax, minmin, maxmin, maxmax];
794
795 current_min = *vals
796 .iter()
797 .min()
798 .expect("vals iterator should not be empty, and should have a minimum.");
799 current_max = *vals
800 .iter()
801 .max()
802 .expect("vals iterator should not be empty, and should have a maximum.");
803 }
804
805 if current_min == current_max {
806 Some(Domain::int(vec![Range::Single(current_min)]))
807 } else {
808 Some(Domain::int(vec![Range::Bounded(current_min, current_max)]))
809 }
810}
811
812fn matrix_element_domain(e: &Expression) -> Option<DomainPtr> {
813 let (elem_domain, _) = e.domain_of()?.as_matrix()?;
814 elem_domain.as_ref().as_int()?;
815 Some(elem_domain)
816}
817
818fn empty_matrix_integer_element_domain(e: &Expression) -> Option<DomainPtr> {
819 match e {
820 Expression::TypeAnnotation(_, inner, domain) => {
821 if !Moo::unwrap_or_clone(inner.clone())
822 .unwrap_matrix_unchecked()
823 .is_some_and(|(elems, _)| elems.is_empty())
824 {
825 return None;
826 }
827 if let ReturnType::Matrix(elem_type) = domain.return_type()
828 && elem_type.as_ref() == &ReturnType::Int
829 {
830 Some(Domain::int_ground(vec![Range::Unbounded]))
831 } else {
832 None
833 }
834 }
835 Expression::DomainAnnotation(_, inner, domain) => {
836 if !Moo::unwrap_or_clone(inner.clone())
837 .unwrap_matrix_unchecked()
838 .is_some_and(|(elems, _)| elems.is_empty())
839 {
840 return None;
841 }
842 let (elem_domain, _) = domain.as_matrix()?;
843 elem_domain.as_ref().as_int()?;
844 Some(elem_domain)
845 }
846 _ => {
847 if !e
848 .clone()
849 .unwrap_matrix_unchecked()
850 .is_some_and(|(elems, _)| elems.is_empty())
851 {
852 return None;
853 }
854 matrix_element_domain(e)
855 }
856 }
857}
858
859fn range_vec_bounds_i32(ranges: &Vec<Range<i32>>) -> Option<(i32, i32)> {
861 let mut min = i32::MAX;
862 let mut max = i32::MIN;
863 for r in ranges {
864 match r {
865 Range::Single(i) => {
866 if *i < min {
867 min = *i;
868 }
869 if *i > max {
870 max = *i;
871 }
872 }
873 Range::Bounded(i, j) => {
874 if *i < min {
875 min = *i;
876 }
877 if *j > max {
878 max = *j;
879 }
880 }
881 Range::UnboundedR(_) | Range::UnboundedL(_) | Range::Unbounded => return None,
882 }
883 }
884 Some((min, max))
885}
886
887fn sum_domain_for_comprehension(expr: &Expression) -> Option<DomainPtr> {
889 let Expression::Comprehension(_, comp) = expr else {
890 return None;
891 };
892 let comp = comp.as_ref();
893 let resolved = comp.return_expression.domain_of()?.resolve().ok()?;
894 let GroundDomain::Int(return_ranges) = resolved.as_ref() else {
895 return None;
896 };
897 let (term_min, term_max) = range_vec_bounds_i32(return_ranges)?;
898
899 let mut term_count = 1i64;
900 for qual in &comp.qualifiers {
901 match qual {
902 ComprehensionQualifier::Generator { ptr } => {
903 let count = ptr.domain()?.resolve().ok()?.length().ok()?;
904 term_count = term_count.saturating_mul(count as i64);
905 if term_count > i32::MAX as i64 {
906 return None;
907 }
908 }
909 ComprehensionQualifier::Condition(_)
910 | ComprehensionQualifier::ExpressionGenerator { .. } => {
911 return None;
912 }
913 }
914 }
915
916 if term_count == 0 {
917 return Some(Domain::int(vec![Range::Single(0)]));
918 }
919
920 let n = term_count as i32;
921 let sum_min = n.saturating_mul(term_min);
922 let sum_max = n.saturating_mul(term_max);
923 if sum_min == sum_max {
924 Some(Domain::int(vec![Range::Single(sum_min)]))
925 } else {
926 Some(Domain::int(vec![Range::Bounded(sum_min, sum_max)]))
927 }
928}
929
930fn sum_domain_of_child(child: &Expression) -> Option<DomainPtr> {
931 sum_domain_for_comprehension(child).or_else(|| {
932 let (elements, _) = child.clone().unwrap_matrix_unchecked()?;
933 if elements.len() == 1 {
934 sum_domain_for_comprehension(&elements[0])
935 } else {
936 None
937 }
938 })
939}
940
941fn finite_mset_bounds(attrs: &MSetAttr<i32>, inner_len: i32) -> Option<((i32, i32), i32)> {
942 let min_size = attrs.size.low().copied().unwrap_or(0);
943 let max_from_size = attrs.size.high().copied();
944 let max_from_occurrence = attrs
945 .occurrence
946 .high()
947 .copied()
948 .and_then(|max| max.checked_mul(inner_len));
949 let max_size = match (max_from_size, max_from_occurrence) {
950 (Some(size), Some(occurrence)) => size.min(occurrence),
951 (Some(size), None) => size,
952 (None, Some(occurrence)) => occurrence,
953 (None, None) => return None,
954 };
955 let max_occurrence = attrs.occurrence.high().copied().unwrap_or(max_size);
956 Some(((min_size, max_size), max_occurrence))
957}
958
959fn selected_representation(expr: &Expression) -> Option<String> {
964 match expr {
965 Expression::Atomic(_, Atom::Reference(reference)) => reference
966 .repr
967 .map(|rule| rule.short_name().to_owned())
968 .or_else(|| {
969 reference
970 .domain_of()
971 .representation_preference()
972 .map(str::to_owned)
973 }),
974 Expression::TypeAnnotation(_, inner, domain)
975 | Expression::DomainAnnotation(_, inner, domain) => domain
976 .representation_preference()
977 .map(str::to_owned)
978 .or_else(|| selected_representation(inner)),
979 _ => None,
980 }
981}
982
983fn mset_union_result_domain(lhs: &Expression, rhs: &Expression) -> Option<DomainPtr> {
984 let lhs_selected = selected_representation(lhs);
985 let rhs_selected = selected_representation(rhs);
986 let lhs = lhs.domain_of()?.resolve().ok()?;
987 let rhs = rhs.domain_of()?.resolve().ok()?;
988 let GroundDomain::MSet(lhs_attrs, lhs_inner) = lhs.as_ref() else {
989 return None;
990 };
991 let GroundDomain::MSet(rhs_attrs, rhs_inner) = rhs.as_ref() else {
992 return None;
993 };
994
995 let lhs_len = i32::try_from(lhs_inner.length().ok()?).ok()?;
996 let rhs_len = i32::try_from(rhs_inner.length().ok()?).ok()?;
997 let ((lhs_min, lhs_max), lhs_max_occurrence) = finite_mset_bounds(lhs_attrs, lhs_len)?;
998 let ((rhs_min, rhs_max), rhs_max_occurrence) = finite_mset_bounds(rhs_attrs, rhs_len)?;
999
1000 let min_size = lhs_min.checked_add(rhs_min)?;
1001 let max_size = lhs_max.checked_add(rhs_max)?;
1002 let max_occurrence = lhs_max_occurrence.checked_add(rhs_max_occurrence)?;
1003 let size = Range::new(Some(min_size), Some(max_size));
1004 let occurrence = Range::new(Some(1), Some(max_occurrence));
1005 let representation = match (
1006 lhs_selected
1007 .as_deref()
1008 .or(lhs_attrs.representation.as_deref()),
1009 rhs_selected
1010 .as_deref()
1011 .or(rhs_attrs.representation.as_deref()),
1012 ) {
1013 (Some(lhs), Some(rhs)) if lhs == rhs => Some(lhs.to_owned()),
1014 (Some(preference), None) | (None, Some(preference)) => Some(preference.to_owned()),
1015 _ => None,
1016 };
1017 let inner = lhs_inner.union(rhs_inner).ok()?;
1018
1019 let mut attrs = MSetAttr::new(size, occurrence);
1020 attrs.representation = representation;
1021 Some(Domain::mset(attrs, DomainPtr::from(inner)))
1022}
1023
1024impl Expression {
1025 pub fn domain_of(&self) -> Option<DomainPtr> {
1033 self.meta_ref().domain_or_init(|| self.domain_of_uncached())
1034 }
1035
1036 pub(crate) fn domain_of_uncached(&self) -> Option<DomainPtr> {
1042 match self {
1043 Expression::Union(_, a, b) => {
1044 let lhs = a.domain_of()?;
1045 let rhs = b.domain_of()?;
1046 mset_union_result_domain(a, b).or_else(|| lhs.union(&rhs).ok())
1047 }
1048 Expression::Intersect(_, a, b) => a.domain_of()?.intersect(&b.domain_of()?).ok(),
1049 Expression::Difference(_, a, _) => a.domain_of(),
1051 Expression::In(_, _, _) => Some(Domain::bool()),
1052 Expression::Supset(_, _, _) => Some(Domain::bool()),
1053 Expression::SupsetEq(_, _, _) => Some(Domain::bool()),
1054 Expression::Subset(_, _, _) => Some(Domain::bool()),
1055 Expression::SubsetEq(_, _, _) => Some(Domain::bool()),
1056 Expression::AbstractLiteral(_, abslit) => abslit.domain_of(),
1057 Expression::DominanceRelation(_, _) => Some(Domain::bool()),
1058 Expression::FromSolution(_, expr) => Some(expr.domain_of()),
1059 Expression::Metavar(_, _) => None,
1060 Expression::Comprehension(_, comprehension) => comprehension.domain_of(),
1061 Expression::RecordField(_, rec, field_name) => {
1062 let rec_ents = rec.domain_of()?.as_record()?;
1063 for ent in rec_ents {
1064 if ent.name.eq(field_name) {
1065 return Some(ent.value);
1066 }
1067 }
1068 None
1069 }
1070 Expression::UnsafeIndex(_, matrix, index) | Expression::SafeIndex(_, matrix, index) => {
1071 let dom = matrix.domain_of()?;
1072 let resolved_dom = dom.resolve().ok().map(Domain::Ground);
1073 if dom.as_matrix().is_some()
1074 || resolved_dom
1075 .as_ref()
1076 .is_some_and(|dom| dom.as_matrix().is_some())
1077 {
1078 let mut current = dom;
1083 let mut remaining = index.len();
1084 while remaining > 0 {
1085 let resolved = current.resolve().ok().map(Domain::Ground);
1086 let Some((elem_domain, idx_domains)) = current
1087 .as_matrix()
1088 .or_else(|| resolved.as_ref()?.as_matrix())
1089 else {
1090 break;
1091 };
1092 if idx_domains.len() > remaining {
1095 return Some(Domain::matrix(
1096 elem_domain,
1097 idx_domains[remaining..].to_vec(),
1098 ));
1099 }
1100 remaining -= idx_domains.len();
1101 current = elem_domain;
1102 }
1103 return Some(current);
1104 }
1105
1106 if let Some(components) =
1110 dom.as_tuple().or_else(|| resolved_dom.as_ref()?.as_tuple())
1111 {
1112 let Expression::Atomic(_, Atom::Literal(Literal::Int(index))) =
1113 index.first()?
1114 else {
1115 return None;
1116 };
1117 let index: usize = (*index - 1).try_into().ok()?;
1118 return components.get(index).cloned();
1119 }
1120
1121 if let Some(doms) = dom.as_variant().or(dom.as_record()).or_else(|| {
1122 let resolved_dom = resolved_dom.as_ref()?;
1123 resolved_dom.as_variant().or(resolved_dom.as_record())
1124 }) {
1125 let index_expr = index.first()?;
1126 return match index_expr {
1127 Expression::Atomic(_, Atom::Reference(reference)) => {
1128 for inner_dom in doms {
1129 if *reference.name() == inner_dom.name {
1130 return Some(inner_dom.value);
1131 }
1132 }
1133 None
1134 }
1135 Expression::Atomic(_, Atom::Literal(Literal::Int(index))) => {
1136 let index: usize = (*index - 1).try_into().ok()?;
1137 doms.get(index).map(|inner_dom| inner_dom.value.clone())
1138 }
1139 _ => None,
1140 };
1141 }
1142
1143 bug!(
1144 "subject of an index operation should support indexing, but got {matrix}: {dom}"
1145 )
1146 }
1147 Expression::UnsafeSlice(_, matrix, indices)
1148 | Expression::SafeSlice(_, matrix, indices) => {
1149 let sliced_dimension = indices.iter().position(Option::is_none);
1150
1151 let dom = matrix.domain_of()?;
1152 let Some((elem_domain, index_domains)) = dom.as_matrix() else {
1153 bug!("subject of an index operation should be a matrix");
1154 };
1155
1156 match sliced_dimension {
1157 Some(dimension) => Some(Domain::matrix(
1158 elem_domain,
1159 vec![index_domains[dimension].clone()],
1160 )),
1161
1162 None => Some(elem_domain),
1164 }
1165 }
1166 Expression::InDomain(_, _, _) => Some(Domain::bool()),
1167 Expression::Atomic(_, atom) => Some(atom.domain_of()),
1168 Expression::TypeAnnotation(_, expr, _) => expr.domain_of(),
1169 Expression::DomainAnnotation(_, _, domain) => Some(domain.clone()),
1170 Expression::Sum(_, e) => sum_domain_of_child(e).or_else(|| {
1171 bounded_i32_domain_for_matrix_literal_monotonic(e, i32::checked_add)
1173 }),
1174 Expression::Product(_, e) => {
1175 bounded_i32_domain_for_matrix_literal_monotonic(e, i32::checked_mul)
1178 }
1179 Expression::Min(_, e) => {
1180 if empty_matrix_integer_element_domain(e).is_some() {
1181 return Some(Domain::empty(ReturnType::Int));
1182 }
1183 bounded_i32_domain_for_matrix_literal_monotonic(e, |x, y| {
1184 Some(if x < y { x } else { y })
1185 })
1186 .or_else(|| matrix_element_domain(e))
1187 }
1188 Expression::Max(_, e) => {
1189 if empty_matrix_integer_element_domain(e).is_some() {
1190 return Some(Domain::empty(ReturnType::Int));
1191 }
1192 bounded_i32_domain_for_matrix_literal_monotonic(e, |x, y| {
1193 Some(if x > y { x } else { y })
1194 })
1195 .or_else(|| matrix_element_domain(e))
1196 }
1197 Expression::UnsafeDiv(_, a, b) => a
1198 .domain_of()?
1199 .resolve()
1200 .ok()?
1201 .apply_i32(
1202 |x, y| {
1205 if y != 0 {
1206 Some((x as f32 / y as f32).floor() as i32)
1207 } else {
1208 None
1209 }
1210 },
1211 b.domain_of()?.resolve().ok()?.as_ref(),
1212 )
1213 .map(DomainPtr::from)
1214 .ok(),
1215 Expression::CatchUndef(_, a, b) => {
1217 let inner = a.domain_of()?;
1218 let default = b.domain_of()?;
1219 inner.union(&default).ok()
1220 }
1221 Expression::SafeDiv(_, a, b) => {
1222 let domain = a
1225 .domain_of()?
1226 .resolve()
1227 .ok()?
1228 .apply_i32(
1229 |x, y| {
1230 if y != 0 {
1231 Some((x as f32 / y as f32).floor() as i32)
1232 } else {
1233 None
1234 }
1235 },
1236 b.domain_of()?.resolve().ok()?.as_ref(),
1237 )
1238 .unwrap_or_else(|err| bug!("Got {err} when computing domain of {self}"));
1239
1240 if let GroundDomain::Int(ranges) = domain {
1241 let mut ranges = ranges;
1242 ranges.push(Range::Single(0));
1243 Some(Domain::int(ranges))
1244 } else if matches!(domain, GroundDomain::Empty(ReturnType::Int)) {
1245 Some(Domain::int(vec![Range::Single(0)]))
1246 } else {
1247 bug!("Domain of {self} was not integer")
1248 }
1249 }
1250 Expression::UnsafeMod(_, a, b) => a
1251 .domain_of()?
1252 .resolve()
1253 .ok()?
1254 .apply_i32(
1255 |x, y| if y != 0 { Some(x % y) } else { None },
1256 b.domain_of()?.resolve().ok()?.as_ref(),
1257 )
1258 .map(DomainPtr::from)
1259 .ok(),
1260 Expression::SafeMod(_, a, b) => {
1261 let domain = a
1262 .domain_of()?
1263 .resolve()
1264 .ok()?
1265 .apply_i32(
1266 |x, y| if y != 0 { Some(x % y) } else { None },
1267 b.domain_of()?.resolve().ok()?.as_ref(),
1268 )
1269 .unwrap_or_else(|err| bug!("Got {err} when computing domain of {self}"));
1270
1271 if let GroundDomain::Int(ranges) = domain {
1272 let mut ranges = ranges;
1273 ranges.push(Range::Single(0));
1274 Some(Domain::int(ranges))
1275 } else if matches!(domain, GroundDomain::Empty(ReturnType::Int)) {
1276 Some(Domain::int(vec![Range::Single(0)]))
1277 } else {
1278 bug!("Domain of {self} was not integer")
1279 }
1280 }
1281 Expression::SafePow(_, a, b) | Expression::UnsafePow(_, a, b) => a
1282 .domain_of()?
1283 .resolve()
1284 .ok()?
1285 .apply_i32(
1286 |x, y| {
1287 if (x != 0 || y != 0) && y >= 0 {
1288 Some(x.pow(y as u32))
1289 } else {
1290 None
1291 }
1292 },
1293 b.domain_of()?.resolve().ok()?.as_ref(),
1294 )
1295 .map(DomainPtr::from)
1296 .ok(),
1297 Expression::Root(_, _) => None,
1298 Expression::Bubble(_, inner, _) => inner.domain_of(),
1299 Expression::AuxDeclaration(_, _, _) => Some(Domain::bool()),
1300 Expression::And(_, _) => Some(Domain::bool()),
1301 Expression::Not(_, _) => Some(Domain::bool()),
1302 Expression::Or(_, _) => Some(Domain::bool()),
1303 Expression::Imply(_, _, _) => Some(Domain::bool()),
1304 Expression::Iff(_, _, _) => Some(Domain::bool()),
1305 Expression::Eq(_, _, _) => Some(Domain::bool()),
1306 Expression::Neq(_, _, _) => Some(Domain::bool()),
1307 Expression::Geq(_, _, _) => Some(Domain::bool()),
1308 Expression::Leq(_, _, _) => Some(Domain::bool()),
1309 Expression::Gt(_, _, _) => Some(Domain::bool()),
1310 Expression::Lt(_, _, _) => Some(Domain::bool()),
1311 Expression::Factorial(_, a) => {
1312 let dom = a.domain_of()?.resolve().ok()?;
1313 let GroundDomain::Int(_) = dom.as_ref() else {
1314 return None;
1315 };
1316 let values = dom.values_i32().ok()?;
1317 let values = values
1318 .into_iter()
1319 .map(factorial_i32)
1320 .collect::<Option<BTreeSet<_>>>()?;
1321
1322 Some(DomainPtr::from(GroundDomain::from_set_i32(&values)))
1323 }
1324 Expression::FlatAbsEq(_, _, _) => Some(Domain::bool()),
1325 Expression::FlatMinEq(_, _, _) => Some(Domain::bool()),
1326 Expression::FlatSumGeq(_, _, _) => Some(Domain::bool()),
1327 Expression::FlatSumLeq(_, _, _) => Some(Domain::bool()),
1328 Expression::MinionDivEqUndefZero(_, _, _, _) => Some(Domain::bool()),
1329 Expression::MinionModuloEqUndefZero(_, _, _, _) => Some(Domain::bool()),
1330 Expression::FlatIneq(_, _, _, _) => Some(Domain::bool()),
1331 Expression::Flatten(_, n, m) => {
1332 if let Some(expr) = n {
1333 if expr.return_type() == ReturnType::Int {
1334 return None;
1336 }
1337 } else {
1338 let dom = m.domain_of()?.resolve().ok()?;
1340 let (val_dom, idx_doms) = match dom.as_ref() {
1341 GroundDomain::Matrix(val, idx) => (val, idx),
1342 _ => return None,
1343 };
1344 let num_elems = matrix::num_elements(idx_doms).ok()? as i32;
1345
1346 let new_index_domain = Domain::int(vec![Range::Bounded(1, num_elems)]);
1347 return Some(Domain::matrix(
1348 val_dom.clone().into(),
1349 vec![new_index_domain],
1350 ));
1351 }
1352 None
1353 }
1354 Expression::AllDiff(_, _) => Some(Domain::bool()),
1355 Expression::SmtDistinct(_, _) => Some(Domain::bool()),
1356 Expression::AllDifferentExcept(_, _, _) => Some(Domain::bool()),
1357 Expression::ElementId(_, matrix, value) => {
1358 let dom = matrix.domain_of()?.resolve().ok()?;
1359 let idx_doms = match dom.as_ref() {
1360 GroundDomain::Matrix(_, idx) => idx,
1361 _ => return None,
1362 };
1363 if let [idx_dom] = idx_doms.as_slice() {
1364 let index_domain = Domain::Ground(idx_dom.clone());
1365 if let Some(n) = matrix.list_len() {
1366 if n > 0 {
1367 return Some(Domain::int(vec![Range::Bounded(1, n as i32)]));
1368 }
1369 Some(Moo::new(index_domain))
1370 } else {
1371 let matrix_is_literal = matches!(
1372 matrix.as_ref(),
1373 Expression::Atomic(_, Atom::Literal(_))
1374 | Expression::AbstractLiteral(_, _)
1375 );
1376 if !matrix_is_literal || eval_constant(value.as_ref()).is_none() {
1377 value
1378 .domain_of()
1379 .and_then(|value_domain| index_domain.union(&value_domain).ok())
1380 .map(Moo::new)
1381 .or_else(|| Some(Moo::new(index_domain)))
1382 } else {
1383 Some(Moo::new(index_domain))
1384 }
1385 }
1386 } else {
1387 let num_elems = matrix::num_elements(idx_doms).ok()? as i32;
1388 Some(Domain::int(vec![Range::Bounded(1, num_elems)]))
1389 }
1390 }
1391 Expression::Table(_, _, _) => Some(Domain::bool()),
1392 Expression::NegativeTable(_, _, _) => Some(Domain::bool()),
1393 Expression::AtLeast(_, _, _, _) => Some(Domain::bool()),
1394 Expression::AtMost(_, _, _, _) => Some(Domain::bool()),
1395 Expression::Gcc(_, _, _, _) | Expression::GccWeak(_, _, _, _) => Some(Domain::bool()),
1396 Expression::FlatWatchedLiteral(_, _, _) => Some(Domain::bool()),
1397 Expression::MinionReify(_, _, _) => Some(Domain::bool()),
1398 Expression::MinionReifyImply(_, _, _) => Some(Domain::bool()),
1399 Expression::MinionWInIntervalSet(_, _, _) => Some(Domain::bool()),
1400 Expression::MinionWInSet(_, _, _) => Some(Domain::bool()),
1401 Expression::MinionElementOne(_, _, _, _) => Some(Domain::bool()),
1402 Expression::Neg(_, x) => {
1403 let dom = x.domain_of()?;
1404 let mut ranges = dom.as_int()?;
1405
1406 ranges = ranges
1407 .into_iter()
1408 .map(|r| match r {
1409 Range::Single(x) => Range::Single(-x),
1410 Range::Bounded(x, y) => Range::Bounded(-y, -x),
1411 Range::UnboundedR(i) => Range::UnboundedL(-i),
1412 Range::UnboundedL(i) => Range::UnboundedR(-i),
1413 Range::Unbounded => Range::Unbounded,
1414 })
1415 .collect();
1416
1417 Some(Domain::int(ranges))
1418 }
1419 Expression::Minus(_, a, b) => {
1420 let a_resolved = a.domain_of()?.resolve().ok()?;
1421 let b_resolved = b.domain_of()?.resolve().ok()?;
1422
1423 if matches!(a_resolved.as_ref(), GroundDomain::Int(_))
1424 && matches!(b_resolved.as_ref(), GroundDomain::Int(_))
1425 {
1426 a_resolved
1427 .apply_i32(|x, y| Some(x - y), b_resolved.as_ref())
1428 .map(DomainPtr::from)
1429 .ok()
1430 } else if matches!(a_resolved.as_ref(), GroundDomain::Set(_, _))
1431 && matches!(b_resolved.as_ref(), GroundDomain::Set(_, _))
1432 {
1433 Some(DomainPtr::from(a_resolved))
1434 } else {
1435 None
1436 }
1437 }
1438 Expression::FlatAllDiff(_, _) => Some(Domain::bool()),
1439 Expression::FlatMinusEq(_, _, _) => Some(Domain::bool()),
1440 Expression::FlatProductEq(_, _, _, _) => Some(Domain::bool()),
1441 Expression::FlatWeightedSumLeq(_, _, _, _) => Some(Domain::bool()),
1442 Expression::FlatWeightedSumGeq(_, _, _, _) => Some(Domain::bool()),
1443 Expression::Abs(_, a) => a
1444 .domain_of()?
1445 .resolve()
1446 .ok()?
1447 .apply_i32(
1448 |a, _| Some(a.abs()),
1449 a.domain_of()?.resolve().ok()?.as_ref(),
1450 )
1451 .map(DomainPtr::from)
1452 .ok(),
1453 Expression::MinionPow(_, _, _, _) => Some(Domain::bool()),
1454 Expression::ToInt(_, _) => Some(Domain::int(vec![Range::Bounded(0, 1)])),
1455 Expression::SATInt(_, _, _, (low, high)) => {
1456 Some(Domain::int_ground(vec![Range::Bounded(*low, *high)]))
1457 }
1458 Expression::PairwiseSum(_, a, b) => a
1459 .domain_of()?
1460 .resolve()
1461 .ok()?
1462 .apply_i32(|a, b| Some(a + b), b.domain_of()?.resolve().ok()?.as_ref())
1463 .map(DomainPtr::from)
1464 .ok(),
1465 Expression::PairwiseProduct(_, a, b) => a
1466 .domain_of()?
1467 .resolve()
1468 .ok()?
1469 .apply_i32(|a, b| Some(a * b), b.domain_of()?.resolve().ok()?.as_ref())
1470 .map(DomainPtr::from)
1471 .ok(),
1472 Expression::Defined(_, function) => {
1473 let (attrs, domain, codomain) = function.domain_of()?.as_function()?;
1474 let size = Self::function_elements_size(attrs, &domain, &codomain);
1475 if let Some(size) = size {
1476 Some(Domain::set(SetAttr::new(size), domain))
1477 } else {
1478 Some(Domain::empty(ReturnType::Set(Box::new(
1479 domain.return_type(),
1480 ))))
1481 }
1482 }
1483 Expression::Range(_, function) => {
1484 let (attrs, domain, codomain) = function.domain_of()?.as_function()?;
1485 let jectivity = attrs.resolve().ok()?.jectivity;
1486
1487 let size_size = attrs.resolve().ok()?.size;
1488 let size_size = match size_size {
1489 Range::Unbounded => Range::UnboundedR(0),
1490 Range::Single(x) => match jectivity {
1492 JectivityAttr::Injective | JectivityAttr::Surjective => Range::Single(x),
1493 _ => Range::Bounded(Ord::min(1, x), x),
1494 },
1495 Range::UnboundedL(x) => Range::Bounded(0, x),
1497 Range::UnboundedR(x) => match jectivity {
1499 JectivityAttr::Injective | JectivityAttr::Surjective => {
1500 Range::UnboundedR(x)
1501 }
1502 _ => Range::UnboundedR(Ord::min(1, x)),
1503 },
1504 Range::Bounded(x, y) => Range::Bounded(Ord::min(1, x), y),
1505 };
1506
1507 let partiality = attrs.resolve().ok()?.partiality;
1509 let codomain_length = codomain.length_signed();
1510 let attr_size = match jectivity {
1511 JectivityAttr::Bijective | JectivityAttr::Surjective => match codomain_length {
1513 Ok(co_len) => Some(Range::Single(co_len)),
1514 Err(_) => None,
1515 },
1516 JectivityAttr::Injective => {
1517 let domain_length = domain.length_signed();
1518 match domain_length {
1519 Ok(len) => match codomain_length {
1520 Ok(co_len) => match partiality {
1521 PartialityAttr::Total => {
1523 Some(Range::Single(Ord::min(len, co_len)))
1524 }
1525 PartialityAttr::Partial => {
1526 Some(Range::Bounded(0, Ord::min(len, co_len)))
1527 }
1528 },
1529 Err(_) => None,
1530 },
1531 Err(_) => None,
1532 }
1533 }
1534 JectivityAttr::None => {
1535 let domain_length = domain.length_signed();
1536 match domain_length {
1537 Ok(len) => Some(Range::Bounded(0, len)),
1539 Err(_) => None,
1540 }
1541 }
1542 };
1543
1544 let size = match attr_size {
1545 Some(attr_size) => {
1546 let unsafe_range = Range::minimal(&[size_size, attr_size]);
1547 match unsafe_range {
1548 Ok(range) => range,
1549 Err(_) => {
1550 return Some(Domain::empty(ReturnType::Set(Box::new(
1551 domain.return_type(),
1552 ))));
1553 }
1554 }
1555 }
1556 None => size_size,
1557 };
1558 Some(Domain::set(SetAttr::new(size), codomain))
1559 }
1560 Expression::Image(_, function, _) => get_function_codomain(function),
1561 Expression::PermInverse(_, perm) => perm.domain_of(),
1562 Expression::Compose(_, g, _h) => g.domain_of(),
1563 Expression::ImageSet(_, function, _) => {
1564 let codomain = get_function_codomain(function);
1565 codomain.map(|inner_dom| Domain::set(SetAttr::new(Range::Bounded(0, 1)), inner_dom))
1567 }
1568 Expression::PreImage(_, function, _) => {
1569 let (attrs, domain, codomain) = function.domain_of()?.as_function()?;
1570
1571 let size_size = attrs.resolve().ok()?.size;
1572 let size_size = match size_size {
1573 Range::Unbounded => Range::UnboundedR(0),
1575 Range::Single(x) => Range::Bounded(0, x),
1576 Range::UnboundedL(x) => Range::Bounded(0, x),
1577 Range::UnboundedR(_) => Range::UnboundedR(0),
1578 Range::Bounded(_, y) => Range::Bounded(0, y),
1579 };
1580
1581 let jectivity = attrs.resolve().ok()?.jectivity;
1582 let codomain_length = codomain.length_signed();
1583 let attr_size = match jectivity {
1584 JectivityAttr::Bijective => Some(Range::Single(1)),
1586 JectivityAttr::Injective => match size_size {
1587 Range::Single(x) | Range::UnboundedL(x) | Range::Bounded(x, _) => {
1588 match codomain_length {
1589 Ok(co_len) => {
1590 if x >= co_len {
1591 Some(Range::Single(1))
1592 } else {
1593 Some(Range::Bounded(0, 1))
1594 }
1595 }
1596 Err(_) => Some(Range::Bounded(0, 1)),
1597 }
1598 }
1599 _ => Some(Range::Bounded(0, 1)),
1600 },
1601 JectivityAttr::Surjective => {
1602 let domain_length = domain.length_signed();
1603 match domain_length {
1604 Ok(len) => match codomain_length {
1605 Ok(co_len) => match size_size {
1608 Range::Bounded(_, x)
1609 | Range::UnboundedL(x)
1610 | Range::Single(x) => Some(Range::Bounded(
1611 1,
1612 Ord::max(Ord::min(len, x) - co_len + 1, 0),
1613 )),
1614 _ => Some(Range::Bounded(1, Ord::max(len - co_len + 1, 0))),
1615 },
1616 Err(_) => Some(Range::UnboundedR(1)),
1617 },
1618 Err(_) => Some(Range::UnboundedR(1)),
1619 }
1620 }
1621 JectivityAttr::None => {
1622 let domain_length = domain.length_signed();
1623 match domain_length {
1624 Ok(len) => Some(Range::Bounded(0, len)),
1625 Err(_) => Some(Range::UnboundedR(0)),
1626 }
1627 }
1628 };
1629
1630 let size = match attr_size {
1631 Some(attr_size) => {
1632 let unsafe_range = Range::minimal(&[size_size, attr_size]);
1633 match unsafe_range {
1634 Ok(range) => range,
1635 Err(_) => {
1636 return Some(Domain::empty(ReturnType::Set(Box::new(
1637 domain.return_type(),
1638 ))));
1639 }
1640 }
1641 }
1642 None => size_size,
1643 };
1644 Some(Domain::set(SetAttr::new(size), domain))
1645 }
1646 Expression::Restrict(_, function, new_domain) => {
1647 let mut domain = function.domain_of()?;
1648 let (attrs_mut, dom, codom_mut) = domain.as_function_mut()?;
1649
1650 let attrs: &FuncAttr<IntVal> = attrs_mut;
1652 let codom: &Moo<Domain> = codom_mut;
1653
1654 let mut new_dom = new_domain.domain_of()?;
1656 if let Some(new_rng) = new_dom.as_int_ground_mut()
1658 && let Some(old_rng) = dom.as_int_ground_mut()
1659 {
1660 new_rng.append(old_rng);
1661 if let Ok(rng) = Range::minimal(new_rng) {
1662 let ranges = vec![rng];
1663 new_dom = Domain::int(ranges);
1664 }
1665 }
1666 let attr_size = attrs.resolve().ok()?.size;
1667 let new_size = match new_dom.length_signed() {
1668 Ok(len) => match Range::minimal(&[attr_size, Range::Bounded(0, len)]) {
1670 Ok(size) => size,
1671 Err(_) => {
1672 return Some(Domain::empty(ReturnType::Function(
1674 Box::new(new_dom.return_type()),
1675 Box::new(codom.return_type()),
1676 )));
1677 }
1678 },
1679 Err(_) => attr_size,
1680 };
1681 let jectivity = attrs.jectivity.clone();
1682 let partiality = attrs.partiality.clone();
1683 let new_attrs = FuncAttr {
1684 size: new_size,
1685 jectivity,
1686 partiality,
1687 };
1688 Some(Domain::function(new_attrs, new_dom, codom.clone()))
1689 }
1690 Expression::Subsequence(_, _, _) => Some(Domain::bool()),
1691 Expression::Substring(_, _, _) => Some(Domain::bool()),
1692 Expression::AttributeAsConstraint(_, _, _, _) => Some(Domain::bool()),
1693 Expression::Inverse(..) => Some(Domain::bool()),
1694 Expression::LexLt(..) => Some(Domain::bool()),
1695 Expression::LexLeq(..) => Some(Domain::bool()),
1696 Expression::LexGt(..) => Some(Domain::bool()),
1697 Expression::LexGeq(..) => Some(Domain::bool()),
1698 Expression::FlatLexLt(..) => Some(Domain::bool()),
1699 Expression::FlatLexLeq(..) => Some(Domain::bool()),
1700 Expression::Active(..) => Some(Domain::bool()),
1701 Expression::ToSet(_, other) => {
1702 if let Some((attrs, dom, codom)) = other.domain_of()?.as_function() {
1703 let set_attrs = SetAttr::new(attrs.size);
1704 Some(Domain::set(set_attrs, Domain::tuple(vec![dom, codom])))
1705 } else if let Some((attrs, doms)) = other.domain_of()?.as_relation() {
1706 let set_attrs = SetAttr::new(attrs.size);
1707 Some(Domain::set(set_attrs, Domain::tuple(doms)))
1708 } else if let Some((attrs, dom)) = other.domain_of()?.as_mset() {
1709 let set_attrs = SetAttr::new(attrs.size);
1710 Some(Domain::set(set_attrs, dom))
1711 } else if let Some((dom, dimensions)) = other.domain_of()?.as_matrix() {
1712 let mut doms = vec![];
1714 for _ in dimensions {
1715 doms.push(dom.clone());
1716 }
1717 let doms_sizes: Result<Vec<i32>, _> =
1718 doms.iter().map(|x| x.length_signed()).collect();
1719 let attr = match doms_sizes {
1720 Ok(vals) => {
1721 if let Some(&size) = vals.iter().min() {
1722 SetAttr::new(Range::Single(size))
1723 } else {
1724 SetAttr::<i32>::default()
1725 }
1726 }
1727 Err(_) => SetAttr::<i32>::default(),
1729 };
1730 Some(Domain::set(attr, Domain::tuple(doms)))
1731 } else {
1732 bug!(
1733 "Domain of {self} needed to be a function, relation, mset, or matrix for ToSet"
1734 )
1735 }
1736 }
1737 Expression::ToMSet(_, other) => {
1738 if let Some((attrs, dom, codom)) = other.domain_of()?.as_function() {
1739 let set_attrs = MSetAttr {
1740 size: attrs.size,
1741 occurrence: Range::Single(IntVal::Const(1)),
1742 representation: None,
1743 };
1744 Some(Domain::mset(set_attrs, Domain::tuple(vec![dom, codom])))
1745 } else if let Some((attrs, doms)) = other.domain_of()?.as_relation() {
1746 let set_attrs = MSetAttr {
1747 size: attrs.size,
1748 occurrence: Range::Single(IntVal::Const(1)),
1749 representation: None,
1750 };
1751 Some(Domain::mset(set_attrs, Domain::tuple(doms)))
1752 } else if let Some((attrs, dom)) = other.domain_of()?.as_set() {
1753 let set_attrs = MSetAttr {
1754 size: attrs.size,
1755 occurrence: Range::Single(IntVal::Const(1)),
1756 representation: None,
1757 };
1758 Some(Domain::mset(set_attrs, dom))
1759 } else {
1760 bug!("Domain of {self} needed to be a function, relation, or set for ToMSet")
1761 }
1762 }
1763 Expression::ToRelation(_, function) => {
1764 let (attrs, domain, codomain) = function.domain_of()?.as_function()?;
1765 let rel_attrs = RelAttr {
1767 size: attrs.size,
1768 binary: vec![],
1769 };
1770 Some(Domain::relation(rel_attrs, vec![domain, codomain]))
1771 }
1772 Expression::RelationProj(_, relation, projections) => {
1773 let (_, domains) = relation.domain_of()?.as_relation()?;
1774 let new_doms = domains
1775 .iter()
1776 .zip(projections.iter())
1777 .filter_map(|(domain, included)| {
1778 if included.is_none() {
1779 Some(domain.clone())
1781 } else {
1782 None
1783 }
1784 })
1785 .collect();
1786 Some(Domain::relation(RelAttr::<IntVal>::default(), new_doms))
1787 }
1788 Expression::Apart(_, _, _) => Some(Domain::bool()),
1789 Expression::Together(_, _, _) => Some(Domain::bool()),
1790 Expression::Participants(_, p) => {
1791 let (attr, inner) = p.domain_of()?.as_partition()?;
1793 let len = inner.length_signed().ok()?;
1794
1795 let p_parts = attr.resolve().ok()?.num_parts;
1796 let p_card = attr.resolve().ok()?.part_len;
1797
1798 match (p_parts.low(), p_parts.high(), p_card.low(), p_card.high()) {
1800 (Some(p), Some(q), Some(r), Some(s)) => {
1801 let lo = p * r;
1802 let hi = q * s;
1803 if len < lo || len > hi {
1804 return Some(Domain::empty(ReturnType::Set(Box::new(
1805 inner.return_type(),
1806 ))));
1807 }
1808 }
1809
1810 (None, Some(q), None, Some(s)) => {
1811 let hi = q * s;
1812 if len > hi {
1813 return Some(Domain::empty(ReturnType::Set(Box::new(
1814 inner.return_type(),
1815 ))));
1816 }
1817 }
1818
1819 (Some(p), None, Some(r), None) => {
1820 let lo = p * r;
1821 if len < lo {
1822 return Some(Domain::empty(ReturnType::Set(Box::new(
1823 inner.return_type(),
1824 ))));
1825 }
1826 }
1827
1828 _ => {}
1829 }
1830
1831 Some(Domain::set(
1832 SetAttr::new_size(len),
1833 Domain::int(inner.as_int()?),
1834 ))
1835 }
1836 Expression::Party(_, _, p) => {
1837 let (attr, inner) = p.domain_of()?.as_partition()?;
1839
1840 Some(Domain::set(SetAttr::new(attr.part_len), inner))
1841 }
1842 Expression::Parts(_, p) => {
1843 let (attr, inner) = p.domain_of()?.as_partition()?;
1844
1845 Some(Domain::set(
1846 SetAttr::new(attr.num_parts.clone()),
1847 Domain::set(SetAttr::new(attr.part_len), inner),
1848 ))
1849 }
1850 Expression::Card(_, collection) => {
1851 let domain = collection.domain_of()?;
1852 if let Some((_, dimensions)) = domain.as_matrix() {
1853 let doms_ground: Result<Vec<i32>, _> =
1854 dimensions.iter().map(|x| x.length_signed()).collect();
1855 if let Ok(doms_ground) = doms_ground {
1856 let size: Range<i32> = Range::Single(doms_ground.iter().product());
1857 Some(Domain::int(vec![size]))
1858 } else {
1859 Some(Domain::int(vec![Range::<i32>::Unbounded]))
1860 }
1861 } else if let Some((attr, dom)) = domain.as_set() {
1862 let attr_size = attr.resolve().ok()?.size;
1863 if let Ok(length) = dom.length_signed() {
1864 let unsafe_range = Range::minimal(&[attr_size, Range::Bounded(0, length)]);
1865 return match unsafe_range {
1866 Ok(range) => Some(Domain::int(vec![range])),
1867 Err(_) => None,
1868 };
1869 }
1870 Some(Domain::int(vec![attr_size]))
1872 } else if let Some((attrs, dom)) = domain.as_mset() {
1873 let attrs_gd = attrs.resolve().ok()?;
1874 let attr_occ = match attrs_gd.occurrence {
1876 Range::Single(x) => Some(x),
1877 Range::Unbounded | Range::UnboundedR(_) => None,
1878 Range::Bounded(_, x) => Some(x),
1879 Range::UnboundedL(x) => Some(x),
1880 };
1881 if let Some(occ) = attr_occ {
1882 if let Ok(length) = dom.length_signed() {
1883 let unsafe_range =
1884 Range::minimal(&[attrs_gd.size, Range::Bounded(0, length * occ)]);
1885 match unsafe_range {
1886 Ok(range) => Some(Domain::int(vec![range])),
1887 Err(_) => None,
1888 }
1889 } else {
1890 Some(Domain::int(vec![attrs_gd.size]))
1892 }
1893 } else {
1894 Some(Domain::int(vec![attrs_gd.size]))
1896 }
1897 } else if let Some((attrs, doms)) = domain.as_relation() {
1898 let attrs_gd = attrs.resolve().ok()?;
1901 let doms_sizes: Result<Vec<i32>, _> =
1903 doms.iter().map(|x| x.length_signed()).collect();
1904 if let Ok(doms_sizes) = doms_sizes {
1905 let length = Range::Bounded(0, doms_sizes.iter().product());
1906 let unsafe_range = Range::minimal(&[attrs_gd.size, length]);
1908 return match unsafe_range {
1909 Ok(range) => Some(Domain::int(vec![range])),
1910 Err(_) => None,
1911 };
1912 }
1913 Some(Domain::int(vec![attrs_gd.size]))
1915 } else if let Some((attrs, dom, codom)) = domain.as_function() {
1916 let size = Self::function_elements_size(attrs, &dom, &codom);
1917 size.map(|size| Domain::int(vec![size]))
1918 } else if let Some((attrs, _dom)) = domain.as_sequence() {
1919 let attrs_gd = attrs.resolve().ok()?;
1923 Some(Domain::int(vec![attrs_gd.size]))
1924 } else if let Some((_attrs, inner)) = domain.as_partition() {
1925 match inner.length_signed() {
1930 Ok(length) => Some(Domain::int(vec![Range::Single(length)])),
1931 Err(_) => None,
1932 }
1933 } else {
1934 bug!(
1935 "Domain of {self} needed to be a matrix, set, mset, sequence, relation, function, or partition for cardinality"
1936 )
1937 }
1938 }
1939 }
1940 }
1941
1942 fn function_elements_size(
1944 attrs: FuncAttr<IntVal>,
1945 domain: &DomainPtr,
1946 codomain: &DomainPtr,
1947 ) -> Option<Range> {
1948 let attrs_gd = attrs.resolve().ok()?;
1949 let domain_length = domain.length_signed();
1950 let attr_size = match domain_length {
1952 Ok(len) => match attrs_gd.partiality {
1953 PartialityAttr::Total => Some(Range::Single(len)),
1954 PartialityAttr::Partial => {
1955 let codomain_length = codomain.length_signed();
1957 match codomain_length {
1958 Ok(co_len) => match attrs_gd.jectivity {
1959 JectivityAttr::Bijective => Some(Range::Single(co_len)),
1960 JectivityAttr::Surjective => Some(Range::Bounded(co_len, len)),
1961 JectivityAttr::Injective => {
1962 Some(Range::Bounded(0, Ord::min(len, co_len)))
1963 }
1964 JectivityAttr::None => Some(Range::Bounded(0, len)),
1965 },
1966 Err(_) => None,
1967 }
1968 }
1969 },
1970 Err(_) => None,
1971 };
1972 match attr_size {
1978 Some(attr_size) => {
1979 let unsafe_range = Range::minimal(&[attrs_gd.size, attr_size]);
1980 unsafe_range.ok()
1981 }
1982 None => Some(attrs_gd.size),
1983 }
1984 }
1985
1986 pub fn meta_ref(&self) -> &Metadata {
1988 macro_rules! match_meta_ref {
1989 ($($variant:ident),* $(,)?) => {
1990 match self {
1991 $(Expression::$variant(meta, ..) => meta,)*
1992 }
1993 };
1994 }
1995 match_meta_ref!(
1996 AbstractLiteral,
1997 Root,
1998 Bubble,
1999 Comprehension,
2000 DominanceRelation,
2001 TypeAnnotation,
2002 DomainAnnotation,
2003 FromSolution,
2004 Metavar,
2005 Atomic,
2006 RecordField,
2007 UnsafeIndex,
2008 SafeIndex,
2009 UnsafeSlice,
2010 SafeSlice,
2011 InDomain,
2012 ToInt,
2013 Abs,
2014 Sum,
2015 Product,
2016 Min,
2017 Max,
2018 Not,
2019 Or,
2020 And,
2021 Imply,
2022 Iff,
2023 Union,
2024 Difference,
2025 In,
2026 Intersect,
2027 Supset,
2028 SupsetEq,
2029 Subset,
2030 SubsetEq,
2031 Eq,
2032 Neq,
2033 Geq,
2034 Leq,
2035 Gt,
2036 Lt,
2037 CatchUndef,
2038 SafeDiv,
2039 UnsafeDiv,
2040 SafeMod,
2041 UnsafeMod,
2042 Apart,
2043 Together,
2044 Participants,
2045 Party,
2046 Parts,
2047 Neg,
2048 Defined,
2049 Range,
2050 UnsafePow,
2051 SafePow,
2052 Flatten,
2053 AttributeAsConstraint,
2054 AllDiff,
2055 SmtDistinct,
2056 AllDifferentExcept,
2057 ElementId,
2058 Minus,
2059 Factorial,
2060 FlatAbsEq,
2061 FlatAllDiff,
2062 FlatMinEq,
2063 FlatSumGeq,
2064 FlatSumLeq,
2065 FlatIneq,
2066 FlatWatchedLiteral,
2067 FlatWeightedSumLeq,
2068 FlatWeightedSumGeq,
2069 FlatMinusEq,
2070 FlatProductEq,
2071 MinionDivEqUndefZero,
2072 MinionModuloEqUndefZero,
2073 MinionPow,
2074 MinionReify,
2075 MinionReifyImply,
2076 MinionWInIntervalSet,
2077 MinionWInSet,
2078 MinionElementOne,
2079 AuxDeclaration,
2080 SATInt,
2081 PairwiseSum,
2082 PairwiseProduct,
2083 Image,
2084 ImageSet,
2085 PreImage,
2086 Inverse,
2087 PermInverse,
2088 Compose,
2089 Restrict,
2090 LexLt,
2091 LexLeq,
2092 LexGt,
2093 LexGeq,
2094 FlatLexLt,
2095 FlatLexLeq,
2096 NegativeTable,
2097 Table,
2098 AtLeast,
2099 AtMost,
2100 Gcc,
2101 GccWeak,
2102 Active,
2103 ToSet,
2104 ToMSet,
2105 ToRelation,
2106 RelationProj,
2107 Card,
2108 Subsequence,
2109 Substring,
2110 )
2111 }
2112
2113 pub fn get_meta(&self) -> Metadata {
2114 let metas: VecDeque<Metadata> = self.children_bi();
2115 metas[0].clone()
2116 }
2117
2118 pub fn set_meta(&self, meta: Metadata) {
2119 self.transform_bi(&|_| meta.clone());
2120 }
2121
2122 pub fn is_safe(&self) -> bool {
2129 !self.any_expression(|expr| {
2131 matches!(
2132 expr,
2133 Expression::UnsafeDiv(_, _, _)
2134 | Expression::UnsafeMod(_, _, _)
2135 | Expression::UnsafePow(_, _, _)
2136 | Expression::UnsafeIndex(_, _, _)
2137 | Expression::Bubble(_, _, _)
2138 | Expression::UnsafeSlice(_, _, _)
2139 ) || matches!(expr, Expression::Image(_, subject, argument)
2140 if image_can_be_undefined(subject, argument))
2141 })
2142 }
2143
2144 pub fn is_associative_commutative_operator(&self) -> bool {
2146 TryInto::<ACOperatorKind>::try_into(self).is_ok()
2147 }
2148
2149 pub fn is_matrix_literal(&self) -> bool {
2154 matches!(
2155 self,
2156 Expression::AbstractLiteral(_, AbstractLiteral::Matrix(_, _))
2157 | Expression::Atomic(
2158 _,
2159 Atom::Literal(Literal::AbstractLiteral(AbstractLiteral::Matrix(_, _))),
2160 )
2161 )
2162 }
2163
2164 pub fn identical_atom_to(&self, other: &Expression) -> bool {
2170 let atom1: Result<&Atom, _> = self.try_into();
2171 let atom2: Result<&Atom, _> = other.try_into();
2172
2173 if let (Ok(atom1), Ok(atom2)) = (atom1, atom2) {
2174 atom2 == atom1
2175 } else {
2176 false
2177 }
2178 }
2179
2180 pub fn unwrap_list_ref(&self) -> Option<&[Expression]> {
2188 match self {
2189 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
2190 expr.unwrap_list_ref()
2191 }
2192 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => {
2193 matrix.unwrap_list().map(Vec::as_slice)
2194 }
2195 _ => None,
2196 }
2197 }
2198
2199 pub fn unwrap_list_cow(&self) -> Option<Cow<'_, [Expression]>> {
2210 match self {
2211 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
2212 expr.unwrap_list_cow()
2213 }
2214 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => matrix
2215 .unwrap_list()
2216 .map(|elems| Cow::Borrowed(elems.as_slice())),
2217 Expression::Atomic(
2218 _,
2219 Atom::Literal(Literal::AbstractLiteral(matrix @ AbstractLiteral::Matrix(_, _))),
2220 ) => matrix.unwrap_list().map(|elems| {
2221 Cow::Owned(
2222 elems
2223 .iter()
2224 .cloned()
2225 .map(|literal| Expression::Atomic(Metadata::new(), Atom::Literal(literal)))
2226 .collect(),
2227 )
2228 }),
2229 _ => None,
2230 }
2231 }
2232
2233 pub fn list_len(&self) -> Option<usize> {
2238 match self {
2239 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
2240 expr.list_len()
2241 }
2242 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => {
2243 matrix.unwrap_list().map(Vec::len)
2244 }
2245 Expression::Atomic(
2246 _,
2247 Atom::Literal(Literal::AbstractLiteral(matrix @ AbstractLiteral::Matrix(_, _))),
2248 ) => matrix.unwrap_list().map(Vec::len),
2249 _ => None,
2250 }
2251 }
2252
2253 pub fn is_list(&self) -> bool {
2255 self.list_len().is_some()
2256 }
2257
2258 pub fn unwrap_list(&self) -> Option<Vec<Expression>> {
2268 match self {
2269 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
2270 expr.unwrap_list()
2271 }
2272 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => {
2273 matrix.unwrap_list().cloned()
2274 }
2275 Expression::Atomic(
2276 _,
2277 Atom::Literal(Literal::AbstractLiteral(matrix @ AbstractLiteral::Matrix(_, _))),
2278 ) => matrix.unwrap_list().map(|elems| {
2279 elems
2280 .clone()
2281 .into_iter()
2282 .map(|x: Literal| Expression::Atomic(Metadata::new(), Atom::Literal(x)))
2283 .collect_vec()
2284 }),
2285 _ => None,
2286 }
2287 }
2288
2289 pub fn into_list(self) -> Option<Vec<Expression>> {
2294 match self {
2295 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
2296 Moo::unwrap_or_clone(expr).into_list()
2297 }
2298 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => {
2299 matrix.into_list()
2300 }
2301 Expression::Atomic(
2302 _,
2303 Atom::Literal(Literal::AbstractLiteral(matrix @ AbstractLiteral::Matrix(_, _))),
2304 ) => matrix.into_list().map(|elems| {
2305 elems
2306 .into_iter()
2307 .map(|literal| Expression::Atomic(Metadata::new(), Atom::Literal(literal)))
2308 .collect()
2309 }),
2310 _ => None,
2311 }
2312 }
2313
2314 pub fn unwrap_matrix_unchecked_ref(&self) -> Option<(&[Expression], &DomainPtr)> {
2320 match self {
2321 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
2322 expr.unwrap_matrix_unchecked_ref()
2323 }
2324 Expression::AbstractLiteral(_, AbstractLiteral::Matrix(elems, domain)) => {
2325 Some((elems, domain))
2326 }
2327 _ => None,
2328 }
2329 }
2330
2331 pub fn unwrap_matrix_unchecked(self) -> Option<(Vec<Expression>, DomainPtr)> {
2339 match self {
2340 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
2341 Moo::unwrap_or_clone(expr).unwrap_matrix_unchecked()
2342 }
2343 Expression::AbstractLiteral(_, AbstractLiteral::Matrix(elems, domain)) => {
2344 Some((elems, domain))
2345 }
2346 Expression::Atomic(
2347 _,
2348 Atom::Literal(Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, domain))),
2349 ) => Some((
2350 elems
2351 .into_iter()
2352 .map(|x: Literal| Expression::Atomic(Metadata::new(), Atom::Literal(x)))
2353 .collect_vec(),
2354 domain.into(),
2355 )),
2356
2357 _ => None,
2358 }
2359 }
2360
2361 pub fn extend_root(self, exprs: Vec<Expression>) -> Expression {
2366 match self {
2367 Expression::Root(meta, mut children) => {
2368 children.extend(exprs);
2369 Expression::Root(meta, children)
2370 }
2371 _ => panic!("extend_root called on a non-Root expression"),
2372 }
2373 }
2374
2375 pub fn into_literal(self) -> Option<Literal> {
2377 match self {
2378 Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
2379 Expression::AbstractLiteral(_, abslit) => {
2380 Some(Literal::AbstractLiteral(abslit.into_literals()?))
2381 }
2382 Expression::Neg(_, e) => {
2383 let Literal::Int(i) = Moo::unwrap_or_clone(e).into_literal()? else {
2384 bug!("negated literal should be an int");
2385 };
2386
2387 Some(Literal::Int(-i))
2388 }
2389
2390 _ => None,
2391 }
2392 }
2393
2394 pub fn to_ac_operator_kind(&self) -> Option<ACOperatorKind> {
2396 TryFrom::try_from(self).ok()
2397 }
2398
2399 pub fn try_return_type(&self) -> Option<ReturnType> {
2405 let has_untyped_reference = self.any_expression(|expr| {
2406 matches!(expr, Expression::Atomic(_, Atom::Reference(reference))
2407 if reference.domain().is_none() && reference.resolve_constant().is_none())
2408 });
2409
2410 (!has_untyped_reference).then(|| self.return_type())
2411 }
2412
2413 pub fn universe_categories(&self) -> HashSet<Category> {
2415 let mut categories = HashSet::new();
2416 self.for_each_expression(&mut |expr| {
2417 categories.insert(expr.category_of());
2418 });
2419 categories
2420 }
2421}
2422
2423pub fn image_can_be_undefined(subject: &Expression, argument: &Expression) -> bool {
2435 let Some(domain) = subject.domain_of().and_then(|domain| domain.resolve().ok()) else {
2436 return true;
2437 };
2438
2439 match domain.as_ref() {
2440 GroundDomain::Function(attr, from, _) => {
2441 !matches!(attr.partiality, PartialityAttr::Total) || !argument_always_in(argument, from)
2442 }
2443 GroundDomain::Permutation(_, inner) => !argument_always_in(argument, inner),
2445 GroundDomain::Sequence(attr, _) => {
2446 let min_length = attr.size.low().copied().unwrap_or(0);
2449 min_length <= 0
2450 || !argument_always_in(
2451 argument,
2452 &GroundDomain::Int(vec![Range::Bounded(1, min_length)]),
2453 )
2454 }
2455 _ => true,
2456 }
2457}
2458
2459fn argument_always_in(argument: &Expression, domain: &GroundDomain) -> bool {
2465 let Some(argument_domain) = argument.domain_of().and_then(|d| d.resolve().ok()) else {
2466 return false;
2467 };
2468
2469 argument_domain
2470 .intersect(domain)
2471 .is_ok_and(|intersection| intersection == *argument_domain.as_ref())
2472}
2473
2474pub fn get_function_codomain(function: &Moo<Expression>) -> Option<DomainPtr> {
2478 let function_domain = function.domain_of()?;
2479 match function_domain.resolve().as_ref() {
2480 Ok(d) => {
2481 match d.as_ref() {
2482 GroundDomain::Function(_, _, codomain) => Some(codomain.clone().into()),
2483 GroundDomain::Permutation(_, inner) => Some(inner.clone().into()),
2484 GroundDomain::Sequence(_, inner) => Some(inner.clone().into()),
2485 _ => None,
2487 }
2488 }
2489 Err(_) => {
2490 match function_domain.as_unresolved()? {
2491 UnresolvedDomain::Function(_, _, codomain) => Some(codomain.clone()),
2492 UnresolvedDomain::Permutation(_, inner) => Some(inner.clone()),
2493 UnresolvedDomain::Sequence(_, inner) => Some(inner.clone()),
2494 _ => None,
2496 }
2497 }
2498 }
2499}
2500
2501impl TryFrom<&Expression> for i32 {
2502 type Error = ();
2503
2504 fn try_from(value: &Expression) -> Result<Self, Self::Error> {
2505 let Expression::Atomic(_, atom) = value else {
2506 return Err(());
2507 };
2508
2509 let Atom::Literal(lit) = atom else {
2510 return Err(());
2511 };
2512
2513 let Literal::Int(i) = lit else {
2514 return Err(());
2515 };
2516
2517 Ok(*i)
2518 }
2519}
2520
2521impl TryFrom<Expression> for i32 {
2522 type Error = ();
2523
2524 fn try_from(value: Expression) -> Result<Self, Self::Error> {
2525 TryFrom::<&Expression>::try_from(&value)
2526 }
2527}
2528impl From<i32> for Expression {
2529 fn from(i: i32) -> Self {
2530 Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(i)))
2531 }
2532}
2533
2534impl From<bool> for Expression {
2535 fn from(b: bool) -> Self {
2536 Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(b)))
2537 }
2538}
2539
2540impl From<Atom> for Expression {
2541 fn from(value: Atom) -> Self {
2542 Expression::Atomic(Metadata::new(), value)
2543 }
2544}
2545
2546impl From<Literal> for Expression {
2547 fn from(value: Literal) -> Self {
2548 Expression::Atomic(Metadata::new(), value.into())
2549 }
2550}
2551
2552impl From<AbstractLiteral<Expression>> for Expression {
2553 fn from(value: AbstractLiteral<Expression>) -> Self {
2554 Expression::AbstractLiteral(Metadata::new(), value)
2555 }
2556}
2557
2558impl From<Moo<Expression>> for Expression {
2559 fn from(val: Moo<Expression>) -> Self {
2560 val.as_ref().clone()
2561 }
2562}
2563
2564impl CategoryOf for Expression {
2565 fn category_of(&self) -> Category {
2566 let category = self.cata(&move |x,children| {
2568
2569 if let Some(max_category) = children.iter().max() {
2570 *max_category
2573 } else {
2574 let mut max_category = Category::Bottom;
2576
2577 if !Biplate::<Model>::universe_bi(&x).is_empty() {
2584 return Category::Decision;
2586 }
2587
2588 if let Some(max_atom_category) = Biplate::<Atom>::universe_bi(&x).iter().map(|x| x.category_of()).max()
2590 && max_atom_category > max_category{
2592 max_category = max_atom_category;
2594 }
2595
2596 if let Some(max_declaration_category) = Biplate::<DeclarationPtr>::universe_bi(&x).iter().map(|x| x.category_of()).max()
2598 && max_declaration_category > max_category{
2600 max_category = max_declaration_category;
2602 }
2603 max_category
2604
2605 }
2606 });
2607
2608 if cfg!(debug_assertions) {
2609 trace!(
2610 category= %category,
2611 expression= %self,
2612 "Called Expression::category_of()"
2613 );
2614 };
2615 category
2616 }
2617}
2618
2619impl Display for Expression {
2620 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2621 match &self {
2622 Expression::Union(_, box1, box2) => {
2623 write!(f, "({} union {})", box1.clone(), box2.clone())
2624 }
2625 Expression::Difference(_, box1, box2) => {
2626 write!(f, "({} - {})", box1.clone(), box2.clone())
2627 }
2628 Expression::In(_, e1, e2) => {
2629 write!(f, "{e1} in {e2}")
2630 }
2631 Expression::Intersect(_, box1, box2) => {
2632 write!(f, "({} intersect {})", box1.clone(), box2.clone())
2633 }
2634 Expression::Supset(_, box1, box2) => {
2635 write!(f, "({} supset {})", box1.clone(), box2.clone())
2636 }
2637 Expression::SupsetEq(_, box1, box2) => {
2638 write!(f, "({} supsetEq {})", box1.clone(), box2.clone())
2639 }
2640 Expression::Subset(_, box1, box2) => {
2641 write!(f, "({} subset {})", box1.clone(), box2.clone())
2642 }
2643 Expression::SubsetEq(_, box1, box2) => {
2644 write!(f, "({} subsetEq {})", box1.clone(), box2.clone())
2645 }
2646
2647 Expression::AbstractLiteral(_, l) => l.fmt(f),
2648 Expression::Comprehension(_, c) => c.fmt(f),
2649 Expression::UnsafeIndex(_, e1, e2) => write!(f, "{e1}{}", pretty_vec(e2)),
2650 Expression::RecordField(_, r, fld) => {
2651 write!(f, "{r}[{fld}]")
2652 }
2653 Expression::SafeIndex(_, e1, e2) => write!(f, "SafeIndex({e1},{})", pretty_vec(e2)),
2654 Expression::UnsafeSlice(_, e1, es) => {
2655 let args = es
2656 .iter()
2657 .map(|x| match x {
2658 Some(x) => format!("{x}"),
2659 None => "..".into(),
2660 })
2661 .join(",");
2662
2663 write!(f, "{e1}[{args}]")
2664 }
2665 Expression::SafeSlice(_, e1, es) => {
2666 let args = es
2667 .iter()
2668 .map(|x| match x {
2669 Some(x) => format!("{x}"),
2670 None => "..".into(),
2671 })
2672 .join(",");
2673
2674 write!(f, "SafeSlice({e1},[{args}])")
2675 }
2676 Expression::InDomain(_, e, domain) => {
2677 write!(f, "__inDomain({e},{domain})")
2678 }
2679 Expression::Root(_, exprs) => {
2680 write!(f, "{}", pretty_expressions_as_top_level(exprs))
2681 }
2682 Expression::DominanceRelation(_, expr) => write!(f, "DominanceRelation({expr})"),
2683 Expression::FromSolution(_, expr) => write!(f, "FromSolution({expr})"),
2684 Expression::Metavar(_, name) => write!(f, "&{name}"),
2685 Expression::Atomic(_, atom) => atom.fmt(f),
2686 Expression::TypeAnnotation(_, expr, domain) => {
2687 write!(
2688 f,
2689 "{}",
2690 pretty_expression_type_annotation(expr, domain.as_type_string())
2691 )
2692 }
2693 Expression::DomainAnnotation(_, expr, domain) => {
2694 write!(f, "{}", pretty_expression_domain_annotation(expr, domain))
2695 }
2696 Expression::Abs(_, a) | Expression::Card(_, a) => write!(f, "|{a}|"),
2697 Expression::Sum(_, e) => {
2698 write!(f, "sum({e})")
2699 }
2700 Expression::Product(_, e) => {
2701 write!(f, "product({e})")
2702 }
2703 Expression::Min(_, e) => {
2704 write!(f, "min({e})")
2705 }
2706 Expression::Max(_, e) => {
2707 write!(f, "max({e})")
2708 }
2709 Expression::Not(_, expr_box) => {
2710 write!(f, "!({})", expr_box.clone())
2711 }
2712 Expression::Or(_, e) => {
2713 write!(f, "or({e})")
2714 }
2715 Expression::And(_, e) => {
2716 write!(f, "and({e})")
2717 }
2718 Expression::Imply(_, box1, box2) => {
2719 write!(f, "({box1}) -> ({box2})")
2720 }
2721 Expression::Iff(_, box1, box2) => {
2722 write!(f, "({box1}) <-> ({box2})")
2723 }
2724 Expression::Eq(_, box1, box2) => {
2725 write!(f, "{box1} = {box2}")
2726 }
2727 Expression::Neq(_, box1, box2) => {
2728 write!(f, "{box1} != {box2}")
2729 }
2730 Expression::Geq(_, box1, box2) => {
2731 write!(f, "{box1} >= {box2}")
2732 }
2733 Expression::Leq(_, box1, box2) => {
2734 write!(f, "{box1} <= {box2}")
2735 }
2736 Expression::Gt(_, box1, box2) => {
2737 write!(f, "{box1} > {box2}")
2738 }
2739 Expression::Lt(_, box1, box2) => {
2740 write!(f, "{box1} < {box2}")
2741 }
2742 Expression::Apart(_, list, partition) => {
2743 write!(f, "apart({list}, {partition})")
2744 }
2745 Expression::Together(_, list, partition) => {
2746 write!(f, "together({list}, {partition})")
2747 }
2748 Expression::Participants(_, partition) => {
2749 write!(f, "participants({partition})")
2750 }
2751 Expression::Party(_, element, partition) => {
2752 write!(f, "party({element}, {partition})")
2753 }
2754 Expression::Parts(_, partition) => {
2755 write!(f, "parts({partition})")
2756 }
2757 Expression::FlatMinEq(_, vars, result) => {
2758 write!(f, "FlatMinEq({}, {})", pretty_vec(vars), result.clone())
2759 }
2760 Expression::FlatSumGeq(_, box1, box2) => {
2761 write!(f, "SumGeq({}, {})", pretty_vec(box1), box2.clone())
2762 }
2763 Expression::FlatSumLeq(_, box1, box2) => {
2764 write!(f, "SumLeq({}, {})", pretty_vec(box1), box2.clone())
2765 }
2766 Expression::FlatIneq(_, box1, box2, box3) => write!(
2767 f,
2768 "Ineq({}, {}, {})",
2769 box1.clone(),
2770 box2.clone(),
2771 box3.clone()
2772 ),
2773 Expression::Flatten(_, n, m) => {
2774 if let Some(n) = n {
2775 write!(f, "flatten({n}, {m})")
2776 } else {
2777 write!(f, "flatten({m})")
2778 }
2779 }
2780 Expression::AttributeAsConstraint(_, target, attr, val) => {
2781 if let Some(val) = val {
2782 write!(f, "{attr}({target}, {val})")
2783 } else {
2784 write!(f, "{attr}({target})")
2785 }
2786 }
2787 Expression::AllDiff(_, e) => {
2788 write!(f, "allDifferent({e})")
2789 }
2790 Expression::SmtDistinct(_, e) => {
2791 write!(f, "smtDistinct({e})")
2792 }
2793 Expression::AllDifferentExcept(_, matrix, except) => {
2794 write!(f, "allDifferentExcept({matrix}, {except})")
2795 }
2796 Expression::ElementId(_, matrix, value) => {
2797 write!(f, "elementId({matrix}, {value})")
2798 }
2799 Expression::Table(_, tuple_expr, rows_expr) => {
2800 write!(f, "table({tuple_expr}, {rows_expr})")
2801 }
2802 Expression::NegativeTable(_, tuple_expr, rows_expr) => {
2803 write!(f, "negativeTable({tuple_expr}, {rows_expr})")
2804 }
2805 Expression::AtLeast(_, vars, counts, values) => {
2806 write!(f, "atLeast({vars}, {counts}, {values})")
2807 }
2808 Expression::AtMost(_, vars, counts, values) => {
2809 write!(f, "atMost({vars}, {counts}, {values})")
2810 }
2811 Expression::Gcc(_, vars, values, counts) => {
2812 write!(f, "globalCardinality({vars}, {values}, {counts})")
2813 }
2814 Expression::GccWeak(_, vars, values, counts) => {
2815 write!(f, "gccweak({vars}, {values}, {counts})")
2816 }
2817 Expression::Bubble(_, box1, box2) => {
2818 write!(f, "{{{} @ {}}}", box1.clone(), box2.clone())
2819 }
2820 Expression::CatchUndef(_, box1, box2) => {
2821 write!(f, "catchUndef({box1}, {box2})")
2822 }
2823 Expression::SafeDiv(_, box1, box2) => {
2824 write!(f, "SafeDiv({}, {})", box1.clone(), box2.clone())
2825 }
2826 Expression::UnsafeDiv(_, box1, box2) => {
2827 write!(f, "({} / {})", box1.clone(), box2.clone())
2828 }
2829 Expression::UnsafePow(_, box1, box2) => {
2830 write!(f, "({} ** {})", box1.clone(), box2.clone())
2831 }
2832 Expression::SafePow(_, box1, box2) => {
2833 write!(f, "SafePow({}, {})", box1.clone(), box2.clone())
2834 }
2835 Expression::Subsequence(_, s, t) => {
2836 write!(f, "{} subsequence {}", s.clone(), t.clone())
2837 }
2838 Expression::Substring(_, s, t) => {
2839 write!(f, "{} substring {}", s.clone(), t.clone())
2840 }
2841 Expression::MinionDivEqUndefZero(_, box1, box2, box3) => {
2842 write!(
2843 f,
2844 "DivEq({}, {}, {})",
2845 box1.clone(),
2846 box2.clone(),
2847 box3.clone()
2848 )
2849 }
2850 Expression::MinionModuloEqUndefZero(_, box1, box2, box3) => {
2851 write!(
2852 f,
2853 "ModEq({}, {}, {})",
2854 box1.clone(),
2855 box2.clone(),
2856 box3.clone()
2857 )
2858 }
2859 Expression::FlatWatchedLiteral(_, x, l) => {
2860 write!(f, "WatchedLiteral({x},{l})")
2861 }
2862 Expression::MinionReify(_, box1, box2) => {
2863 write!(f, "Reify({}, {})", box1.clone(), box2.clone())
2864 }
2865 Expression::MinionReifyImply(_, box1, box2) => {
2866 write!(f, "ReifyImply({}, {})", box1.clone(), box2.clone())
2867 }
2868 Expression::MinionWInIntervalSet(_, atom, intervals) => {
2869 let intervals = intervals.iter().join(",");
2870 write!(f, "__minion_w_inintervalset({atom},[{intervals}])")
2871 }
2872 Expression::MinionWInSet(_, atom, values) => {
2873 let values = values.iter().join(",");
2874 write!(f, "__minion_w_inset({atom},[{values}])")
2875 }
2876 Expression::AuxDeclaration(_, reference, e) => {
2877 write!(f, "{} =aux {}", reference, e.clone())
2878 }
2879 Expression::UnsafeMod(_, a, b) => {
2880 write!(f, "{} % {}", a.clone(), b.clone())
2881 }
2882 Expression::SafeMod(_, a, b) => {
2883 write!(f, "SafeMod({},{})", a.clone(), b.clone())
2884 }
2885 Expression::Neg(_, a) => {
2886 write!(f, "-({})", a.clone())
2887 }
2888 Expression::Factorial(_, a) => {
2889 write!(f, "({})!", a.clone())
2890 }
2891 Expression::Minus(_, a, b) => {
2892 write!(f, "({} - {})", a.clone(), b.clone())
2893 }
2894 Expression::FlatAllDiff(_, es) => {
2895 write!(f, "__flat_alldiff({})", pretty_vec(es))
2896 }
2897 Expression::FlatAbsEq(_, a, b) => {
2898 write!(f, "AbsEq({},{})", a.clone(), b.clone())
2899 }
2900 Expression::FlatMinusEq(_, a, b) => {
2901 write!(f, "MinusEq({},{})", a.clone(), b.clone())
2902 }
2903 Expression::FlatProductEq(_, a, b, c) => {
2904 write!(
2905 f,
2906 "FlatProductEq({},{},{})",
2907 a.clone(),
2908 b.clone(),
2909 c.clone()
2910 )
2911 }
2912 Expression::FlatWeightedSumLeq(_, cs, vs, total) => {
2913 write!(
2914 f,
2915 "FlatWeightedSumLeq({},{},{})",
2916 pretty_vec(cs),
2917 pretty_vec(vs),
2918 total.clone()
2919 )
2920 }
2921 Expression::FlatWeightedSumGeq(_, cs, vs, total) => {
2922 write!(
2923 f,
2924 "FlatWeightedSumGeq({},{},{})",
2925 pretty_vec(cs),
2926 pretty_vec(vs),
2927 total.clone()
2928 )
2929 }
2930 Expression::MinionPow(_, atom, atom1, atom2) => {
2931 write!(f, "MinionPow({atom},{atom1},{atom2})")
2932 }
2933 Expression::MinionElementOne(_, atoms, atom, atom1) => {
2934 let atoms = atoms.iter().join(",");
2935 write!(f, "__minion_element_one([{atoms}],{atom},{atom1})")
2936 }
2937
2938 Expression::ToInt(_, expr) => {
2939 write!(f, "toInt({expr})")
2940 }
2941
2942 Expression::SATInt(_, encoding, bits, (min, max)) => {
2943 write!(f, "SATInt({encoding:?}, {bits} [{min}, {max}])")
2944 }
2945
2946 Expression::PairwiseSum(_, a, b) => write!(f, "PairwiseSum({a}, {b})"),
2947 Expression::PairwiseProduct(_, a, b) => write!(f, "PairwiseProduct({a}, {b})"),
2948
2949 Expression::Defined(_, function) => write!(f, "defined({function})"),
2950 Expression::Range(_, function) => write!(f, "range({function})"),
2951 Expression::Image(_, function, elems) => write!(f, "image({function},{elems})"),
2952 Expression::ImageSet(_, function, elems) => write!(f, "imageSet({function},{elems})"),
2953 Expression::PreImage(_, function, elems) => write!(f, "preImage({function},{elems})"),
2954 Expression::Inverse(_, a, b) => write!(f, "inverse({a},{b})"),
2955 Expression::PermInverse(_, p) => write!(f, "permInverse({p})"),
2956 Expression::Compose(_, g, h) => write!(f, "compose({g},{h})"),
2957 Expression::Restrict(_, function, domain) => write!(f, "restrict({function},{domain})"),
2958
2959 Expression::LexLt(_, a, b) => write!(f, "({a} <lex {b})"),
2960 Expression::LexLeq(_, a, b) => write!(f, "({a} <=lex {b})"),
2961 Expression::LexGt(_, a, b) => write!(f, "({a} >lex {b})"),
2962 Expression::LexGeq(_, a, b) => write!(f, "({a} >=lex {b})"),
2963 Expression::FlatLexLt(_, a, b) => {
2964 write!(f, "FlatLexLt({}, {})", pretty_vec(a), pretty_vec(b))
2965 }
2966 Expression::FlatLexLeq(_, a, b) => {
2967 write!(f, "FlatLexLeq({}, {})", pretty_vec(a), pretty_vec(b))
2968 }
2969 Expression::Active(_, variant, field_name) => {
2970 write!(f, "active({variant}, {field_name})")
2971 }
2972 Expression::ToSet(_, other) => write!(f, "toSet({other})"),
2973 Expression::ToMSet(_, other) => write!(f, "toMSet({other})"),
2974 Expression::ToRelation(_, function) => write!(f, "toRelation({function})"),
2975 Expression::RelationProj(_, relation, projections) => {
2976 let projections_str = projections
2977 .iter()
2978 .map(|x| {
2979 if let Some(x) = x {
2980 x.to_string()
2981 } else {
2982 String::from("_")
2983 }
2984 })
2985 .join(", ");
2986 write!(f, "{relation}({projections_str})")
2987 }
2988 }
2989 }
2990}
2991
2992fn minus_operand_return_type(expr: &Expression) -> ReturnType {
2993 match expr {
2994 Expression::Atomic(_, Atom::Reference(reference)) => {
2995 let decl_kind = reference.ptr.kind().clone();
2996 match decl_kind {
2997 DeclarationKind::Find(var) | DeclarationKind::FindAuxiliary(var) => {
2998 var.return_type()
2999 }
3000 DeclarationKind::Given(domain)
3001 | DeclarationKind::DomainLetting(domain) => domain.return_type(),
3002 DeclarationKind::Quantified(inner) => inner.domain().return_type(),
3003 DeclarationKind::QuantifiedExpr(inner)
3004 | DeclarationKind::TemporaryValueLetting(inner)
3005 | DeclarationKind::ValueLetting(inner, _) => inner.return_type(),
3007 }
3008 }
3009 _ => expr.return_type(),
3010 }
3011}
3012
3013impl Typeable for Expression {
3014 fn return_type(&self) -> ReturnType {
3015 match self {
3016 Expression::Union(_, subject, _)
3017 | Expression::Intersect(_, subject, _)
3018 | Expression::Difference(_, subject, _) => subject.return_type(),
3019 Expression::In(_, _, _) => ReturnType::Bool,
3020 Expression::Supset(_, _, _) => ReturnType::Bool,
3021 Expression::SupsetEq(_, _, _) => ReturnType::Bool,
3022 Expression::Subset(_, _, _) => ReturnType::Bool,
3023 Expression::SubsetEq(_, _, _) => ReturnType::Bool,
3024 Expression::AbstractLiteral(_, lit) => lit.return_type(),
3025 Expression::RecordField(_, rec, field_name) => {
3026 if let ReturnType::Record(ents) = rec.return_type() {
3027 for Field { name, value } in ents {
3028 if name.eq(field_name) {
3029 return value;
3030 }
3031 }
3032 }
3033 ReturnType::Unknown
3034 }
3035 Expression::UnsafeIndex(_, subject, idx) | Expression::SafeIndex(_, subject, idx) => {
3036 let mut indexed_ty = subject.return_type();
3037 for index in idx {
3038 indexed_ty = match indexed_ty {
3039 ReturnType::Tuple(field_types) => {
3040 let Expression::Atomic(_, Atom::Literal(Literal::Int(index))) = index
3041 else {
3042 return ReturnType::Unknown;
3043 };
3044 let Some(zero_based_index) = index
3045 .checked_sub(1)
3046 .and_then(|index| usize::try_from(index).ok())
3047 else {
3048 return ReturnType::Unknown;
3049 };
3050 field_types
3051 .get(zero_based_index)
3052 .cloned()
3053 .unwrap_or(ReturnType::Unknown)
3054 }
3055 ReturnType::Matrix(element_type) => {
3059 let element_type = *element_type;
3060 if !matches!(element_type, ReturnType::Matrix(_)) {
3061 return element_type;
3062 }
3063 element_type
3064 }
3065 ReturnType::Record(_) | ReturnType::Variant(_) | ReturnType::Unknown => {
3068 return ReturnType::Unknown;
3069 }
3070 subject_ty => bug!(
3071 "Invalid indexing operation: expected the operand to be a collection, got {self}: {subject_ty}"
3072 ),
3073 };
3074 }
3075 indexed_ty
3076 }
3077 Expression::UnsafeSlice(_, subject, _) | Expression::SafeSlice(_, subject, _) => {
3078 let mut element_type = subject.return_type();
3079 while let ReturnType::Matrix(inner) = element_type {
3080 element_type = *inner;
3081 }
3082 ReturnType::Matrix(Box::new(element_type))
3083 }
3084 Expression::InDomain(_, _, _) => ReturnType::Bool,
3085 Expression::Comprehension(_, comp) => comp.return_type(),
3086 Expression::Root(_, _) => ReturnType::Bool,
3087 Expression::DominanceRelation(_, _) => ReturnType::Bool,
3088 Expression::FromSolution(_, expr) => expr.return_type(),
3089 Expression::Metavar(_, _) => ReturnType::Unknown,
3090 Expression::Atomic(_, atom) => atom.return_type(),
3091 Expression::TypeAnnotation(_, _, domain) => domain.return_type(),
3092 Expression::DomainAnnotation(_, _, domain) => domain.return_type(),
3093 Expression::Abs(_, _) => ReturnType::Int,
3094 Expression::Sum(_, _) => ReturnType::Int,
3095 Expression::Product(_, _) => ReturnType::Int,
3096 Expression::Min(_, _) => ReturnType::Int,
3097 Expression::Max(_, _) => ReturnType::Int,
3098 Expression::Not(_, _) => ReturnType::Bool,
3099 Expression::Or(_, _) => ReturnType::Bool,
3100 Expression::Imply(_, _, _) => ReturnType::Bool,
3101 Expression::Iff(_, _, _) => ReturnType::Bool,
3102 Expression::And(_, _) => ReturnType::Bool,
3103 Expression::Eq(_, _, _) => ReturnType::Bool,
3104 Expression::Neq(_, _, _) => ReturnType::Bool,
3105 Expression::Geq(_, _, _) => ReturnType::Bool,
3106 Expression::Leq(_, _, _) => ReturnType::Bool,
3107 Expression::Gt(_, _, _) => ReturnType::Bool,
3108 Expression::Lt(_, _, _) => ReturnType::Bool,
3109 Expression::Apart(_, _, _) => ReturnType::Bool,
3110 Expression::Together(_, _, _) => ReturnType::Bool,
3111 Expression::Party(_, _, subject) => ReturnType::Set(Box::new(subject.return_type())),
3112 Expression::Participants(_, subject) => {
3113 ReturnType::Set(Box::new(subject.return_type()))
3114 }
3115 Expression::Parts(_, subject) => {
3116 ReturnType::Set(Box::new(ReturnType::Set(Box::new(subject.return_type()))))
3117 }
3118 Expression::CatchUndef(_, _, _) => ReturnType::Int,
3119 Expression::SafeDiv(_, _, _) => ReturnType::Int,
3120 Expression::UnsafeDiv(_, _, _) => ReturnType::Int,
3121 Expression::FlatAllDiff(_, _) => ReturnType::Bool,
3122 Expression::FlatMinEq(_, _, _) => ReturnType::Bool,
3123 Expression::FlatSumGeq(_, _, _) => ReturnType::Bool,
3124 Expression::FlatSumLeq(_, _, _) => ReturnType::Bool,
3125 Expression::MinionDivEqUndefZero(_, _, _, _) => ReturnType::Bool,
3126 Expression::FlatIneq(_, _, _, _) => ReturnType::Bool,
3127 Expression::Flatten(_, _, matrix) => {
3128 let matrix_type = matrix.return_type();
3129 match matrix_type {
3130 ReturnType::Matrix(_) => {
3131 let mut elem_type = matrix_type;
3133 while let ReturnType::Matrix(new_elem_type) = &elem_type {
3134 elem_type = *new_elem_type.clone();
3135 }
3136 ReturnType::Matrix(Box::new(elem_type))
3137 }
3138 _ => bug!(
3139 "Invalid indexing operation: expected the operand to be a collection, got {self}: {matrix_type}"
3140 ),
3141 }
3142 }
3143 Expression::AllDiff(_, _) => ReturnType::Bool,
3144 Expression::SmtDistinct(_, _) => ReturnType::Bool,
3145 Expression::AllDifferentExcept(_, _, _) => ReturnType::Bool,
3146 Expression::ElementId(_, _, _) => ReturnType::Int,
3147 Expression::Table(_, _, _) => ReturnType::Bool,
3148 Expression::NegativeTable(_, _, _) => ReturnType::Bool,
3149 Expression::AtLeast(_, _, _, _) => ReturnType::Bool,
3150 Expression::AtMost(_, _, _, _) => ReturnType::Bool,
3151 Expression::Gcc(_, _, _, _) | Expression::GccWeak(_, _, _, _) => ReturnType::Bool,
3152 Expression::Bubble(_, inner, _) => inner.return_type(),
3153 Expression::FlatWatchedLiteral(_, _, _) => ReturnType::Bool,
3154 Expression::MinionReify(_, _, _) => ReturnType::Bool,
3155 Expression::MinionReifyImply(_, _, _) => ReturnType::Bool,
3156 Expression::MinionWInIntervalSet(_, _, _) => ReturnType::Bool,
3157 Expression::MinionWInSet(_, _, _) => ReturnType::Bool,
3158 Expression::MinionElementOne(_, _, _, _) => ReturnType::Bool,
3159 Expression::AuxDeclaration(_, _, _) => ReturnType::Bool,
3160 Expression::UnsafeMod(_, _, _) => ReturnType::Int,
3161 Expression::SafeMod(_, _, _) => ReturnType::Int,
3162 Expression::MinionModuloEqUndefZero(_, _, _, _) => ReturnType::Bool,
3163 Expression::Neg(_, _) => ReturnType::Int,
3164 Expression::Factorial(_, _) => ReturnType::Int,
3165 Expression::UnsafePow(_, _, _) => ReturnType::Int,
3166 Expression::SafePow(_, _, _) => ReturnType::Int,
3167 Expression::Minus(_, a, b) => {
3168 let a_type = minus_operand_return_type(a);
3171 let b_type = minus_operand_return_type(b);
3172
3173 if a_type == ReturnType::Int && b_type == ReturnType::Int {
3174 ReturnType::Int
3175 } else if let ReturnType::Set(a_inner) = a_type
3176 && let ReturnType::Set(b_inner) = b_type
3177 && a_inner == b_inner
3178 {
3179 ReturnType::Set(a_inner)
3180 } else {
3181 bug!(
3182 "Invalid minus operation: operands are of different or invalid types for this operation"
3183 )
3184 }
3185 }
3186 Expression::FlatAbsEq(_, _, _) => ReturnType::Bool,
3187 Expression::FlatMinusEq(_, _, _) => ReturnType::Bool,
3188 Expression::FlatProductEq(_, _, _, _) => ReturnType::Bool,
3189 Expression::FlatWeightedSumLeq(_, _, _, _) => ReturnType::Bool,
3190 Expression::FlatWeightedSumGeq(_, _, _, _) => ReturnType::Bool,
3191 Expression::MinionPow(_, _, _, _) => ReturnType::Bool,
3192 Expression::ToInt(_, _) => ReturnType::Int,
3193 Expression::SATInt(..) => ReturnType::Int,
3194 Expression::PairwiseSum(_, _, _) => ReturnType::Int,
3195 Expression::PairwiseProduct(_, _, _) => ReturnType::Int,
3196 Expression::Defined(_, function) => {
3197 let subject = function.return_type();
3198 match subject {
3199 ReturnType::Function(domain, _) => ReturnType::Set(Box::new(*domain)),
3200 _ => bug!(
3201 "Invalid defined operation: expected the operand to be a function, got {self}: {subject}"
3202 ),
3203 }
3204 }
3205 Expression::Range(_, function) => {
3206 let subject = function.return_type();
3207 match subject {
3208 ReturnType::Function(_, codomain) => ReturnType::Set(Box::new(*codomain)),
3209 _ => bug!(
3210 "Invalid range operation: expected the operand to be a function, got {self}: {subject}"
3211 ),
3212 }
3213 }
3214 Expression::Image(_, function, _) => {
3215 let subject = function.return_type();
3216 match subject {
3217 ReturnType::Function(_, codomain) => *codomain,
3218 ReturnType::Permutation(inner) => *inner,
3219 ReturnType::Sequence(inner) => *inner,
3221 _ => bug!(
3222 "Invalid image operation: expected the operand to be a function or permutation, got {self}: {subject}"
3223 ),
3224 }
3225 }
3226 Expression::ImageSet(_, function, _) => {
3227 let subject = function.return_type();
3228 match subject {
3229 ReturnType::Function(_, codomain) => ReturnType::Set(Box::new(*codomain)),
3230 ReturnType::Permutation(inner) => ReturnType::Set(inner),
3231 _ => bug!(
3232 "Invalid imageSet operation: expected the operand to be a function or permutation, got {self}: {subject}"
3233 ),
3234 }
3235 }
3236 Expression::PreImage(_, function, _) => {
3237 let subject = function.return_type();
3238 match subject {
3239 ReturnType::Function(domain, _) => ReturnType::Set(Box::new(*domain)),
3240 _ => bug!(
3241 "Invalid preImage operation: expected the operand to be a function, got {self}: {subject}"
3242 ),
3243 }
3244 }
3245 Expression::Restrict(_, function, new_domain) => {
3246 let subject = function.return_type();
3247 match subject {
3248 ReturnType::Function(_, codomain) => {
3249 ReturnType::Function(Box::new(new_domain.return_type()), codomain)
3250 }
3251 _ => bug!(
3252 "Invalid preImage operation: expected the operand to be a function, got {self}: {subject}"
3253 ),
3254 }
3255 }
3256 Expression::Inverse(..) => ReturnType::Bool,
3257 Expression::PermInverse(_, p) => p.return_type(),
3258 Expression::Compose(_, g, _h) => g.return_type(),
3259 Expression::LexLt(..) => ReturnType::Bool,
3260 Expression::LexGt(..) => ReturnType::Bool,
3261 Expression::LexLeq(..) => ReturnType::Bool,
3262 Expression::LexGeq(..) => ReturnType::Bool,
3263 Expression::FlatLexLt(..) => ReturnType::Bool,
3264 Expression::FlatLexLeq(..) => ReturnType::Bool,
3265 Expression::Active(..) => ReturnType::Bool,
3266 Expression::ToSet(_, other) => {
3267 let subject = other.return_type();
3268 match subject {
3269 ReturnType::Matrix(domain) => ReturnType::Set(Box::new(*domain)),
3270 ReturnType::MSet(domain) => ReturnType::Set(Box::new(*domain)),
3271 ReturnType::Function(domain, codomain) => {
3272 ReturnType::Set(Box::new(ReturnType::Tuple(vec![*domain, *codomain])))
3273 }
3274 ReturnType::Relation(domains) => {
3275 ReturnType::Set(Box::new(ReturnType::Tuple(domains)))
3276 }
3277 _ => bug!(
3278 "Invalid toSet operation: expected the operand to be a mset, matrix, relation, or function, got {self}: {subject}"
3279 ),
3280 }
3281 }
3282 Expression::ToMSet(_, other) => {
3283 let subject = other.return_type();
3284 match subject {
3285 ReturnType::Set(domain) => ReturnType::MSet(Box::new(*domain)),
3286 ReturnType::Function(domain, codomain) => {
3287 ReturnType::MSet(Box::new(ReturnType::Tuple(vec![*domain, *codomain])))
3288 }
3289 ReturnType::Relation(domains) => {
3290 ReturnType::MSet(Box::new(ReturnType::Tuple(domains)))
3291 }
3292 _ => bug!(
3293 "Invalid toMSet operation: expected the operand to be a set, relation, or function, got {self}: {subject}"
3294 ),
3295 }
3296 }
3297 Expression::ToRelation(_, function) => {
3298 let subject = function.return_type();
3299 match subject {
3300 ReturnType::Function(domain, codomain) => {
3301 ReturnType::Relation(vec![*domain, *codomain])
3302 }
3303 _ => bug!(
3304 "Invalid toRelation operation: expected the operand to be a function, got {self}: {subject}"
3305 ),
3306 }
3307 }
3308 Expression::RelationProj(_, relation, projections) => {
3309 let subject = relation.return_type();
3310 match subject {
3311 ReturnType::Relation(domains) => {
3312 let new_doms = domains
3313 .iter()
3314 .zip(projections.iter())
3315 .filter_map(|(domain, included)| {
3316 if included.is_none() {
3317 Some(domain.clone())
3319 } else {
3320 None
3321 }
3322 })
3323 .collect();
3324 ReturnType::Relation(new_doms)
3325 }
3326 _ => bug!(
3327 "Invalid RelationProj operation: expected the operand to be a relation, got {self}: {subject}"
3328 ),
3329 }
3330 }
3331 Expression::Card(..) => ReturnType::Int,
3332 Expression::Subsequence(_, _, _) => ReturnType::Bool,
3333 Expression::Substring(_, _, _) => ReturnType::Bool,
3334 Expression::AttributeAsConstraint(_, _, _, _) => ReturnType::Bool,
3335 }
3336 }
3337}
3338
3339impl Expression {
3340 pub fn for_each_expr_child<'a>(&'a self, f: &mut impl FnMut(&'a Expression)) {
3342 match self {
3343 Expression::AbstractLiteral(_, alit) => match alit {
3345 AbstractLiteral::Set(v) | AbstractLiteral::MSet(v) | AbstractLiteral::Tuple(v) => {
3346 for expr in v {
3347 f(expr);
3348 }
3349 }
3350 AbstractLiteral::Partition(two_d_v) => {
3351 for part in two_d_v {
3352 for expr in part {
3353 f(expr);
3354 }
3355 }
3356 }
3357 AbstractLiteral::Matrix(v, _domain) => {
3358 for expr in v {
3359 f(expr);
3360 }
3361 }
3362 AbstractLiteral::Record(rs) => {
3363 for r in rs {
3364 f(&r.value);
3365 }
3366 }
3367 AbstractLiteral::Sequence(v) => {
3368 for expr in v {
3369 f(expr);
3370 }
3371 }
3372 AbstractLiteral::Function(vs) => {
3373 for (a, b) in vs {
3374 f(a);
3375 f(b);
3376 }
3377 }
3378 AbstractLiteral::Variant(v) => {
3379 f(&v.value);
3380 }
3381 AbstractLiteral::Relation(vs) => {
3382 for exprs in vs {
3383 for expr in exprs {
3384 f(expr);
3385 }
3386 }
3387 }
3388 AbstractLiteral::Permutation(cycles) => {
3389 for cycle in cycles {
3390 for expr in cycle {
3391 f(expr);
3392 }
3393 }
3394 }
3395 },
3396 Expression::Root(_, vs) => {
3397 for expr in vs {
3398 f(expr);
3399 }
3400 }
3401
3402 Expression::DominanceRelation(_, m1)
3404 | Expression::TypeAnnotation(_, m1, _)
3405 | Expression::DomainAnnotation(_, m1, _)
3406 | Expression::ToInt(_, m1)
3407 | Expression::Abs(_, m1)
3408 | Expression::Sum(_, m1)
3409 | Expression::Product(_, m1)
3410 | Expression::Min(_, m1)
3411 | Expression::Max(_, m1)
3412 | Expression::Not(_, m1)
3413 | Expression::Or(_, m1)
3414 | Expression::And(_, m1)
3415 | Expression::Neg(_, m1)
3416 | Expression::PermInverse(_, m1)
3417 | Expression::Defined(_, m1)
3418 | Expression::AllDiff(_, m1)
3419 | Expression::SmtDistinct(_, m1)
3420 | Expression::Factorial(_, m1)
3421 | Expression::Range(_, m1)
3422 | Expression::Participants(_, m1)
3423 | Expression::Parts(_, m1)
3424 | Expression::ToSet(_, m1)
3425 | Expression::ToMSet(_, m1)
3426 | Expression::ToRelation(_, m1)
3427 | Expression::Card(_, m1)
3428 | Expression::RecordField(_, m1, _)
3429 | Expression::Active(_, m1, _) => {
3430 f(m1);
3431 }
3432
3433 Expression::Table(_, m1, m2)
3435 | Expression::NegativeTable(_, m1, m2)
3436 | Expression::Bubble(_, m1, m2)
3437 | Expression::Imply(_, m1, m2)
3438 | Expression::Iff(_, m1, m2)
3439 | Expression::Difference(_, m1, m2)
3440 | Expression::Union(_, m1, m2)
3441 | Expression::In(_, m1, m2)
3442 | Expression::Intersect(_, m1, m2)
3443 | Expression::Supset(_, m1, m2)
3444 | Expression::SupsetEq(_, m1, m2)
3445 | Expression::Subset(_, m1, m2)
3446 | Expression::SubsetEq(_, m1, m2)
3447 | Expression::Eq(_, m1, m2)
3448 | Expression::Neq(_, m1, m2)
3449 | Expression::Geq(_, m1, m2)
3450 | Expression::Leq(_, m1, m2)
3451 | Expression::Gt(_, m1, m2)
3452 | Expression::Lt(_, m1, m2)
3453 | Expression::CatchUndef(_, m1, m2)
3454 | Expression::SafeDiv(_, m1, m2)
3455 | Expression::UnsafeDiv(_, m1, m2)
3456 | Expression::SafeMod(_, m1, m2)
3457 | Expression::UnsafeMod(_, m1, m2)
3458 | Expression::UnsafePow(_, m1, m2)
3459 | Expression::SafePow(_, m1, m2)
3460 | Expression::Minus(_, m1, m2)
3461 | Expression::PairwiseSum(_, m1, m2)
3462 | Expression::PairwiseProduct(_, m1, m2)
3463 | Expression::Image(_, m1, m2)
3464 | Expression::ImageSet(_, m1, m2)
3465 | Expression::PreImage(_, m1, m2)
3466 | Expression::Inverse(_, m1, m2)
3467 | Expression::Compose(_, m1, m2)
3468 | Expression::Restrict(_, m1, m2)
3469 | Expression::Apart(_, m1, m2)
3470 | Expression::Together(_, m1, m2)
3471 | Expression::Party(_, m1, m2)
3472 | Expression::LexLt(_, m1, m2)
3473 | Expression::LexLeq(_, m1, m2)
3474 | Expression::LexGt(_, m1, m2)
3475 | Expression::LexGeq(_, m1, m2)
3476 | Expression::Subsequence(_, m1, m2)
3477 | Expression::Substring(_, m1, m2) => {
3478 f(m1);
3479 f(m2);
3480 }
3481
3482 Expression::UnsafeIndex(_, m, vs) | Expression::SafeIndex(_, m, vs) => {
3484 f(m);
3485 for v in vs {
3486 f(v);
3487 }
3488 }
3489 Expression::UnsafeSlice(_, m, vs)
3491 | Expression::SafeSlice(_, m, vs)
3492 | Expression::RelationProj(_, m, vs) => {
3493 f(m);
3494 for e in vs.iter().flatten() {
3495 f(e);
3496 }
3497 }
3498
3499 Expression::AtLeast(_, m1, m2, m3)
3501 | Expression::AtMost(_, m1, m2, m3)
3502 | Expression::Gcc(_, m1, m2, m3)
3503 | Expression::GccWeak(_, m1, m2, m3) => {
3504 f(m1);
3505 f(m2);
3506 f(m3);
3507 }
3508
3509 Expression::AllDifferentExcept(_, m1, m2) | Expression::ElementId(_, m1, m2) => {
3511 f(m1);
3512 f(m2);
3513 }
3514
3515 Expression::InDomain(_, m, _) => {
3517 f(m);
3518 }
3519
3520 Expression::Flatten(_, opt, m) => {
3522 if let Some(e) = opt {
3523 f(e);
3524 }
3525 f(m);
3526 }
3527
3528 Expression::AttributeAsConstraint(_, target, _, val) => {
3530 f(target);
3531 if let Some(v) = val {
3532 f(v);
3533 }
3534 }
3535
3536 Expression::MinionReify(_, m, _) | Expression::MinionReifyImply(_, m, _) => {
3538 f(m);
3539 }
3540
3541 Expression::AuxDeclaration(_, _, m) => {
3543 f(m);
3544 }
3545
3546 Expression::SATInt(_, _, m, _) => {
3548 f(m);
3549 }
3550
3551 Expression::Comprehension(_, _)
3553 | Expression::Atomic(_, _)
3554 | Expression::FromSolution(_, _)
3555 | Expression::Metavar(_, _)
3556 | Expression::FlatAbsEq(_, _, _)
3557 | Expression::FlatMinusEq(_, _, _)
3558 | Expression::FlatProductEq(_, _, _, _)
3559 | Expression::MinionDivEqUndefZero(_, _, _, _)
3560 | Expression::MinionModuloEqUndefZero(_, _, _, _)
3561 | Expression::MinionPow(_, _, _, _)
3562 | Expression::FlatAllDiff(_, _)
3563 | Expression::FlatMinEq(_, _, _)
3564 | Expression::FlatSumGeq(_, _, _)
3565 | Expression::FlatSumLeq(_, _, _)
3566 | Expression::FlatIneq(_, _, _, _)
3567 | Expression::FlatWatchedLiteral(_, _, _)
3568 | Expression::FlatWeightedSumLeq(_, _, _, _)
3569 | Expression::FlatWeightedSumGeq(_, _, _, _)
3570 | Expression::MinionWInIntervalSet(_, _, _)
3571 | Expression::MinionWInSet(_, _, _)
3572 | Expression::MinionElementOne(_, _, _, _)
3573 | Expression::FlatLexLt(_, _, _)
3574 | Expression::FlatLexLeq(_, _, _) => {}
3575 }
3576 }
3577
3578 pub fn for_each_expression<'a>(&'a self, f: &mut impl FnMut(&'a Expression)) {
3580 f(self);
3581 self.for_each_expr_child(&mut |child| child.for_each_expression(f));
3582 }
3583
3584 pub fn any_expression(&self, mut predicate: impl FnMut(&Expression) -> bool) -> bool {
3588 fn visit(expr: &Expression, predicate: &mut impl FnMut(&Expression) -> bool) -> bool {
3589 if predicate(expr) {
3590 return true;
3591 }
3592
3593 let mut found = false;
3594 expr.for_each_expr_child(&mut |child| {
3595 if !found {
3596 found = visit(child, predicate);
3597 }
3598 });
3599 found
3600 }
3601
3602 visit(self, &mut predicate)
3603 }
3604
3605 pub fn any_expression_descendant(
3607 &self,
3608 mut predicate: impl FnMut(&Expression) -> bool,
3609 ) -> bool {
3610 let mut found = false;
3611 self.for_each_expr_child(&mut |child| {
3612 if !found {
3613 found = child.any_expression(&mut predicate);
3614 }
3615 });
3616 found
3617 }
3618}
3619
3620impl Expression {
3621 pub(crate) fn invalidate_cached_content_hash(&self) {
3623 let metadata = self.meta_ref();
3624 metadata
3625 .cached_content_hash
3626 .store(NO_HASH, Ordering::Relaxed);
3627 }
3628
3629 pub(crate) fn cached_content_hash(&self) -> u64 {
3631 let stored = self.meta_ref().cached_content_hash.load(Ordering::Relaxed);
3632 if stored != NO_HASH {
3633 HASH_HITS.fetch_add(1, Ordering::Relaxed);
3634 return stored;
3635 }
3636 HASH_MISSES.fetch_add(1, Ordering::Relaxed);
3637 self.calculate_content_hash()
3638 }
3639
3640 #[allow(unused_variables)]
3645 pub(crate) fn content_hash_from_child_hashes(
3646 &self,
3647 child_hashes: &mut impl Iterator<Item = u64>,
3648 ) -> u64 {
3649 fn child_hash(child_hashes: &mut impl Iterator<Item = u64>) -> u64 {
3650 child_hashes
3651 .next()
3652 .expect("expression content hash missing child hash")
3653 }
3654
3655 let mut hasher = DefaultHasher::new();
3656 std::mem::discriminant(self).hash(&mut hasher);
3657 match self {
3658 Expression::AbstractLiteral(_, alit) => match alit {
3660 AbstractLiteral::Set(v)
3661 | AbstractLiteral::MSet(v)
3662 | AbstractLiteral::Tuple(v)
3663 | AbstractLiteral::Sequence(v) => {
3664 for expr in v {
3665 child_hash(child_hashes).hash(&mut hasher);
3666 }
3667 }
3668 AbstractLiteral::Matrix(v, domain) => {
3669 domain.hash(&mut hasher);
3670 for expr in v {
3671 child_hash(child_hashes).hash(&mut hasher);
3672 }
3673 }
3674 AbstractLiteral::Record(rs) => {
3675 for r in rs {
3676 r.name.hash(&mut hasher);
3677 child_hash(child_hashes).hash(&mut hasher);
3678 }
3679 }
3680 AbstractLiteral::Function(vs) => {
3681 for (a, b) in vs {
3682 child_hash(child_hashes).hash(&mut hasher);
3683 child_hash(child_hashes).hash(&mut hasher);
3684 }
3685 }
3686 AbstractLiteral::Variant(v) => {
3687 v.name.hash(&mut hasher);
3688 child_hash(child_hashes).hash(&mut hasher);
3689 }
3690 AbstractLiteral::Relation(v) => {
3691 for exprs in v {
3692 for expr in exprs {
3693 child_hash(child_hashes).hash(&mut hasher);
3694 }
3695 }
3696 }
3697 AbstractLiteral::Partition(v) => {
3698 for exprs in v {
3699 for expr in exprs {
3700 child_hash(child_hashes).hash(&mut hasher);
3701 }
3702 }
3703 }
3704 AbstractLiteral::Permutation(v) => {
3705 for exprs in v {
3706 for expr in exprs {
3707 child_hash(child_hashes).hash(&mut hasher);
3708 }
3709 }
3710 }
3711 },
3712 Expression::Root(_, vs) => {
3713 for expr in vs {
3714 child_hash(child_hashes).hash(&mut hasher);
3715 }
3716 }
3717
3718 Expression::DominanceRelation(_, m1)
3720 | Expression::ToInt(_, m1)
3721 | Expression::Abs(_, m1)
3722 | Expression::Sum(_, m1)
3723 | Expression::Product(_, m1)
3724 | Expression::Min(_, m1)
3725 | Expression::Max(_, m1)
3726 | Expression::Not(_, m1)
3727 | Expression::Or(_, m1)
3728 | Expression::And(_, m1)
3729 | Expression::Neg(_, m1)
3730 | Expression::PermInverse(_, m1)
3731 | Expression::Defined(_, m1)
3732 | Expression::AllDiff(_, m1)
3733 | Expression::SmtDistinct(_, m1)
3734 | Expression::Factorial(_, m1)
3735 | Expression::Participants(_, m1)
3736 | Expression::Parts(_, m1)
3737 | Expression::Range(_, m1)
3738 | Expression::ToSet(_, m1)
3739 | Expression::ToMSet(_, m1)
3740 | Expression::ToRelation(_, m1)
3741 | Expression::Card(_, m1) => {
3742 child_hash(child_hashes).hash(&mut hasher);
3743 }
3744 Expression::TypeAnnotation(_, m1, domain) => {
3745 child_hash(child_hashes).hash(&mut hasher);
3746 domain.hash(&mut hasher);
3747 }
3748 Expression::DomainAnnotation(_, m1, domain) => {
3749 child_hash(child_hashes).hash(&mut hasher);
3750 domain.hash(&mut hasher);
3751 }
3752
3753 Expression::Table(_, m1, m2)
3755 | Expression::NegativeTable(_, m1, m2)
3756 | Expression::Bubble(_, m1, m2)
3757 | Expression::Imply(_, m1, m2)
3758 | Expression::Iff(_, m1, m2)
3759 | Expression::Difference(_, m1, m2)
3760 | Expression::Union(_, m1, m2)
3761 | Expression::In(_, m1, m2)
3762 | Expression::Intersect(_, m1, m2)
3763 | Expression::Supset(_, m1, m2)
3764 | Expression::SupsetEq(_, m1, m2)
3765 | Expression::Subset(_, m1, m2)
3766 | Expression::SubsetEq(_, m1, m2)
3767 | Expression::Eq(_, m1, m2)
3768 | Expression::Neq(_, m1, m2)
3769 | Expression::Geq(_, m1, m2)
3770 | Expression::Leq(_, m1, m2)
3771 | Expression::Gt(_, m1, m2)
3772 | Expression::Lt(_, m1, m2)
3773 | Expression::Apart(_, m1, m2)
3774 | Expression::Together(_, m1, m2)
3775 | Expression::Party(_, m1, m2)
3776 | Expression::CatchUndef(_, m1, m2)
3777 | Expression::SafeDiv(_, m1, m2)
3778 | Expression::UnsafeDiv(_, m1, m2)
3779 | Expression::SafeMod(_, m1, m2)
3780 | Expression::UnsafeMod(_, m1, m2)
3781 | Expression::UnsafePow(_, m1, m2)
3782 | Expression::SafePow(_, m1, m2)
3783 | Expression::Minus(_, m1, m2)
3784 | Expression::PairwiseSum(_, m1, m2)
3785 | Expression::PairwiseProduct(_, m1, m2)
3786 | Expression::Image(_, m1, m2)
3787 | Expression::ImageSet(_, m1, m2)
3788 | Expression::PreImage(_, m1, m2)
3789 | Expression::Inverse(_, m1, m2)
3790 | Expression::Compose(_, m1, m2)
3791 | Expression::Restrict(_, m1, m2)
3792 | Expression::LexLt(_, m1, m2)
3793 | Expression::LexLeq(_, m1, m2)
3794 | Expression::LexGt(_, m1, m2)
3795 | Expression::LexGeq(_, m1, m2)
3796 | Expression::Subsequence(_, m1, m2)
3797 | Expression::Substring(_, m1, m2) => {
3798 child_hash(child_hashes).hash(&mut hasher);
3799 child_hash(child_hashes).hash(&mut hasher);
3800 }
3801 Expression::UnsafeIndex(_, m, vs) | Expression::SafeIndex(_, m, vs) => {
3803 child_hash(child_hashes).hash(&mut hasher);
3804 for v in vs {
3805 child_hash(child_hashes).hash(&mut hasher);
3806 }
3807 }
3808
3809 Expression::UnsafeSlice(_, m, vs)
3811 | Expression::SafeSlice(_, m, vs)
3812 | Expression::RelationProj(_, m, vs) => {
3813 child_hash(child_hashes).hash(&mut hasher);
3814 for v in vs {
3815 match v {
3816 Some(e) => child_hash(child_hashes).hash(&mut hasher),
3817 None => 0u64.hash(&mut hasher),
3818 }
3819 }
3820 }
3821
3822 Expression::AtLeast(_, m1, m2, m3)
3824 | Expression::AtMost(_, m1, m2, m3)
3825 | Expression::Gcc(_, m1, m2, m3)
3826 | Expression::GccWeak(_, m1, m2, m3) => {
3827 child_hash(child_hashes).hash(&mut hasher);
3828 child_hash(child_hashes).hash(&mut hasher);
3829 child_hash(child_hashes).hash(&mut hasher);
3830 }
3831
3832 Expression::AllDifferentExcept(_, m1, m2) | Expression::ElementId(_, m1, m2) => {
3834 child_hash(child_hashes).hash(&mut hasher);
3835 child_hash(child_hashes).hash(&mut hasher);
3836 }
3837
3838 Expression::RecordField(_, m, n) | Expression::Active(_, m, n) => {
3840 child_hash(child_hashes).hash(&mut hasher);
3841 n.hash(&mut hasher);
3842 }
3843
3844 Expression::InDomain(_, m, d) => {
3846 child_hash(child_hashes).hash(&mut hasher);
3847 d.hash(&mut hasher);
3848 }
3849
3850 Expression::Flatten(_, opt, m) => {
3852 if let Some(e) = opt {
3853 child_hash(child_hashes).hash(&mut hasher);
3854 }
3855 child_hash(child_hashes).hash(&mut hasher);
3856 }
3857
3858 Expression::AttributeAsConstraint(_, target, attr, val) => {
3860 child_hash(child_hashes).hash(&mut hasher);
3861 attr.hash(&mut hasher);
3862 if let Some(v) = val {
3863 child_hash(child_hashes).hash(&mut hasher);
3864 }
3865 }
3866
3867 Expression::MinionReify(_, m, a) | Expression::MinionReifyImply(_, m, a) => {
3869 child_hash(child_hashes).hash(&mut hasher);
3870 a.hash(&mut hasher);
3871 }
3872
3873 Expression::AuxDeclaration(_, r, m) => {
3875 r.hash(&mut hasher);
3876 child_hash(child_hashes).hash(&mut hasher);
3877 }
3878
3879 Expression::SATInt(_, enc, m, bounds) => {
3881 enc.hash(&mut hasher);
3882 child_hash(child_hashes).hash(&mut hasher);
3883 bounds.hash(&mut hasher);
3884 }
3885
3886 Expression::Comprehension(_, c) => c.hash(&mut hasher),
3888
3889 Expression::Atomic(_, a) => a.hash(&mut hasher),
3891 Expression::FromSolution(_, a) => a.hash(&mut hasher),
3892 Expression::Metavar(_, u) => u.hash(&mut hasher),
3893
3894 Expression::FlatAbsEq(_, a1, a2) | Expression::FlatMinusEq(_, a1, a2) => {
3896 a1.hash(&mut hasher);
3897 a2.hash(&mut hasher);
3898 }
3899
3900 Expression::FlatProductEq(_, a1, a2, a3)
3902 | Expression::MinionDivEqUndefZero(_, a1, a2, a3)
3903 | Expression::MinionModuloEqUndefZero(_, a1, a2, a3)
3904 | Expression::MinionPow(_, a1, a2, a3) => {
3905 a1.hash(&mut hasher);
3906 a2.hash(&mut hasher);
3907 a3.hash(&mut hasher);
3908 }
3909
3910 Expression::FlatAllDiff(_, vs) => {
3912 for v in vs {
3913 v.hash(&mut hasher);
3914 }
3915 }
3916
3917 Expression::FlatMinEq(_, vs, a)
3919 | Expression::FlatSumGeq(_, vs, a)
3920 | Expression::FlatSumLeq(_, vs, a) => {
3921 for v in vs {
3922 v.hash(&mut hasher);
3923 }
3924 a.hash(&mut hasher);
3925 }
3926
3927 Expression::FlatIneq(_, a1, a2, lit) => {
3929 a1.hash(&mut hasher);
3930 a2.hash(&mut hasher);
3931 lit.hash(&mut hasher);
3932 }
3933
3934 Expression::FlatWatchedLiteral(_, r, l) => {
3936 r.hash(&mut hasher);
3937 l.hash(&mut hasher);
3938 }
3939
3940 Expression::FlatWeightedSumLeq(_, lits, atoms, a)
3942 | Expression::FlatWeightedSumGeq(_, lits, atoms, a) => {
3943 for l in lits {
3944 l.hash(&mut hasher);
3945 }
3946 for at in atoms {
3947 at.hash(&mut hasher);
3948 }
3949 a.hash(&mut hasher);
3950 }
3951
3952 Expression::MinionWInIntervalSet(_, a, vs) | Expression::MinionWInSet(_, a, vs) => {
3954 a.hash(&mut hasher);
3955 for v in vs {
3956 v.hash(&mut hasher);
3957 }
3958 }
3959
3960 Expression::MinionElementOne(_, vs, a1, a2) => {
3962 for v in vs {
3963 v.hash(&mut hasher);
3964 }
3965 a1.hash(&mut hasher);
3966 a2.hash(&mut hasher);
3967 }
3968
3969 Expression::FlatLexLt(_, v1, v2) | Expression::FlatLexLeq(_, v1, v2) => {
3971 for v in v1 {
3972 v.hash(&mut hasher);
3973 }
3974 for v in v2 {
3975 v.hash(&mut hasher);
3976 }
3977 }
3978 };
3979
3980 hasher.finish()
3981 }
3982
3983 pub(crate) fn calculate_content_hash(&self) -> u64 {
3985 let mut hashes = Vec::new();
3986 self.for_each_expr_child(&mut |child| hashes.push(child.cached_content_hash()));
3987 let mut child_hashes = hashes.into_iter();
3988 let result = self.content_hash_from_child_hashes(&mut child_hashes);
3989 self.meta_ref()
3990 .cached_content_hash
3991 .store(result, Ordering::Relaxed);
3992 result
3993 }
3994}
3995
3996#[cfg(test)]
3997mod tests {
3998 use crate::matrix_expr;
3999
4000 use super::*;
4001
4002 #[test]
4003 fn test_domain_of_constant_sum() {
4004 let c1 = Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(1)));
4005 let c2 = Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(2)));
4006 let sum = Expression::Sum(Metadata::new(), Moo::new(matrix_expr![c1, c2]));
4007 assert_eq!(sum.domain_of(), Some(Domain::int(vec![Range::Single(3)])));
4008 }
4009
4010 #[test]
4011 fn test_domain_of_constant_invalid_type() {
4012 let c1 = Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(1)));
4013 let c2 = Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(true)));
4014 let sum = Expression::Sum(Metadata::new(), Moo::new(matrix_expr![c1, c2]));
4015 assert_eq!(sum.domain_of(), None);
4016 }
4017
4018 #[test]
4019 fn test_domain_of_empty_sum() {
4020 let sum = Expression::Sum(Metadata::new(), Moo::new(matrix_expr![]));
4021 assert_eq!(sum.domain_of(), None);
4022 }
4023
4024 #[test]
4026 fn test_domain_of_product_overflow_returns_none() {
4027 let mk_var = |name: &str| {
4028 Expression::Atomic(
4029 Metadata::new(),
4030 Atom::Reference(Reference::new(DeclarationPtr::new_find(
4031 Name::User(name.into()),
4032 Domain::int(vec![Range::Bounded(0, 711)]),
4033 ))),
4034 )
4035 };
4036 let product = Expression::Product(
4037 Metadata::new(),
4038 Moo::new(matrix_expr![
4039 mk_var("item1"),
4040 mk_var("item2"),
4041 mk_var("item3"),
4042 mk_var("item4")
4043 ]),
4044 );
4045 assert_eq!(product.domain_of(), None);
4046 }
4047
4048 #[test]
4049 fn mset_union_domain_adds_finite_operand_bounds() {
4050 let lhs = DeclarationPtr::new_find(
4051 Name::user("xs"),
4052 Domain::mset(
4053 MSetAttr::new_max_size(6).with_representation("counts"),
4054 Domain::int(vec![Range::Bounded(1, 999)]),
4055 ),
4056 );
4057 let rhs = Expression::AbstractLiteral(
4058 Metadata::new(),
4059 AbstractLiteral::MSet(vec![1.into(), 2.into()]),
4060 );
4061 let union = Expression::Union(
4062 Metadata::new(),
4063 Moo::new(Expression::from(Reference::new(lhs))),
4064 Moo::new(rhs),
4065 );
4066
4067 let domain = union.domain_of().expect("multiset union has a domain");
4068 let (attrs, inner) = domain.as_mset_ground().expect("ground multiset domain");
4069 assert_eq!(attrs.size, Range::Bounded(2, 8));
4070 assert_eq!(attrs.occurrence, Range::Bounded(1, 8));
4071 assert_eq!(attrs.representation.as_deref(), Some("counts"));
4072 assert_eq!(
4073 inner.as_ref(),
4074 &GroundDomain::Int(vec![Range::Bounded(1, 999)])
4075 );
4076 }
4077
4078 #[test]
4079 fn list_inspection_borrows_expression_elements_without_cloning_the_list() {
4080 let list = matrix_expr![
4081 Expression::from(Literal::Int(1)),
4082 Expression::from(Literal::Int(2))
4083 ];
4084
4085 assert_eq!(list.list_len(), Some(2));
4086 assert!(list.is_list());
4087 assert!(matches!(list.unwrap_list_cow(), Some(Cow::Borrowed(_))));
4088 }
4089
4090 #[test]
4091 fn list_inspection_materialises_literal_elements_only_when_they_are_requested() {
4092 let list = Expression::Atomic(
4093 Metadata::new(),
4094 Atom::Literal(Literal::AbstractLiteral(
4095 AbstractLiteral::matrix_implied_indices(vec![Literal::Int(1), Literal::Int(2)]),
4096 )),
4097 );
4098
4099 assert_eq!(list.list_len(), Some(2));
4100 assert!(list.is_list());
4101 assert!(matches!(list.unwrap_list_cow(), Some(Cow::Owned(_))));
4102 assert_eq!(
4103 list.unwrap_list_cow().map(Cow::into_owned),
4104 list.unwrap_list()
4105 );
4106 }
4107
4108 #[test]
4109 fn list_length_looks_through_annotations() {
4110 let list = Expression::DomainAnnotation(
4111 Metadata::new(),
4112 Moo::new(matrix_expr![Expression::from(Literal::Int(1))]),
4113 Domain::int(vec![Range::Bounded(0, 1)]),
4114 );
4115
4116 assert_eq!(list.list_len(), Some(1));
4117 assert!(matches!(list.unwrap_list_cow(), Some(Cow::Borrowed(_))));
4118 }
4119}