1use std::borrow::Cow;
2use std::collections::{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::metadata::NO_HASH;
28use crate::bug;
29
30use super::ac_operators::ACOperatorKind;
31use super::categories::{Category, CategoryOf};
32use super::collection_domains::{
33 SetOperation, SizeBounds, bounded_set, collection_size, distinct_size, mset_size,
34 set_operation_domain,
35};
36use super::comprehension::Comprehension;
37use super::declaration::DeclarationKind;
38use super::domains::HasDomain as _;
39use super::eval::eval_constant;
40use super::expression_domains::{
41 absolute_integer_domain, binary_integer_domain,
42 bounded_i32_domain_for_matrix_literal_monotonic, division_domain,
43 empty_matrix_integer_element_domain, factorial_domain, get_function_codomain,
44 matrix_element_domain, modulo_domain, mset_union_result_domain, power_integer_domain,
45 sum_domain_of_child,
46};
47use super::function_domains::{
48 defined_domain, function_size, image_set_domain, pre_image_domain, range_domain,
49 restricted_domain,
50};
51use super::pretty::{pretty_expression_domain_annotation, pretty_expression_type_annotation};
52use super::pretty::{pretty_expressions_as_top_level, pretty_vec};
53use super::records::Field;
54use super::sat_encoding::SATIntEncoding;
55use super::{
56 AbstractLiteral, Atom, DeclarationPtr, Domain, DomainPtr, GroundDomain, IntVal, Literal,
57 MSetAttr, Metadata, Model, Moo, Name, PartialityAttr, Range, Reference, RelAttr, ReturnType,
58 SetAttr, SymbolTable, SymbolTablePtr, Typeable, matrix,
59};
60
61static_assertions::const_assert!(std::mem::size_of::<Expression>() <= 152);
85
86#[generate_discriminants]
91#[document_compatibility]
92#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Uniplate, Quine)]
93#[biplate(to=AbstractLiteral<Expression>)]
94#[biplate(to=AbstractLiteral<Literal>)]
95#[biplate(to=Atom)]
96#[biplate(to=Comprehension)]
97#[biplate(to=DeclarationPtr)]
98#[biplate(to=DomainPtr)]
99#[biplate(to=Literal)]
100#[biplate(to=Metadata)]
101#[biplate(to=Name)]
102#[biplate(to=Option<Expression>)]
103#[biplate(to=Field<Expression>)]
104#[biplate(to=Field<Literal>)]
105#[biplate(to=Reference)]
106#[biplate(to=Model)]
107#[biplate(to=SymbolTable)]
108#[biplate(to=SymbolTablePtr)]
109#[biplate(to=Vec<Expression>)]
110#[path_prefix(conjure_cp::ast)]
111pub enum Expression {
112 AbstractLiteral(Metadata, AbstractLiteral<Expression>),
113 Root(Metadata, Vec<Expression>),
115
116 Bubble(Metadata, Moo<Expression>, Moo<Expression>),
119
120 #[polyquine_skip]
126 Comprehension(Metadata, Moo<Comprehension>),
127
128 DominanceRelation(Metadata, Moo<Expression>),
130 FromSolution(Metadata, Moo<Atom>),
132
133 #[polyquine_with(arm = (_, name) => {
134 let ident = proc_macro2::Ident::new(name.as_str(), proc_macro2::Span::call_site());
135 quote::quote! { #ident.clone().into() }
136 })]
137 Metavar(Metadata, Ustr),
138
139 Atomic(Metadata, Atom),
140
141 TypeAnnotation(Metadata, Moo<Expression>, DomainPtr),
143
144 DomainAnnotation(Metadata, Moo<Expression>, DomainPtr),
146
147 #[compatible(JsonInput)]
150 Active(Metadata, Moo<Expression>, Name),
151
152 #[compatible(JsonInput)]
155 RecordField(Metadata, Moo<Expression>, Name),
156
157 #[compatible(JsonInput)]
161 UnsafeIndex(Metadata, Moo<Expression>, Vec<Expression>),
162
163 #[compatible(SMT)]
167 SafeIndex(Metadata, Moo<Expression>, Vec<Expression>),
168
169 #[polyquine_skip]
172 SatElement(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
173
174 SatAllDifferentComparisons(Metadata, Moo<Expression>),
176
177 #[compatible(JsonInput)]
187 UnsafeSlice(Metadata, Moo<Expression>, Vec<Option<Expression>>),
188
189 SafeSlice(Metadata, Moo<Expression>, Vec<Option<Expression>>),
193
194 InDomain(Metadata, Moo<Expression>, DomainPtr),
200
201 #[compatible(SMT)]
207 ToInt(Metadata, Moo<Expression>),
208
209 #[compatible(JsonInput, SMT)]
211 Abs(Metadata, Moo<Expression>),
212
213 #[compatible(JsonInput, SMT)]
215 Sum(Metadata, Moo<Expression>),
216
217 #[compatible(JsonInput, SMT)]
219 Product(Metadata, Moo<Expression>),
220
221 #[compatible(JsonInput, SMT)]
223 Min(Metadata, Moo<Expression>),
224
225 #[compatible(JsonInput, SMT)]
227 Max(Metadata, Moo<Expression>),
228
229 #[compatible(JsonInput, SAT, SMT)]
231 Not(Metadata, Moo<Expression>),
232
233 #[compatible(JsonInput, SAT, SMT)]
235 Or(Metadata, Moo<Expression>),
236
237 #[compatible(JsonInput, SAT, SMT)]
239 And(Metadata, Moo<Expression>),
240
241 #[compatible(JsonInput, SMT)]
243 Imply(Metadata, Moo<Expression>, Moo<Expression>),
244
245 #[compatible(JsonInput, SMT)]
247 Iff(Metadata, Moo<Expression>, Moo<Expression>),
248
249 #[compatible(JsonInput)]
250 Union(Metadata, Moo<Expression>, Moo<Expression>),
251
252 #[compatible(JsonInput)]
253 In(Metadata, Moo<Expression>, Moo<Expression>),
254
255 #[compatible(JsonInput)]
256 Intersect(Metadata, Moo<Expression>, Moo<Expression>),
257
258 #[compatible(JsonInput)]
264 Difference(Metadata, Moo<Expression>, Moo<Expression>),
265
266 #[compatible(JsonInput)]
267 Supset(Metadata, Moo<Expression>, Moo<Expression>),
268
269 #[compatible(JsonInput)]
270 SupsetEq(Metadata, Moo<Expression>, Moo<Expression>),
271
272 #[compatible(JsonInput)]
273 Subset(Metadata, Moo<Expression>, Moo<Expression>),
274
275 #[compatible(JsonInput)]
276 SubsetEq(Metadata, Moo<Expression>, Moo<Expression>),
277
278 #[compatible(JsonInput, SMT)]
279 Eq(Metadata, Moo<Expression>, Moo<Expression>),
280
281 #[compatible(JsonInput, SMT)]
282 Neq(Metadata, Moo<Expression>, Moo<Expression>),
283
284 #[compatible(JsonInput, SMT)]
285 Geq(Metadata, Moo<Expression>, Moo<Expression>),
286
287 #[compatible(JsonInput, SMT)]
288 Leq(Metadata, Moo<Expression>, Moo<Expression>),
289
290 #[compatible(JsonInput, SMT)]
291 Gt(Metadata, Moo<Expression>, Moo<Expression>),
292
293 #[compatible(JsonInput, SMT)]
294 Lt(Metadata, Moo<Expression>, Moo<Expression>),
295
296 #[compatible(JsonInput)]
297 Pred(Metadata, Moo<Expression>),
298
299 #[compatible(JsonInput)]
300 Succ(Metadata, Moo<Expression>),
301
302 #[compatible(JsonInput)]
305 Subsequence(Metadata, Moo<Expression>, Moo<Expression>),
306
307 #[compatible(JsonInput)]
310 Substring(Metadata, Moo<Expression>, Moo<Expression>),
311
312 #[compatible(JsonInput)]
317 CatchUndef(Metadata, Moo<Expression>, Moo<Expression>),
318
319 #[compatible(SMT)]
321 SafeDiv(Metadata, Moo<Expression>, Moo<Expression>),
322
323 #[compatible(JsonInput)]
325 UnsafeDiv(Metadata, Moo<Expression>, Moo<Expression>),
326
327 #[compatible(SMT)]
329 SafeMod(Metadata, Moo<Expression>, Moo<Expression>),
330
331 #[compatible(JsonInput)]
333 UnsafeMod(Metadata, Moo<Expression>, Moo<Expression>),
334
335 #[compatible(JsonInput, SMT)]
337 Neg(Metadata, Moo<Expression>),
338
339 #[compatible(JsonInput)]
341 Factorial(Metadata, Moo<Expression>),
342
343 #[compatible(JsonInput)]
345 Defined(Metadata, Moo<Expression>),
346
347 #[compatible(JsonInput)]
349 Range(Metadata, Moo<Expression>),
350
351 #[compatible(JsonInput)]
352 ToSet(Metadata, Moo<Expression>),
353
354 #[compatible(JsonInput)]
355 ToMSet(Metadata, Moo<Expression>),
356
357 #[compatible(JsonInput)]
358 ToRelation(Metadata, Moo<Expression>),
359
360 #[compatible(JsonInput)]
364 UnsafePow(Metadata, Moo<Expression>, Moo<Expression>),
365
366 SafePow(Metadata, Moo<Expression>, Moo<Expression>),
368
369 Flatten(Metadata, Option<Moo<Expression>>, Moo<Expression>),
373
374 AttributeAsConstraint(Metadata, Moo<Expression>, Ustr, Option<Moo<Expression>>),
378
379 #[compatible(JsonInput)]
381 AllDiff(Metadata, Moo<Expression>),
382
383 #[compatible(SMT)]
391 SmtDistinct(Metadata, Moo<Expression>),
392
393 #[compatible(JsonInput)]
395 AllDifferentExcept(Metadata, Moo<Expression>, Moo<Expression>),
396
397 ElementId(Metadata, Moo<Expression>, Moo<Expression>),
399
400 #[polyquine_skip]
402 IndexOf(Metadata, Moo<Expression>, Moo<Expression>),
403
404 #[compatible(JsonInput)]
409 Table(Metadata, Moo<Expression>, Moo<Expression>),
410
411 #[compatible(JsonInput)]
416 NegativeTable(Metadata, Moo<Expression>, Moo<Expression>),
417
418 ShortTable(Metadata, Moo<Expression>, Moo<Expression>),
421
422 #[polyquine_skip]
424 FlatTable(Metadata, Vec<Atom>, Vec<Vec<i32>>, bool),
425
426 #[polyquine_skip]
428 FlatShortTable(Metadata, Vec<Atom>, Vec<Vec<(usize, i32)>>),
429
430 #[compatible(JsonInput)]
434 AtLeast(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
435
436 #[compatible(JsonInput)]
440 AtMost(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
441
442 #[compatible(JsonInput)]
447 Gcc(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
448
449 #[compatible(Minion)]
451 GccWeak(Metadata, Moo<Expression>, Moo<Expression>, Moo<Expression>),
452
453 #[compatible(JsonInput)]
459 Minus(Metadata, Moo<Expression>, Moo<Expression>),
460
461 #[compatible(JsonInput)]
465 Apart(Metadata, Moo<Expression>, Moo<Expression>),
466
467 #[compatible(JsonInput)]
470 Participants(Metadata, Moo<Expression>),
471
472 #[compatible(JsonInput)]
476 Party(Metadata, Moo<Expression>, Moo<Expression>),
477
478 #[compatible(JsonInput)]
481 Parts(Metadata, Moo<Expression>),
482
483 #[compatible(JsonInput)]
487 Together(Metadata, Moo<Expression>, Moo<Expression>),
488
489 #[compatible(Minion)]
497 FlatAbsEq(Metadata, Moo<Atom>, Moo<Atom>),
498
499 #[compatible(Minion)]
507 FlatAllDiff(Metadata, Vec<Atom>),
508
509 #[compatible(Minion)]
518 FlatMinEq(Metadata, Vec<Atom>, Atom),
519
520 #[compatible(Minion)]
528 FlatSumGeq(Metadata, Vec<Atom>, Atom),
529
530 #[compatible(Minion)]
538 FlatSumLeq(Metadata, Vec<Atom>, Atom),
539
540 #[compatible(Minion)]
548 FlatIneq(Metadata, Moo<Atom>, Moo<Atom>, Box<Literal>),
549
550 #[compatible(Minion)]
563 #[polyquine_skip]
564 FlatWatchedLiteral(Metadata, Reference, Literal),
565
566 FlatWeightedSumLeq(Metadata, Vec<Literal>, Vec<Atom>, Moo<Atom>),
578
579 FlatWeightedSumGeq(Metadata, Vec<Literal>, Vec<Atom>, Moo<Atom>),
591
592 #[compatible(Minion)]
600 FlatMinusEq(Metadata, Moo<Atom>, Moo<Atom>),
601
602 #[compatible(Minion)]
610 FlatProductEq(Metadata, Moo<Atom>, Moo<Atom>, Moo<Atom>),
611
612 #[compatible(Minion)]
620 MinionDivEqUndefZero(Metadata, Moo<Atom>, Moo<Atom>, Moo<Atom>),
621
622 #[compatible(Minion)]
630 MinionModuloEqUndefZero(Metadata, Moo<Atom>, Moo<Atom>, Moo<Atom>),
631
632 MinionPow(Metadata, Moo<Atom>, Moo<Atom>, Moo<Atom>),
644
645 #[compatible(Minion)]
654 MinionReify(Metadata, Moo<Expression>, Atom),
655
656 #[compatible(Minion)]
665 MinionReifyImply(Metadata, Moo<Expression>, Atom),
666
667 #[compatible(Minion)]
678 MinionWInIntervalSet(Metadata, Atom, Vec<i32>),
679
680 #[compatible(Minion)]
692 MinionWInSet(Metadata, Atom, Vec<i32>),
693
694 #[compatible(Minion)]
703 MinionElementOne(Metadata, Vec<Atom>, Moo<Atom>, Moo<Atom>),
704
705 #[compatible(Minion)]
709 #[polyquine_skip]
710 AuxDeclaration(Metadata, Reference, Moo<Expression>),
711
712 #[compatible(SAT)]
714 SATInt(Metadata, SATIntEncoding, Moo<Expression>, (i32, i32)),
715 #[compatible(SAT)]
717 SatObjective(Metadata, bool, Moo<Expression>),
718
719 #[compatible(SMT)]
722 PairwiseSum(Metadata, Moo<Expression>, Moo<Expression>),
723
724 #[compatible(SMT)]
727 PairwiseProduct(Metadata, Moo<Expression>, Moo<Expression>),
728
729 #[compatible(JsonInput)]
730 Image(Metadata, Moo<Expression>, Moo<Expression>),
731
732 #[compatible(JsonInput)]
733 ImageSet(Metadata, Moo<Expression>, Moo<Expression>),
734
735 #[compatible(JsonInput)]
736 PreImage(Metadata, Moo<Expression>, Moo<Expression>),
737
738 #[compatible(JsonInput)]
739 Inverse(Metadata, Moo<Expression>, Moo<Expression>),
740
741 #[compatible(JsonInput)]
745 PermInverse(Metadata, Moo<Expression>),
746
747 #[compatible(JsonInput)]
750 Compose(Metadata, Moo<Expression>, Moo<Expression>),
751
752 #[compatible(JsonInput)]
753 Restrict(Metadata, Moo<Expression>, Moo<Expression>),
754
755 LexLt(Metadata, Moo<Expression>, Moo<Expression>),
764
765 LexLeq(Metadata, Moo<Expression>, Moo<Expression>),
767
768 LexGt(Metadata, Moo<Expression>, Moo<Expression>),
771
772 LexGeq(Metadata, Moo<Expression>, Moo<Expression>),
775
776 FlatLexLt(Metadata, Vec<Atom>, Vec<Atom>),
778
779 FlatLexLeq(Metadata, Vec<Atom>, Vec<Atom>),
781
782 #[compatible(JsonInput)]
784 RelationProj(Metadata, Moo<Expression>, Vec<Option<Expression>>),
785
786 #[compatible(JsonInput)]
788 Card(Metadata, Moo<Expression>),
789}
790
791impl Expression {
792 pub fn domain_of(&self) -> Option<DomainPtr> {
800 self.meta_ref().domain_or_init(|| self.domain_of_uncached())
801 }
802
803 pub(crate) fn domain_of_uncached(&self) -> Option<DomainPtr> {
809 match self {
810 Expression::Union(_, a, b) => {
811 let lhs = a.domain_of()?;
812 let rhs = b.domain_of()?;
813 set_operation_domain(a, b, SetOperation::Union)
814 .or_else(|| mset_union_result_domain(a, b))
815 .or_else(|| lhs.union(&rhs).ok())
816 }
817 Expression::Intersect(_, a, b) => set_operation_domain(a, b, SetOperation::Intersect)
818 .or_else(|| a.domain_of()?.intersect(&b.domain_of()?).ok()),
819 Expression::Difference(_, a, b) => set_operation_domain(a, b, SetOperation::Difference),
820 Expression::In(_, _, _) => Some(Domain::bool()),
821 Expression::Supset(_, _, _) => Some(Domain::bool()),
822 Expression::SupsetEq(_, _, _) => Some(Domain::bool()),
823 Expression::Subset(_, _, _) => Some(Domain::bool()),
824 Expression::SubsetEq(_, _, _) => Some(Domain::bool()),
825 Expression::AbstractLiteral(_, abslit) => abslit.domain_of(),
826 Expression::DominanceRelation(_, _) => Some(Domain::bool()),
827 Expression::FromSolution(_, expr) => Some(expr.domain_of()),
828 Expression::Metavar(_, _) => None,
829 Expression::Comprehension(_, comprehension) => comprehension.domain_of(),
830 Expression::RecordField(_, rec, field_name) => {
831 let rec_ents = rec.domain_of()?.as_record()?;
832 for ent in rec_ents {
833 if ent.name.eq(field_name) {
834 return Some(ent.value);
835 }
836 }
837 None
838 }
839 Expression::UnsafeIndex(_, matrix, index) | Expression::SafeIndex(_, matrix, index) => {
840 let dom = matrix.domain_of()?;
841 let resolved_dom = dom.resolve().ok().map(Domain::Ground);
842 if dom.as_matrix().is_some()
843 || resolved_dom
844 .as_ref()
845 .is_some_and(|dom| dom.as_matrix().is_some())
846 {
847 let mut current = dom;
852 let mut remaining = index.len();
853 while remaining > 0 {
854 let resolved = current.resolve().ok().map(Domain::Ground);
855 let Some((elem_domain, idx_domains)) = current
856 .as_matrix()
857 .or_else(|| resolved.as_ref()?.as_matrix())
858 else {
859 break;
860 };
861 if idx_domains.len() > remaining {
864 return Some(Domain::matrix(
865 elem_domain,
866 idx_domains[remaining..].to_vec(),
867 ));
868 }
869 remaining -= idx_domains.len();
870 current = elem_domain;
871 }
872 return Some(current);
873 }
874
875 if let Some(components) =
879 dom.as_tuple().or_else(|| resolved_dom.as_ref()?.as_tuple())
880 {
881 let Expression::Atomic(_, Atom::Literal(Literal::Int(index))) =
882 index.first()?
883 else {
884 return None;
885 };
886 let index: usize = (*index - 1).try_into().ok()?;
887 return components.get(index).cloned();
888 }
889
890 if let Some(doms) = dom.as_variant().or(dom.as_record()).or_else(|| {
891 let resolved_dom = resolved_dom.as_ref()?;
892 resolved_dom.as_variant().or(resolved_dom.as_record())
893 }) {
894 let index_expr = index.first()?;
895 return match index_expr {
896 Expression::Atomic(_, Atom::Reference(reference)) => {
897 for inner_dom in doms {
898 if *reference.name() == inner_dom.name {
899 return Some(inner_dom.value);
900 }
901 }
902 None
903 }
904 Expression::Atomic(_, Atom::Literal(Literal::Int(index))) => {
905 let index: usize = (*index - 1).try_into().ok()?;
906 doms.get(index).map(|inner_dom| inner_dom.value.clone())
907 }
908 _ => None,
909 };
910 }
911
912 bug!(
913 "subject of an index operation should support indexing, but got {matrix}: {dom}"
914 )
915 }
916 Expression::UnsafeSlice(_, matrix, indices)
917 | Expression::SafeSlice(_, matrix, indices) => {
918 let sliced_dimension = indices.iter().position(Option::is_none);
919
920 let dom = matrix.domain_of()?;
921 let Some((elem_domain, index_domains)) = dom.as_matrix() else {
922 bug!("subject of an index operation should be a matrix");
923 };
924
925 match sliced_dimension {
926 Some(dimension) => Some(Domain::matrix(
927 elem_domain,
928 vec![index_domains[dimension].clone()],
929 )),
930
931 None => Some(elem_domain),
933 }
934 }
935 Expression::InDomain(_, _, _) => Some(Domain::bool()),
936 Expression::Atomic(_, atom) => Some(atom.domain_of()),
937 Expression::TypeAnnotation(_, expr, _) => expr.domain_of(),
938 Expression::DomainAnnotation(_, _, domain) => Some(domain.clone()),
939 Expression::Sum(_, e) => sum_domain_of_child(e).or_else(|| {
940 bounded_i32_domain_for_matrix_literal_monotonic(e, i32::checked_add)
942 }),
943 Expression::Product(_, e) => {
944 bounded_i32_domain_for_matrix_literal_monotonic(e, i32::checked_mul)
947 }
948 Expression::Min(_, e) => {
949 if empty_matrix_integer_element_domain(e).is_some() {
950 return Some(Domain::empty(ReturnType::Int));
951 }
952 bounded_i32_domain_for_matrix_literal_monotonic(e, |x, y| {
953 Some(if x < y { x } else { y })
954 })
955 .or_else(|| matrix_element_domain(e))
956 }
957 Expression::Max(_, e) => {
958 if empty_matrix_integer_element_domain(e).is_some() {
959 return Some(Domain::empty(ReturnType::Int));
960 }
961 bounded_i32_domain_for_matrix_literal_monotonic(e, |x, y| {
962 Some(if x > y { x } else { y })
963 })
964 .or_else(|| matrix_element_domain(e))
965 }
966 Expression::Pred(_, operand) | Expression::Succ(_, operand) => {
967 let domain = operand.domain_of()?.resolve().ok()?;
968 if !matches!(domain.as_ref(), GroundDomain::EnumeratedType(_, _)) {
969 return None;
970 }
971 let values = domain
972 .values()
973 .ok()?
974 .filter_map(|value| {
975 let Literal::EnumVariant(value) = value else {
976 return None;
977 };
978 let neighbour = if matches!(self, Expression::Pred(_, _)) {
979 value.pred()
980 } else {
981 value.succ()
982 };
983 neighbour.map(Literal::EnumVariant)
984 })
985 .collect::<Vec<_>>();
986 if values.is_empty() {
987 Some(Domain::empty(operand.return_type()))
988 } else {
989 GroundDomain::from_literal_vec(&values)
990 .ok()
991 .map(DomainPtr::from)
992 }
993 }
994 Expression::UnsafeDiv(_, a, b) => division_domain(a, b, false),
995 Expression::CatchUndef(_, a, b) => {
997 let inner = a.domain_of()?;
998 let default = b.domain_of()?;
999 inner.union(&default).ok()
1000 }
1001 Expression::SafeDiv(_, a, b) => division_domain(a, b, true),
1002 Expression::UnsafeMod(_, a, b) => modulo_domain(a, b, false),
1003 Expression::SafeMod(_, a, b) => modulo_domain(a, b, true),
1004 Expression::SafePow(_, a, b) | Expression::UnsafePow(_, a, b) => {
1005 power_integer_domain(a, b)
1006 }
1007 Expression::Root(_, _) => None,
1008 Expression::Bubble(_, inner, _) => inner.domain_of(),
1009 Expression::AuxDeclaration(_, _, _) => Some(Domain::bool()),
1010 Expression::And(_, _) => Some(Domain::bool()),
1011 Expression::Not(_, _) => Some(Domain::bool()),
1012 Expression::Or(_, _) => Some(Domain::bool()),
1013 Expression::Imply(_, _, _) => Some(Domain::bool()),
1014 Expression::Iff(_, _, _) => Some(Domain::bool()),
1015 Expression::Eq(_, _, _) => Some(Domain::bool()),
1016 Expression::Neq(_, _, _) => Some(Domain::bool()),
1017 Expression::Geq(_, _, _) => Some(Domain::bool()),
1018 Expression::Leq(_, _, _) => Some(Domain::bool()),
1019 Expression::Gt(_, _, _) => Some(Domain::bool()),
1020 Expression::Lt(_, _, _) => Some(Domain::bool()),
1021 Expression::Factorial(_, a) => factorial_domain(a),
1022 Expression::FlatAbsEq(_, _, _) => Some(Domain::bool()),
1023 Expression::FlatMinEq(_, _, _) => Some(Domain::bool()),
1024 Expression::FlatSumGeq(_, _, _) => Some(Domain::bool()),
1025 Expression::FlatSumLeq(_, _, _) => Some(Domain::bool()),
1026 Expression::MinionDivEqUndefZero(_, _, _, _) => Some(Domain::bool()),
1027 Expression::MinionModuloEqUndefZero(_, _, _, _) => Some(Domain::bool()),
1028 Expression::FlatIneq(_, _, _, _) => Some(Domain::bool()),
1029 Expression::Flatten(_, n, m) => {
1030 if let Some(expr) = n {
1031 if expr.return_type() == ReturnType::Int {
1032 return None;
1034 }
1035 } else {
1036 let dom = m.domain_of()?.resolve().ok()?;
1038 let (val_dom, idx_doms) = match dom.as_ref() {
1039 GroundDomain::Matrix(val, idx, _) => (val, idx),
1040 _ => return None,
1041 };
1042 let num_elems = matrix::num_elements(idx_doms).ok()? as i32;
1043
1044 let new_index_domain = Domain::int(vec![Range::Bounded(1, num_elems)]);
1045 return Some(Domain::matrix(
1046 val_dom.clone().into(),
1047 vec![new_index_domain],
1048 ));
1049 }
1050 None
1051 }
1052 Expression::AllDiff(_, _) => Some(Domain::bool()),
1053 Expression::SmtDistinct(_, _) => Some(Domain::bool()),
1054 Expression::AllDifferentExcept(_, _, _) => Some(Domain::bool()),
1055 Expression::ElementId(_, matrix, index) => {
1056 let lookup = Expression::UnsafeIndex(
1057 Metadata::new(),
1058 matrix.clone(),
1059 vec![(**index).clone()],
1060 );
1061 let numeric = |domain: DomainPtr| {
1062 if domain.is_bool() {
1063 Some(Domain::int(vec![Range::Bounded(0, 1)]))
1064 } else if domain.is_int() {
1065 Some(domain)
1066 } else {
1067 None
1068 }
1069 };
1070 if matches!(matrix.as_ref(), Expression::Atomic(_, Atom::Literal(Literal::AbstractLiteral(AbstractLiteral::Matrix(entries, _)))) if entries.is_empty())
1071 || matrix
1072 .unwrap_matrix_unchecked_ref()
1073 .is_some_and(|(entries, _)| entries.is_empty())
1074 {
1075 return numeric(index.domain_of()?);
1076 }
1077 numeric(lookup.domain_of()?)?
1078 .union(&numeric(index.domain_of()?)?)
1079 .ok()
1080 }
1081 Expression::IndexOf(_, matrix, value) => {
1082 let dom = matrix.domain_of()?.resolve().ok()?;
1083 let idx_doms = match dom.as_ref() {
1084 GroundDomain::Matrix(_, idx, _) => idx,
1085 _ => return None,
1086 };
1087 if let [idx_dom] = idx_doms.as_slice() {
1088 let index_domain = Domain::Ground(idx_dom.clone());
1089 if let Some(n) = matrix.list_len() {
1090 if n > 0 {
1091 return Some(Domain::int(vec![Range::Bounded(1, n as i32)]));
1092 }
1093 Some(Moo::new(index_domain))
1094 } else {
1095 let matrix_is_literal = matches!(
1096 matrix.as_ref(),
1097 Expression::Atomic(_, Atom::Literal(_))
1098 | Expression::AbstractLiteral(_, _)
1099 );
1100 if !matrix_is_literal || eval_constant(value.as_ref()).is_none() {
1101 value
1102 .domain_of()
1103 .and_then(|value_domain| index_domain.union(&value_domain).ok())
1104 .map(Moo::new)
1105 .or_else(|| Some(Moo::new(index_domain)))
1106 } else {
1107 Some(Moo::new(index_domain))
1108 }
1109 }
1110 } else {
1111 let num_elems = matrix::num_elements(idx_doms).ok()? as i32;
1112 Some(Domain::int(vec![Range::Bounded(1, num_elems)]))
1113 }
1114 }
1115 Expression::SatElement(_, _, _, _) | Expression::SatAllDifferentComparisons(_, _) => {
1116 Some(Domain::bool())
1117 }
1118 Expression::Table(_, _, _)
1119 | Expression::FlatTable(..)
1120 | Expression::FlatShortTable(..)
1121 | Expression::NegativeTable(_, _, _)
1122 | Expression::ShortTable(_, _, _) => Some(Domain::bool()),
1123 Expression::AtLeast(_, _, _, _) => Some(Domain::bool()),
1124 Expression::AtMost(_, _, _, _) => Some(Domain::bool()),
1125 Expression::Gcc(_, _, _, _) | Expression::GccWeak(_, _, _, _) => Some(Domain::bool()),
1126 Expression::FlatWatchedLiteral(_, _, _) => Some(Domain::bool()),
1127 Expression::MinionReify(_, _, _) => Some(Domain::bool()),
1128 Expression::MinionReifyImply(_, _, _) => Some(Domain::bool()),
1129 Expression::MinionWInIntervalSet(_, _, _) => Some(Domain::bool()),
1130 Expression::MinionWInSet(_, _, _) => Some(Domain::bool()),
1131 Expression::MinionElementOne(_, _, _, _) => Some(Domain::bool()),
1132 Expression::Neg(_, x) => {
1133 let dom = x.domain_of()?;
1134 let mut ranges = dom.as_int()?;
1135
1136 ranges = ranges
1137 .into_iter()
1138 .map(|r| match r {
1139 Range::Single(x) => Range::Single(-x),
1140 Range::Bounded(x, y) => Range::Bounded(-y, -x),
1141 Range::UnboundedR(i) => Range::UnboundedL(-i),
1142 Range::UnboundedL(i) => Range::UnboundedR(-i),
1143 Range::Unbounded => Range::Unbounded,
1144 })
1145 .collect();
1146
1147 Some(Domain::int(ranges))
1148 }
1149 Expression::Minus(_, a, b) => {
1150 let a_resolved = a.domain_of()?.resolve().ok()?;
1151 let b_resolved = b.domain_of()?.resolve().ok()?;
1152 if matches!(
1153 a_resolved.as_ref(),
1154 GroundDomain::Int(_, _) | GroundDomain::Empty(ReturnType::Int)
1155 ) && matches!(
1156 b_resolved.as_ref(),
1157 GroundDomain::Int(_, _) | GroundDomain::Empty(ReturnType::Int)
1158 ) {
1159 binary_integer_domain(a, b, i32::checked_sub)
1160 } else if matches!(a_resolved.as_ref(), GroundDomain::Set(_, _))
1161 && matches!(b_resolved.as_ref(), GroundDomain::Set(_, _))
1162 {
1163 set_operation_domain(a, b, SetOperation::Difference)
1164 } else {
1165 None
1166 }
1167 }
1168 Expression::FlatAllDiff(_, _) => Some(Domain::bool()),
1169 Expression::FlatMinusEq(_, _, _) => Some(Domain::bool()),
1170 Expression::FlatProductEq(_, _, _, _) => Some(Domain::bool()),
1171 Expression::FlatWeightedSumLeq(_, _, _, _) => Some(Domain::bool()),
1172 Expression::FlatWeightedSumGeq(_, _, _, _) => Some(Domain::bool()),
1173 Expression::Abs(_, a) => absolute_integer_domain(a),
1174 Expression::MinionPow(_, _, _, _) => Some(Domain::bool()),
1175 Expression::ToInt(_, _) => Some(Domain::int(vec![Range::Bounded(0, 1)])),
1176 Expression::SatObjective(..) => Some(Domain::bool()),
1177 Expression::SATInt(_, _, _, (low, high)) => {
1178 Some(Domain::int_ground(vec![Range::Bounded(*low, *high)]))
1179 }
1180 Expression::PairwiseSum(_, a, b) => binary_integer_domain(a, b, i32::checked_add),
1181 Expression::PairwiseProduct(_, a, b) => binary_integer_domain(a, b, i32::checked_mul),
1182 Expression::Defined(_, function) => defined_domain(function),
1183 Expression::Range(_, function) => range_domain(function),
1184 Expression::Image(_, function, _) => get_function_codomain(function),
1185 Expression::PermInverse(_, perm) => perm.domain_of(),
1186 Expression::Compose(_, g, _h) => g.domain_of(),
1187 Expression::ImageSet(_, function, argument) => image_set_domain(function, argument)
1188 .or_else(|| {
1189 get_function_codomain(function)
1190 .map(|inner| Domain::set(SetAttr::new(Range::Bounded(0, 1)), inner))
1191 }),
1192 Expression::PreImage(_, function, image) => pre_image_domain(function, image),
1193 Expression::Restrict(_, function, new_domain) => {
1194 restricted_domain(function, new_domain)
1195 }
1196 Expression::Subsequence(_, _, _) => Some(Domain::bool()),
1197 Expression::Substring(_, _, _) => Some(Domain::bool()),
1198 Expression::AttributeAsConstraint(_, _, _, _) => Some(Domain::bool()),
1199 Expression::Inverse(..) => Some(Domain::bool()),
1200 Expression::LexLt(..) => Some(Domain::bool()),
1201 Expression::LexLeq(..) => Some(Domain::bool()),
1202 Expression::LexGt(..) => Some(Domain::bool()),
1203 Expression::LexGeq(..) => Some(Domain::bool()),
1204 Expression::FlatLexLt(..) => Some(Domain::bool()),
1205 Expression::FlatLexLeq(..) => Some(Domain::bool()),
1206 Expression::Active(..) => Some(Domain::bool()),
1207 Expression::ToSet(_, other) => {
1208 if let Some((attrs, dom, codom)) = other.domain_of()?.as_function() {
1209 Some(bounded_set(
1210 function_size(&attrs, &dom, &codom),
1211 Domain::tuple(vec![dom, codom]),
1212 ))
1213 } else if let Some((_, doms)) = other.domain_of()?.as_relation() {
1214 let size = collection_size(&other.domain_of()?)?;
1215 Some(bounded_set(size, Domain::tuple(doms)))
1216 } else if let Some((attrs, dom)) = other.domain_of()?.as_mset() {
1217 let size = mset_size(&attrs, &dom);
1218 let occurrence = SizeBounds::from_size(&attrs.occurrence);
1219 if size.range().is_none() || occurrence.range().is_none() {
1220 return Some(Domain::empty(ReturnType::Set(Box::new(dom.return_type()))));
1221 }
1222 Some(bounded_set(distinct_size(size, occurrence), dom))
1223 } else if let Some((dom, dimensions)) = other.domain_of()?.as_matrix() {
1224 if dimensions.len() != 1 {
1226 return None;
1227 }
1228 let size = collection_size(&other.domain_of()?)?;
1229 Some(bounded_set(
1230 distinct_size(size, SizeBounds::new(1, None)),
1231 dom,
1232 ))
1233 } else {
1234 bug!(
1235 "Domain of {self} needed to be a function, relation, mset, or matrix for ToSet"
1236 )
1237 }
1238 }
1239 Expression::ToMSet(_, other) => {
1240 if let Some((attrs, dom, codom)) = other.domain_of()?.as_function() {
1241 let set_attrs = MSetAttr {
1242 size: function_size(&attrs, &dom, &codom).range()?.into(),
1243 occurrence: Range::Single(IntVal::Const(1)),
1244 representation: None,
1245 };
1246 Some(Domain::mset(set_attrs, Domain::tuple(vec![dom, codom])))
1247 } else if let Some((attrs, doms)) = other.domain_of()?.as_relation() {
1248 let set_attrs = MSetAttr {
1249 size: attrs.size,
1250 occurrence: Range::Single(IntVal::Const(1)),
1251 representation: None,
1252 };
1253 Some(Domain::mset(set_attrs, Domain::tuple(doms)))
1254 } else if let Some((attrs, dom)) = other.domain_of()?.as_set() {
1255 let set_attrs = MSetAttr {
1256 size: attrs.size,
1257 occurrence: Range::Single(IntVal::Const(1)),
1258 representation: None,
1259 };
1260 Some(Domain::mset(set_attrs, dom))
1261 } else {
1262 bug!("Domain of {self} needed to be a function, relation, or set for ToMSet")
1263 }
1264 }
1265 Expression::ToRelation(_, function) => {
1266 let (attrs, domain, codomain) = function.domain_of()?.as_function()?;
1267 let rel_attrs = RelAttr {
1269 size: function_size(&attrs, &domain, &codomain).range()?,
1270 binary: vec![],
1271 representation: None,
1273 };
1274 Some(Domain::relation(rel_attrs, vec![domain, codomain]))
1275 }
1276 Expression::RelationProj(_, relation, projections) => {
1277 let (_, domains) = relation.domain_of()?.as_relation()?;
1278 let new_doms = domains
1279 .iter()
1280 .zip(projections.iter())
1281 .filter_map(|(domain, included)| {
1282 if included.is_none() {
1283 Some(domain.clone())
1285 } else {
1286 None
1287 }
1288 })
1289 .collect();
1290 Some(Domain::relation(RelAttr::<IntVal>::default(), new_doms))
1291 }
1292 Expression::Apart(_, _, _) => Some(Domain::bool()),
1293 Expression::Together(_, _, _) => Some(Domain::bool()),
1294 Expression::Participants(_, p) => {
1295 let (attr, inner) = p.domain_of()?.as_partition()?;
1297 let len = inner.length_signed().ok()?;
1298
1299 let p_parts = attr.resolve().ok()?.num_parts;
1300 let p_card = attr.resolve().ok()?.part_len;
1301
1302 match (p_parts.low(), p_parts.high(), p_card.low(), p_card.high()) {
1304 (Some(p), Some(q), Some(r), Some(s)) => {
1305 let lo = p * r;
1306 let hi = q * s;
1307 if len < lo || len > hi {
1308 return Some(Domain::empty(ReturnType::Set(Box::new(
1309 inner.return_type(),
1310 ))));
1311 }
1312 }
1313
1314 (None, Some(q), None, Some(s)) => {
1315 let hi = q * s;
1316 if len > hi {
1317 return Some(Domain::empty(ReturnType::Set(Box::new(
1318 inner.return_type(),
1319 ))));
1320 }
1321 }
1322
1323 (Some(p), None, Some(r), None) => {
1324 let lo = p * r;
1325 if len < lo {
1326 return Some(Domain::empty(ReturnType::Set(Box::new(
1327 inner.return_type(),
1328 ))));
1329 }
1330 }
1331
1332 _ => {}
1333 }
1334
1335 Some(Domain::set(
1336 SetAttr::new_size(len),
1337 Domain::int(inner.as_int()?),
1338 ))
1339 }
1340 Expression::Party(_, _, p) => {
1341 let (attr, inner) = p.domain_of()?.as_partition()?;
1343
1344 Some(Domain::set(SetAttr::new(attr.part_len), inner))
1345 }
1346 Expression::Parts(_, p) => {
1347 let (attr, inner) = p.domain_of()?.as_partition()?;
1348
1349 Some(Domain::set(
1350 SetAttr::new(attr.num_parts.clone()),
1351 Domain::set(SetAttr::new(attr.part_len), inner),
1352 ))
1353 }
1354 Expression::Card(_, collection) => {
1355 let domain = collection.domain_of()?;
1356 if matches!(domain.as_ground(), Some(GroundDomain::Empty(_))) {
1357 Some(Domain::empty(ReturnType::Int))
1358 } else if let Some(bounds) = collection_size(&domain) {
1359 Some(match bounds.range() {
1360 Some(size) => Domain::int(vec![size]),
1361 None => Domain::empty(ReturnType::Int),
1362 })
1363 } else if let Some((attrs, dom, codom)) = domain.as_function() {
1364 Some(match function_size(&attrs, &dom, &codom).range() {
1365 Some(size) => Domain::int(vec![size]),
1366 None => Domain::empty(ReturnType::Int),
1367 })
1368 } else if let Some((_attrs, inner)) = domain.as_partition() {
1369 match inner.length_signed() {
1374 Ok(length) => Some(Domain::int(vec![Range::Single(length)])),
1375 Err(_) => None,
1376 }
1377 } else {
1378 bug!(
1379 "Domain of {self} needed to be a matrix, set, mset, sequence, relation, function, or partition for cardinality"
1380 )
1381 }
1382 }
1383 }
1384 }
1385
1386 pub fn meta_ref(&self) -> &Metadata {
1388 macro_rules! match_meta_ref {
1389 ($($variant:ident),* $(,)?) => {
1390 match self {
1391 $(Expression::$variant(meta, ..) => meta,)*
1392 }
1393 };
1394 }
1395 match_meta_ref!(
1396 AbstractLiteral,
1397 Root,
1398 Bubble,
1399 Comprehension,
1400 DominanceRelation,
1401 TypeAnnotation,
1402 DomainAnnotation,
1403 FromSolution,
1404 Metavar,
1405 Atomic,
1406 RecordField,
1407 UnsafeIndex,
1408 SafeIndex,
1409 SatElement,
1410 SatAllDifferentComparisons,
1411 UnsafeSlice,
1412 SafeSlice,
1413 InDomain,
1414 ToInt,
1415 Abs,
1416 Sum,
1417 Product,
1418 Min,
1419 Max,
1420 Not,
1421 Or,
1422 And,
1423 Imply,
1424 Iff,
1425 Union,
1426 Difference,
1427 In,
1428 Intersect,
1429 Supset,
1430 SupsetEq,
1431 Subset,
1432 SubsetEq,
1433 Eq,
1434 Neq,
1435 Geq,
1436 Leq,
1437 Gt,
1438 Lt,
1439 CatchUndef,
1440 SafeDiv,
1441 UnsafeDiv,
1442 SafeMod,
1443 UnsafeMod,
1444 Apart,
1445 Together,
1446 Participants,
1447 Party,
1448 Parts,
1449 Neg,
1450 Defined,
1451 Range,
1452 UnsafePow,
1453 SafePow,
1454 Flatten,
1455 AttributeAsConstraint,
1456 AllDiff,
1457 SmtDistinct,
1458 AllDifferentExcept,
1459 ElementId,
1460 IndexOf,
1461 Minus,
1462 Factorial,
1463 FlatAbsEq,
1464 FlatAllDiff,
1465 FlatTable,
1466 FlatShortTable,
1467 FlatMinEq,
1468 FlatSumGeq,
1469 FlatSumLeq,
1470 FlatIneq,
1471 FlatWatchedLiteral,
1472 FlatWeightedSumLeq,
1473 FlatWeightedSumGeq,
1474 FlatMinusEq,
1475 FlatProductEq,
1476 MinionDivEqUndefZero,
1477 MinionModuloEqUndefZero,
1478 MinionPow,
1479 MinionReify,
1480 MinionReifyImply,
1481 MinionWInIntervalSet,
1482 MinionWInSet,
1483 MinionElementOne,
1484 AuxDeclaration,
1485 SATInt,
1486 SatObjective,
1487 PairwiseSum,
1488 PairwiseProduct,
1489 Image,
1490 ImageSet,
1491 PreImage,
1492 Inverse,
1493 PermInverse,
1494 Compose,
1495 Restrict,
1496 LexLt,
1497 LexLeq,
1498 LexGt,
1499 LexGeq,
1500 FlatLexLt,
1501 FlatLexLeq,
1502 NegativeTable,
1503 ShortTable,
1504 Table,
1505 AtLeast,
1506 AtMost,
1507 Gcc,
1508 GccWeak,
1509 Active,
1510 ToSet,
1511 ToMSet,
1512 ToRelation,
1513 RelationProj,
1514 Pred,
1515 Succ,
1516 Card,
1517 Subsequence,
1518 Substring,
1519 )
1520 }
1521
1522 pub fn get_meta(&self) -> Metadata {
1523 let metas: VecDeque<Metadata> = self.children_bi();
1524 metas[0].clone()
1525 }
1526
1527 pub fn set_meta(&self, meta: Metadata) {
1528 self.transform_bi(&|_| meta.clone());
1529 }
1530
1531 pub fn is_safe(&self) -> bool {
1538 !self.any_expression(|expr| {
1540 matches!(
1541 expr,
1542 Expression::UnsafeDiv(_, _, _)
1543 | Expression::UnsafeMod(_, _, _)
1544 | Expression::UnsafePow(_, _, _)
1545 | Expression::UnsafeIndex(_, _, _)
1546 | Expression::Bubble(_, _, _)
1547 | Expression::UnsafeSlice(_, _, _)
1548 | Expression::Pred(_, _)
1549 | Expression::Succ(_, _)
1550 ) || matches!(expr, Expression::Image(_, subject, argument)
1551 if image_can_be_undefined(subject, argument))
1552 })
1553 }
1554
1555 pub fn is_associative_commutative_operator(&self) -> bool {
1557 TryInto::<ACOperatorKind>::try_into(self).is_ok()
1558 }
1559
1560 pub fn is_matrix_literal(&self) -> bool {
1565 matches!(
1566 self,
1567 Expression::AbstractLiteral(_, AbstractLiteral::Matrix(_, _))
1568 | Expression::Atomic(
1569 _,
1570 Atom::Literal(Literal::AbstractLiteral(AbstractLiteral::Matrix(_, _))),
1571 )
1572 )
1573 }
1574
1575 pub fn identical_atom_to(&self, other: &Expression) -> bool {
1581 let atom1: Result<&Atom, _> = self.try_into();
1582 let atom2: Result<&Atom, _> = other.try_into();
1583
1584 if let (Ok(atom1), Ok(atom2)) = (atom1, atom2) {
1585 atom2 == atom1
1586 } else {
1587 false
1588 }
1589 }
1590
1591 pub fn unwrap_list_ref(&self) -> Option<&[Expression]> {
1599 match self {
1600 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
1601 expr.unwrap_list_ref()
1602 }
1603 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => {
1604 matrix.unwrap_list().map(Vec::as_slice)
1605 }
1606 _ => None,
1607 }
1608 }
1609
1610 pub fn unwrap_list_cow(&self) -> Option<Cow<'_, [Expression]>> {
1621 match self {
1622 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
1623 expr.unwrap_list_cow()
1624 }
1625 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => matrix
1626 .unwrap_list()
1627 .map(|elems| Cow::Borrowed(elems.as_slice())),
1628 Expression::Atomic(
1629 _,
1630 Atom::Literal(Literal::AbstractLiteral(matrix @ AbstractLiteral::Matrix(_, _))),
1631 ) => matrix.unwrap_list().map(|elems| {
1632 Cow::Owned(
1633 elems
1634 .iter()
1635 .cloned()
1636 .map(|literal| Expression::Atomic(Metadata::new(), Atom::Literal(literal)))
1637 .collect(),
1638 )
1639 }),
1640 _ => None,
1641 }
1642 }
1643
1644 pub fn list_len(&self) -> Option<usize> {
1649 match self {
1650 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
1651 expr.list_len()
1652 }
1653 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => {
1654 matrix.unwrap_list().map(Vec::len)
1655 }
1656 Expression::Atomic(
1657 _,
1658 Atom::Literal(Literal::AbstractLiteral(matrix @ AbstractLiteral::Matrix(_, _))),
1659 ) => matrix.unwrap_list().map(Vec::len),
1660 _ => None,
1661 }
1662 }
1663
1664 pub fn is_list(&self) -> bool {
1666 self.list_len().is_some()
1667 }
1668
1669 pub fn unwrap_list(&self) -> Option<Vec<Expression>> {
1679 match self {
1680 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
1681 expr.unwrap_list()
1682 }
1683 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => {
1684 matrix.unwrap_list().cloned()
1685 }
1686 Expression::Atomic(
1687 _,
1688 Atom::Literal(Literal::AbstractLiteral(matrix @ AbstractLiteral::Matrix(_, _))),
1689 ) => matrix.unwrap_list().map(|elems| {
1690 elems
1691 .clone()
1692 .into_iter()
1693 .map(|x: Literal| Expression::Atomic(Metadata::new(), Atom::Literal(x)))
1694 .collect_vec()
1695 }),
1696 _ => None,
1697 }
1698 }
1699
1700 pub fn into_list(self) -> Option<Vec<Expression>> {
1705 match self {
1706 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
1707 Moo::unwrap_or_clone(expr).into_list()
1708 }
1709 Expression::AbstractLiteral(_, matrix @ AbstractLiteral::Matrix(_, _)) => {
1710 matrix.into_list()
1711 }
1712 Expression::Atomic(
1713 _,
1714 Atom::Literal(Literal::AbstractLiteral(matrix @ AbstractLiteral::Matrix(_, _))),
1715 ) => matrix.into_list().map(|elems| {
1716 elems
1717 .into_iter()
1718 .map(|literal| Expression::Atomic(Metadata::new(), Atom::Literal(literal)))
1719 .collect()
1720 }),
1721 _ => None,
1722 }
1723 }
1724
1725 pub fn unwrap_matrix_unchecked_ref(&self) -> Option<(&[Expression], &DomainPtr)> {
1731 match self {
1732 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
1733 expr.unwrap_matrix_unchecked_ref()
1734 }
1735 Expression::AbstractLiteral(_, AbstractLiteral::Matrix(elems, domain)) => {
1736 Some((elems, domain))
1737 }
1738 _ => None,
1739 }
1740 }
1741
1742 pub fn unwrap_matrix_unchecked(self) -> Option<(Vec<Expression>, DomainPtr)> {
1750 match self {
1751 Expression::TypeAnnotation(_, expr, _) | Expression::DomainAnnotation(_, expr, _) => {
1752 Moo::unwrap_or_clone(expr).unwrap_matrix_unchecked()
1753 }
1754 Expression::AbstractLiteral(_, AbstractLiteral::Matrix(elems, domain)) => {
1755 Some((elems, domain))
1756 }
1757 Expression::Atomic(
1758 _,
1759 Atom::Literal(Literal::AbstractLiteral(AbstractLiteral::Matrix(elems, domain))),
1760 ) => Some((
1761 elems
1762 .into_iter()
1763 .map(|x: Literal| Expression::Atomic(Metadata::new(), Atom::Literal(x)))
1764 .collect_vec(),
1765 domain.into(),
1766 )),
1767
1768 _ => None,
1769 }
1770 }
1771
1772 pub fn extend_root(self, exprs: Vec<Expression>) -> Expression {
1777 match self {
1778 Expression::Root(meta, mut children) => {
1779 children.extend(exprs);
1780 Expression::Root(meta, children)
1781 }
1782 _ => panic!("extend_root called on a non-Root expression"),
1783 }
1784 }
1785
1786 pub fn into_literal(self) -> Option<Literal> {
1788 match self {
1789 Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
1790 Expression::AbstractLiteral(_, abslit) => {
1791 Some(Literal::AbstractLiteral(abslit.into_literals()?))
1792 }
1793 Expression::Neg(_, e) => {
1794 let Literal::Int(i) = Moo::unwrap_or_clone(e).into_literal()? else {
1795 bug!("negated literal should be an int");
1796 };
1797
1798 Some(Literal::Int(-i))
1799 }
1800
1801 _ => None,
1802 }
1803 }
1804
1805 pub fn to_ac_operator_kind(&self) -> Option<ACOperatorKind> {
1807 TryFrom::try_from(self).ok()
1808 }
1809
1810 pub fn try_return_type(&self) -> Option<ReturnType> {
1816 let has_untyped_reference = self.any_expression(|expr| {
1817 matches!(expr, Expression::Atomic(_, Atom::Reference(reference))
1818 if reference.domain().is_none())
1819 });
1820
1821 (!has_untyped_reference).then(|| self.return_type())
1822 }
1823
1824 pub fn universe_categories(&self) -> HashSet<Category> {
1826 let mut categories = HashSet::new();
1827 self.for_each_expression(&mut |expr| {
1828 categories.insert(expr.category_of());
1829 });
1830 categories
1831 }
1832}
1833
1834pub fn image_can_be_undefined(subject: &Expression, argument: &Expression) -> bool {
1846 let Some(domain) = subject.domain_of().and_then(|domain| domain.resolve().ok()) else {
1847 return true;
1848 };
1849
1850 match domain.as_ref() {
1851 GroundDomain::Function(attr, from, _) => {
1852 !matches!(attr.partiality, PartialityAttr::Total) || !argument_always_in(argument, from)
1853 }
1854 GroundDomain::Permutation(_, inner) => !argument_always_in(argument, inner),
1856 GroundDomain::Sequence(attr, _) => {
1857 let min_length = attr.size.low().copied().unwrap_or(0);
1860 min_length <= 0
1861 || !argument_always_in(
1862 argument,
1863 &GroundDomain::Int(vec![Range::Bounded(1, min_length)], None),
1864 )
1865 }
1866 _ => true,
1867 }
1868}
1869
1870fn argument_always_in(argument: &Expression, domain: &GroundDomain) -> bool {
1876 let Some(argument_domain) = argument.domain_of().and_then(|d| d.resolve().ok()) else {
1877 return false;
1878 };
1879
1880 argument_domain
1881 .intersect(domain)
1882 .is_ok_and(|intersection| intersection == *argument_domain.as_ref())
1883}
1884
1885impl TryFrom<&Expression> for i32 {
1886 type Error = ();
1887
1888 fn try_from(value: &Expression) -> Result<Self, Self::Error> {
1889 let Expression::Atomic(_, atom) = value else {
1890 return Err(());
1891 };
1892
1893 let Atom::Literal(lit) = atom else {
1894 return Err(());
1895 };
1896
1897 let Literal::Int(i) = lit else {
1898 return Err(());
1899 };
1900
1901 Ok(*i)
1902 }
1903}
1904
1905impl TryFrom<Expression> for i32 {
1906 type Error = ();
1907
1908 fn try_from(value: Expression) -> Result<Self, Self::Error> {
1909 TryFrom::<&Expression>::try_from(&value)
1910 }
1911}
1912impl From<i32> for Expression {
1913 fn from(i: i32) -> Self {
1914 Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(i)))
1915 }
1916}
1917
1918impl From<bool> for Expression {
1919 fn from(b: bool) -> Self {
1920 Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(b)))
1921 }
1922}
1923
1924impl From<Atom> for Expression {
1925 fn from(value: Atom) -> Self {
1926 Expression::Atomic(Metadata::new(), value)
1927 }
1928}
1929
1930impl From<Literal> for Expression {
1931 fn from(value: Literal) -> Self {
1932 Expression::Atomic(Metadata::new(), value.into())
1933 }
1934}
1935
1936impl From<AbstractLiteral<Expression>> for Expression {
1937 fn from(value: AbstractLiteral<Expression>) -> Self {
1938 Expression::AbstractLiteral(Metadata::new(), value)
1939 }
1940}
1941
1942impl From<Moo<Expression>> for Expression {
1943 fn from(val: Moo<Expression>) -> Self {
1944 val.as_ref().clone()
1945 }
1946}
1947
1948impl CategoryOf for Expression {
1949 fn category_of(&self) -> Category {
1950 let category = self.cata(&move |x,children| {
1952
1953 if let Some(max_category) = children.iter().max() {
1954 *max_category
1957 } else {
1958 let mut max_category = Category::Bottom;
1960
1961 if !Biplate::<Model>::universe_bi(&x).is_empty() {
1968 return Category::Decision;
1970 }
1971
1972 if let Some(max_atom_category) = Biplate::<Atom>::universe_bi(&x).iter().map(|x| x.category_of()).max()
1974 && max_atom_category > max_category{
1976 max_category = max_atom_category;
1978 }
1979
1980 if let Some(max_declaration_category) = Biplate::<DeclarationPtr>::universe_bi(&x).iter().map(|x| x.category_of()).max()
1982 && max_declaration_category > max_category{
1984 max_category = max_declaration_category;
1986 }
1987 max_category
1988
1989 }
1990 });
1991
1992 if cfg!(debug_assertions) {
1993 trace!(
1994 category= %category,
1995 expression= %self,
1996 "Called Expression::category_of()"
1997 );
1998 };
1999 category
2000 }
2001}
2002
2003impl Display for Expression {
2004 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2005 match &self {
2006 Expression::Union(_, box1, box2) => {
2007 write!(f, "({} union {})", box1.clone(), box2.clone())
2008 }
2009 Expression::Difference(_, box1, box2) => {
2010 write!(f, "({} - {})", box1.clone(), box2.clone())
2011 }
2012 Expression::In(_, e1, e2) => {
2013 write!(f, "{e1} in {e2}")
2014 }
2015 Expression::Intersect(_, box1, box2) => {
2016 write!(f, "({} intersect {})", box1.clone(), box2.clone())
2017 }
2018 Expression::Supset(_, box1, box2) => {
2019 write!(f, "({} supset {})", box1.clone(), box2.clone())
2020 }
2021 Expression::SupsetEq(_, box1, box2) => {
2022 write!(f, "({} supsetEq {})", box1.clone(), box2.clone())
2023 }
2024 Expression::Subset(_, box1, box2) => {
2025 write!(f, "({} subset {})", box1.clone(), box2.clone())
2026 }
2027 Expression::SubsetEq(_, box1, box2) => {
2028 write!(f, "({} subsetEq {})", box1.clone(), box2.clone())
2029 }
2030
2031 Expression::AbstractLiteral(_, l) => l.fmt(f),
2032 Expression::Comprehension(_, c) => c.fmt(f),
2033 Expression::UnsafeIndex(_, e1, e2) => write!(f, "{e1}{}", pretty_vec(e2)),
2034 Expression::RecordField(_, r, fld) => {
2035 write!(f, "{r}[{fld}]")
2036 }
2037 Expression::SafeIndex(_, e1, e2) => write!(f, "SafeIndex({e1},{})", pretty_vec(e2)),
2038 Expression::UnsafeSlice(_, e1, es) => {
2039 let args = es
2040 .iter()
2041 .map(|x| match x {
2042 Some(x) => format!("{x}"),
2043 None => "..".into(),
2044 })
2045 .join(",");
2046
2047 write!(f, "{e1}[{args}]")
2048 }
2049 Expression::SafeSlice(_, e1, es) => {
2050 let args = es
2051 .iter()
2052 .map(|x| match x {
2053 Some(x) => format!("{x}"),
2054 None => "..".into(),
2055 })
2056 .join(",");
2057
2058 write!(f, "SafeSlice({e1},[{args}])")
2059 }
2060 Expression::InDomain(_, e, domain) => {
2061 write!(f, "__inDomain({e},{domain})")
2062 }
2063 Expression::Root(_, exprs) => {
2064 write!(f, "{}", pretty_expressions_as_top_level(exprs))
2065 }
2066 Expression::DominanceRelation(_, expr) => write!(f, "DominanceRelation({expr})"),
2067 Expression::FromSolution(_, expr) => write!(f, "FromSolution({expr})"),
2068 Expression::Metavar(_, name) => write!(f, "&{name}"),
2069 Expression::Atomic(_, atom) => atom.fmt(f),
2070 Expression::TypeAnnotation(_, expr, domain) => {
2071 write!(
2072 f,
2073 "{}",
2074 pretty_expression_type_annotation(expr, domain.as_type_string())
2075 )
2076 }
2077 Expression::DomainAnnotation(_, expr, domain) => {
2078 write!(f, "{}", pretty_expression_domain_annotation(expr, domain))
2079 }
2080 Expression::Abs(_, a) | Expression::Card(_, a) => write!(f, "|{a}|"),
2081 Expression::Sum(_, e) => {
2082 write!(f, "sum({e})")
2083 }
2084 Expression::Product(_, e) => {
2085 write!(f, "product({e})")
2086 }
2087 Expression::Min(_, e) => {
2088 write!(f, "min({e})")
2089 }
2090 Expression::Max(_, e) => {
2091 write!(f, "max({e})")
2092 }
2093 Expression::Not(_, expr_box) => {
2094 write!(f, "!({})", expr_box.clone())
2095 }
2096 Expression::Or(_, e) => {
2097 write!(f, "or({e})")
2098 }
2099 Expression::And(_, e) => {
2100 write!(f, "and({e})")
2101 }
2102 Expression::Imply(_, box1, box2) => {
2103 write!(f, "({box1}) -> ({box2})")
2104 }
2105 Expression::Iff(_, box1, box2) => {
2106 write!(f, "({box1}) <-> ({box2})")
2107 }
2108 Expression::Eq(_, box1, box2) => {
2109 write!(f, "{box1} = {box2}")
2110 }
2111 Expression::Neq(_, box1, box2) => {
2112 write!(f, "{box1} != {box2}")
2113 }
2114 Expression::Geq(_, box1, box2) => {
2115 write!(f, "{box1} >= {box2}")
2116 }
2117 Expression::Leq(_, box1, box2) => {
2118 write!(f, "{box1} <= {box2}")
2119 }
2120 Expression::Gt(_, box1, box2) => {
2121 write!(f, "{box1} > {box2}")
2122 }
2123 Expression::Lt(_, box1, box2) => {
2124 write!(f, "{box1} < {box2}")
2125 }
2126 Expression::Apart(_, list, partition) => {
2127 write!(f, "apart({list}, {partition})")
2128 }
2129 Expression::Together(_, list, partition) => {
2130 write!(f, "together({list}, {partition})")
2131 }
2132 Expression::Participants(_, partition) => {
2133 write!(f, "participants({partition})")
2134 }
2135 Expression::Party(_, element, partition) => {
2136 write!(f, "party({element}, {partition})")
2137 }
2138 Expression::Parts(_, partition) => {
2139 write!(f, "parts({partition})")
2140 }
2141 Expression::FlatMinEq(_, vars, result) => {
2142 write!(f, "FlatMinEq({}, {})", pretty_vec(vars), result.clone())
2143 }
2144 Expression::FlatSumGeq(_, box1, box2) => {
2145 write!(f, "SumGeq({}, {})", pretty_vec(box1), box2.clone())
2146 }
2147 Expression::FlatSumLeq(_, box1, box2) => {
2148 write!(f, "SumLeq({}, {})", pretty_vec(box1), box2.clone())
2149 }
2150 Expression::FlatIneq(_, box1, box2, box3) => write!(
2151 f,
2152 "Ineq({}, {}, {})",
2153 box1.clone(),
2154 box2.clone(),
2155 box3.clone()
2156 ),
2157 Expression::Flatten(_, n, m) => {
2158 if let Some(n) = n {
2159 write!(f, "flatten({n}, {m})")
2160 } else {
2161 write!(f, "flatten({m})")
2162 }
2163 }
2164 Expression::AttributeAsConstraint(_, target, attr, val) => {
2165 if let Some(val) = val {
2166 write!(f, "{attr}({target}, {val})")
2167 } else {
2168 write!(f, "{attr}({target})")
2169 }
2170 }
2171 Expression::AllDiff(_, e) => {
2172 write!(f, "allDifferent({e})")
2173 }
2174 Expression::SmtDistinct(_, e) => {
2175 write!(f, "smtDistinct({e})")
2176 }
2177 Expression::AllDifferentExcept(_, matrix, except) => {
2178 write!(f, "allDifferentExcept({matrix}, {except})")
2179 }
2180 Expression::ElementId(_, matrix, value) => {
2181 write!(f, "elementId({matrix}, {value})")
2182 }
2183 Expression::IndexOf(_, matrix, value) => write!(f, "indexOf({matrix}, {value})"),
2184 Expression::SatAllDifferentComparisons(_, conditions) => {
2185 write!(f, "sat-allDifferent-comparisons({conditions})")
2186 }
2187 Expression::SatElement(_, matrix, index, value) => {
2188 write!(f, "satElement({matrix}, {index}, {value})")
2189 }
2190 Expression::FlatShortTable(_, inputs, rows) => {
2191 write!(f, "FlatShortTable({}, {rows:?})", pretty_vec(inputs))
2192 }
2193 Expression::FlatTable(_, inputs, rows, negative) => {
2194 write!(f, "FlatTable({}, {rows:?}, {negative})", pretty_vec(inputs))
2195 }
2196 Expression::Table(_, tuple_expr, rows_expr) => {
2197 write!(f, "table({tuple_expr}, {rows_expr})")
2198 }
2199 Expression::ShortTable(_, tuple_expr, rows_expr) => {
2200 write!(f, "shortTable({tuple_expr}, {rows_expr})")
2201 }
2202 Expression::NegativeTable(_, tuple_expr, rows_expr) => {
2203 write!(f, "negativeTable({tuple_expr}, {rows_expr})")
2204 }
2205 Expression::AtLeast(_, vars, counts, values) => {
2206 write!(f, "atLeast({vars}, {counts}, {values})")
2207 }
2208 Expression::AtMost(_, vars, counts, values) => {
2209 write!(f, "atMost({vars}, {counts}, {values})")
2210 }
2211 Expression::Gcc(_, vars, values, counts) => {
2212 write!(f, "globalCardinality({vars}, {values}, {counts})")
2213 }
2214 Expression::GccWeak(_, vars, values, counts) => {
2215 write!(f, "gccweak({vars}, {values}, {counts})")
2216 }
2217 Expression::Bubble(_, box1, box2) => {
2218 write!(f, "{{{} @ {}}}", box1.clone(), box2.clone())
2219 }
2220 Expression::CatchUndef(_, box1, box2) => {
2221 write!(f, "catchUndef({box1}, {box2})")
2222 }
2223 Expression::SafeDiv(_, box1, box2) => {
2224 write!(f, "SafeDiv({}, {})", box1.clone(), box2.clone())
2225 }
2226 Expression::UnsafeDiv(_, box1, box2) => {
2227 write!(f, "({} / {})", box1.clone(), box2.clone())
2228 }
2229 Expression::UnsafePow(_, box1, box2) => {
2230 write!(f, "({} ** {})", box1.clone(), box2.clone())
2231 }
2232 Expression::SafePow(_, box1, box2) => {
2233 write!(f, "SafePow({}, {})", box1.clone(), box2.clone())
2234 }
2235 Expression::Subsequence(_, s, t) => {
2236 write!(f, "{} subsequence {}", s.clone(), t.clone())
2237 }
2238 Expression::Substring(_, s, t) => {
2239 write!(f, "{} substring {}", s.clone(), t.clone())
2240 }
2241 Expression::MinionDivEqUndefZero(_, box1, box2, box3) => {
2242 write!(
2243 f,
2244 "DivEq({}, {}, {})",
2245 box1.clone(),
2246 box2.clone(),
2247 box3.clone()
2248 )
2249 }
2250 Expression::MinionModuloEqUndefZero(_, box1, box2, box3) => {
2251 write!(
2252 f,
2253 "ModEq({}, {}, {})",
2254 box1.clone(),
2255 box2.clone(),
2256 box3.clone()
2257 )
2258 }
2259 Expression::FlatWatchedLiteral(_, x, l) => {
2260 write!(f, "WatchedLiteral({x},{l})")
2261 }
2262 Expression::MinionReify(_, box1, box2) => {
2263 write!(f, "Reify({}, {})", box1.clone(), box2.clone())
2264 }
2265 Expression::MinionReifyImply(_, box1, box2) => {
2266 write!(f, "ReifyImply({}, {})", box1.clone(), box2.clone())
2267 }
2268 Expression::MinionWInIntervalSet(_, atom, intervals) => {
2269 let intervals = intervals.iter().join(",");
2270 write!(f, "__minion_w_inintervalset({atom},[{intervals}])")
2271 }
2272 Expression::MinionWInSet(_, atom, values) => {
2273 let values = values.iter().join(",");
2274 write!(f, "__minion_w_inset({atom},[{values}])")
2275 }
2276 Expression::AuxDeclaration(_, reference, e) => {
2277 write!(f, "{} =aux {}", reference, e.clone())
2278 }
2279 Expression::UnsafeMod(_, a, b) => {
2280 write!(f, "{} % {}", a.clone(), b.clone())
2281 }
2282 Expression::SafeMod(_, a, b) => {
2283 write!(f, "SafeMod({},{})", a.clone(), b.clone())
2284 }
2285 Expression::Neg(_, a) => {
2286 write!(f, "-({})", a.clone())
2287 }
2288 Expression::Factorial(_, a) => {
2289 write!(f, "({})!", a.clone())
2290 }
2291 Expression::Minus(_, a, b) => {
2292 write!(f, "({} - {})", a.clone(), b.clone())
2293 }
2294 Expression::FlatAllDiff(_, es) => {
2295 write!(f, "__flat_alldiff({})", pretty_vec(es))
2296 }
2297 Expression::FlatAbsEq(_, a, b) => {
2298 write!(f, "AbsEq({},{})", a.clone(), b.clone())
2299 }
2300 Expression::FlatMinusEq(_, a, b) => {
2301 write!(f, "MinusEq({},{})", a.clone(), b.clone())
2302 }
2303 Expression::FlatProductEq(_, a, b, c) => {
2304 write!(
2305 f,
2306 "FlatProductEq({},{},{})",
2307 a.clone(),
2308 b.clone(),
2309 c.clone()
2310 )
2311 }
2312 Expression::FlatWeightedSumLeq(_, cs, vs, total) => {
2313 write!(
2314 f,
2315 "FlatWeightedSumLeq({},{},{})",
2316 pretty_vec(cs),
2317 pretty_vec(vs),
2318 total.clone()
2319 )
2320 }
2321 Expression::FlatWeightedSumGeq(_, cs, vs, total) => {
2322 write!(
2323 f,
2324 "FlatWeightedSumGeq({},{},{})",
2325 pretty_vec(cs),
2326 pretty_vec(vs),
2327 total.clone()
2328 )
2329 }
2330 Expression::MinionPow(_, atom, atom1, atom2) => {
2331 write!(f, "MinionPow({atom},{atom1},{atom2})")
2332 }
2333 Expression::MinionElementOne(_, atoms, atom, atom1) => {
2334 let atoms = atoms.iter().join(",");
2335 write!(f, "__minion_element_one([{atoms}],{atom},{atom1})")
2336 }
2337
2338 Expression::ToInt(_, expr) => {
2339 write!(f, "toInt({expr})")
2340 }
2341
2342 Expression::SatObjective(_, minimise, value) => {
2343 write!(f, "optimise(minimise={minimise}, value={value})")
2344 }
2345 Expression::SATInt(_, encoding, bits, (min, max)) => {
2346 write!(f, "SATInt({encoding:?}, {bits} [{min}, {max}])")
2347 }
2348
2349 Expression::PairwiseSum(_, a, b) => write!(f, "PairwiseSum({a}, {b})"),
2350 Expression::PairwiseProduct(_, a, b) => write!(f, "PairwiseProduct({a}, {b})"),
2351
2352 Expression::Defined(_, function) => write!(f, "defined({function})"),
2353 Expression::Range(_, function) => write!(f, "range({function})"),
2354 Expression::Image(_, function, elems) => write!(f, "image({function},{elems})"),
2355 Expression::ImageSet(_, function, elems) => write!(f, "imageSet({function},{elems})"),
2356 Expression::PreImage(_, function, elems) => write!(f, "preImage({function},{elems})"),
2357 Expression::Inverse(_, a, b) => write!(f, "inverse({a},{b})"),
2358 Expression::PermInverse(_, p) => write!(f, "permInverse({p})"),
2359 Expression::Compose(_, g, h) => write!(f, "compose({g},{h})"),
2360 Expression::Restrict(_, function, domain) => write!(f, "restrict({function},{domain})"),
2361
2362 Expression::LexLt(_, a, b) => write!(f, "({a} <lex {b})"),
2363 Expression::LexLeq(_, a, b) => write!(f, "({a} <=lex {b})"),
2364 Expression::LexGt(_, a, b) => write!(f, "({a} >lex {b})"),
2365 Expression::LexGeq(_, a, b) => write!(f, "({a} >=lex {b})"),
2366 Expression::FlatLexLt(_, a, b) => {
2367 write!(f, "FlatLexLt({}, {})", pretty_vec(a), pretty_vec(b))
2368 }
2369 Expression::FlatLexLeq(_, a, b) => {
2370 write!(f, "FlatLexLeq({}, {})", pretty_vec(a), pretty_vec(b))
2371 }
2372 Expression::Active(_, variant, field_name) => {
2373 write!(f, "active({variant}, {field_name})")
2374 }
2375 Expression::ToSet(_, other) => write!(f, "toSet({other})"),
2376 Expression::ToMSet(_, other) => write!(f, "toMSet({other})"),
2377 Expression::ToRelation(_, function) => write!(f, "toRelation({function})"),
2378 Expression::RelationProj(_, relation, projections) => {
2379 let projections_str = projections
2380 .iter()
2381 .map(|x| {
2382 if let Some(x) = x {
2383 x.to_string()
2384 } else {
2385 String::from("_")
2386 }
2387 })
2388 .join(", ");
2389 write!(f, "{relation}({projections_str})")
2390 }
2391 Expression::Pred(_, ev) => write!(f, "Pred({})", ev),
2392 Expression::Succ(_, ev) => write!(f, "Succ({})", ev),
2393 }
2394 }
2395}
2396
2397fn minus_operand_return_type(expr: &Expression) -> ReturnType {
2398 match expr {
2399 Expression::Atomic(_, Atom::Reference(reference)) => {
2400 let decl_kind = reference.ptr.kind().clone();
2401 match decl_kind {
2402 DeclarationKind::Find(var) | DeclarationKind::FindAuxiliary(var) => {
2403 var.return_type()
2404 }
2405 DeclarationKind::EnumeratedType(ty) => ReturnType::EnumeratedType(ty),
2406 DeclarationKind::UnnamedType(_) => reference.ptr.return_type(),
2407 DeclarationKind::Given(domain)
2408 | DeclarationKind::DomainLetting(domain) => domain.return_type(),
2409 DeclarationKind::Quantified(inner) => inner.domain().return_type(),
2410 DeclarationKind::QuantifiedExpr(inner)
2411 | DeclarationKind::TemporaryValueLetting(inner)
2412 | DeclarationKind::ValueLetting(inner, _) => inner.return_type(),
2414 }
2415 }
2416 _ => expr.return_type(),
2417 }
2418}
2419
2420impl Typeable for Expression {
2421 fn return_type(&self) -> ReturnType {
2422 match self {
2423 Expression::Union(_, subject, _)
2424 | Expression::Intersect(_, subject, _)
2425 | Expression::Difference(_, subject, _) => subject.return_type(),
2426 Expression::In(_, _, _) => ReturnType::Bool,
2427 Expression::Supset(_, _, _) => ReturnType::Bool,
2428 Expression::SupsetEq(_, _, _) => ReturnType::Bool,
2429 Expression::Subset(_, _, _) => ReturnType::Bool,
2430 Expression::SubsetEq(_, _, _) => ReturnType::Bool,
2431 Expression::AbstractLiteral(_, lit) => lit.return_type(),
2432 Expression::RecordField(_, rec, field_name) => {
2433 if let ReturnType::Record(ents) = rec.return_type() {
2434 for Field { name, value } in ents {
2435 if name.eq(field_name) {
2436 return value;
2437 }
2438 }
2439 }
2440 ReturnType::Unknown
2441 }
2442 Expression::UnsafeIndex(_, subject, idx) | Expression::SafeIndex(_, subject, idx) => {
2443 let mut indexed_ty = subject.return_type();
2444 for index in idx {
2445 indexed_ty = match indexed_ty {
2446 ReturnType::Tuple(field_types) => {
2447 let Expression::Atomic(_, Atom::Literal(Literal::Int(index))) = index
2448 else {
2449 return ReturnType::Unknown;
2450 };
2451 let Some(zero_based_index) = index
2452 .checked_sub(1)
2453 .and_then(|index| usize::try_from(index).ok())
2454 else {
2455 return ReturnType::Unknown;
2456 };
2457 field_types
2458 .get(zero_based_index)
2459 .cloned()
2460 .unwrap_or(ReturnType::Unknown)
2461 }
2462 ReturnType::Matrix(element_type) => {
2466 let element_type = *element_type;
2467 if !matches!(element_type, ReturnType::Matrix(_)) {
2468 return element_type;
2469 }
2470 element_type
2471 }
2472 ReturnType::Record(_) | ReturnType::Variant(_) | ReturnType::Unknown => {
2475 return ReturnType::Unknown;
2476 }
2477 subject_ty => bug!(
2478 "Invalid indexing operation: expected the operand to be a collection, got {self}: {subject_ty}"
2479 ),
2480 };
2481 }
2482 indexed_ty
2483 }
2484 Expression::UnsafeSlice(_, subject, _) | Expression::SafeSlice(_, subject, _) => {
2485 let mut element_type = subject.return_type();
2486 while let ReturnType::Matrix(inner) = element_type {
2487 element_type = *inner;
2488 }
2489 ReturnType::Matrix(Box::new(element_type))
2490 }
2491 Expression::InDomain(_, _, _) => ReturnType::Bool,
2492 Expression::Comprehension(_, comp) => comp.return_type(),
2493 Expression::Root(_, _) => ReturnType::Bool,
2494 Expression::DominanceRelation(_, _) => ReturnType::Bool,
2495 Expression::FromSolution(_, expr) => expr.return_type(),
2496 Expression::Metavar(_, _) => ReturnType::Unknown,
2497 Expression::Atomic(_, atom) => atom.return_type(),
2498 Expression::TypeAnnotation(_, _, domain) => domain.return_type(),
2499 Expression::DomainAnnotation(_, _, domain) => domain.return_type(),
2500 Expression::Abs(_, _) => ReturnType::Int,
2501 Expression::Sum(_, _) => ReturnType::Int,
2502 Expression::Product(_, _) => ReturnType::Int,
2503 Expression::Min(_, _) => ReturnType::Int,
2504 Expression::Max(_, _) => ReturnType::Int,
2505 Expression::Not(_, _) => ReturnType::Bool,
2506 Expression::Or(_, _) => ReturnType::Bool,
2507 Expression::Imply(_, _, _) => ReturnType::Bool,
2508 Expression::Iff(_, _, _) => ReturnType::Bool,
2509 Expression::And(_, _) => ReturnType::Bool,
2510 Expression::Eq(_, _, _) => ReturnType::Bool,
2511 Expression::Neq(_, _, _) => ReturnType::Bool,
2512 Expression::Geq(_, _, _) => ReturnType::Bool,
2513 Expression::Leq(_, _, _) => ReturnType::Bool,
2514 Expression::Gt(_, _, _) => ReturnType::Bool,
2515 Expression::Lt(_, _, _) => ReturnType::Bool,
2516 Expression::Apart(_, _, _) => ReturnType::Bool,
2517 Expression::Together(_, _, _) => ReturnType::Bool,
2518 Expression::Party(_, _, subject) => ReturnType::Set(Box::new(subject.return_type())),
2519 Expression::Participants(_, subject) => {
2520 ReturnType::Set(Box::new(subject.return_type()))
2521 }
2522 Expression::Parts(_, subject) => {
2523 ReturnType::Set(Box::new(ReturnType::Set(Box::new(subject.return_type()))))
2524 }
2525 Expression::CatchUndef(_, value, _) => value.return_type(),
2526 Expression::SafeDiv(_, _, _) => ReturnType::Int,
2527 Expression::UnsafeDiv(_, _, _) => ReturnType::Int,
2528 Expression::FlatAllDiff(_, _) => ReturnType::Bool,
2529 Expression::FlatMinEq(_, _, _) => ReturnType::Bool,
2530 Expression::FlatSumGeq(_, _, _) => ReturnType::Bool,
2531 Expression::FlatSumLeq(_, _, _) => ReturnType::Bool,
2532 Expression::MinionDivEqUndefZero(_, _, _, _) => ReturnType::Bool,
2533 Expression::FlatIneq(_, _, _, _) => ReturnType::Bool,
2534 Expression::Flatten(_, _, matrix) => {
2535 let matrix_type = matrix.return_type();
2536 match matrix_type {
2537 ReturnType::Matrix(_) => {
2538 let mut elem_type = matrix_type;
2540 while let ReturnType::Matrix(new_elem_type) = &elem_type {
2541 elem_type = *new_elem_type.clone();
2542 }
2543 ReturnType::Matrix(Box::new(elem_type))
2544 }
2545 _ => bug!(
2546 "Invalid indexing operation: expected the operand to be a collection, got {self}: {matrix_type}"
2547 ),
2548 }
2549 }
2550 Expression::AllDiff(_, _) => ReturnType::Bool,
2551 Expression::SmtDistinct(_, _) => ReturnType::Bool,
2552 Expression::AllDifferentExcept(_, _, _) => ReturnType::Bool,
2553 Expression::ElementId(_, _, _) | Expression::IndexOf(_, _, _) => ReturnType::Int,
2554 Expression::SatElement(_, _, _, _) | Expression::SatAllDifferentComparisons(_, _) => {
2555 ReturnType::Bool
2556 }
2557 Expression::Table(_, _, _)
2558 | Expression::FlatTable(..)
2559 | Expression::FlatShortTable(..) => ReturnType::Bool,
2560 Expression::NegativeTable(_, _, _) | Expression::ShortTable(_, _, _) => {
2561 ReturnType::Bool
2562 }
2563 Expression::AtLeast(_, _, _, _) => ReturnType::Bool,
2564 Expression::AtMost(_, _, _, _) => ReturnType::Bool,
2565 Expression::Gcc(_, _, _, _) | Expression::GccWeak(_, _, _, _) => ReturnType::Bool,
2566 Expression::Bubble(_, inner, _) => inner.return_type(),
2567 Expression::FlatWatchedLiteral(_, _, _) => ReturnType::Bool,
2568 Expression::MinionReify(_, _, _) => ReturnType::Bool,
2569 Expression::MinionReifyImply(_, _, _) => ReturnType::Bool,
2570 Expression::MinionWInIntervalSet(_, _, _) => ReturnType::Bool,
2571 Expression::MinionWInSet(_, _, _) => ReturnType::Bool,
2572 Expression::MinionElementOne(_, _, _, _) => ReturnType::Bool,
2573 Expression::AuxDeclaration(_, _, _) => ReturnType::Bool,
2574 Expression::UnsafeMod(_, _, _) => ReturnType::Int,
2575 Expression::SafeMod(_, _, _) => ReturnType::Int,
2576 Expression::MinionModuloEqUndefZero(_, _, _, _) => ReturnType::Bool,
2577 Expression::Neg(_, _) => ReturnType::Int,
2578 Expression::Factorial(_, _) => ReturnType::Int,
2579 Expression::UnsafePow(_, _, _) => ReturnType::Int,
2580 Expression::SafePow(_, _, _) => ReturnType::Int,
2581 Expression::Minus(_, a, b) => {
2582 let a_type = minus_operand_return_type(a);
2585 let b_type = minus_operand_return_type(b);
2586
2587 if a_type == ReturnType::Int && b_type == ReturnType::Int {
2588 ReturnType::Int
2589 } else if let ReturnType::Set(a_inner) = a_type
2590 && let ReturnType::Set(b_inner) = b_type
2591 && a_inner == b_inner
2592 {
2593 ReturnType::Set(a_inner)
2594 } else {
2595 bug!(
2596 "Invalid minus operation: operands are of different or invalid types for this operation"
2597 )
2598 }
2599 }
2600 Expression::FlatAbsEq(_, _, _) => ReturnType::Bool,
2601 Expression::FlatMinusEq(_, _, _) => ReturnType::Bool,
2602 Expression::FlatProductEq(_, _, _, _) => ReturnType::Bool,
2603 Expression::FlatWeightedSumLeq(_, _, _, _) => ReturnType::Bool,
2604 Expression::FlatWeightedSumGeq(_, _, _, _) => ReturnType::Bool,
2605 Expression::MinionPow(_, _, _, _) => ReturnType::Bool,
2606 Expression::ToInt(_, _) => ReturnType::Int,
2607 Expression::SATInt(..) => ReturnType::Int,
2608 Expression::SatObjective(..) => ReturnType::Bool,
2609 Expression::PairwiseSum(_, _, _) => ReturnType::Int,
2610 Expression::PairwiseProduct(_, _, _) => ReturnType::Int,
2611 Expression::Defined(_, function) => {
2612 let subject = function.return_type();
2613 match subject {
2614 ReturnType::Function(domain, _) => ReturnType::Set(Box::new(*domain)),
2615 _ => bug!(
2616 "Invalid defined operation: expected the operand to be a function, got {self}: {subject}"
2617 ),
2618 }
2619 }
2620 Expression::Range(_, function) => {
2621 let subject = function.return_type();
2622 match subject {
2623 ReturnType::Function(_, codomain) => ReturnType::Set(Box::new(*codomain)),
2624 _ => bug!(
2625 "Invalid range operation: expected the operand to be a function, got {self}: {subject}"
2626 ),
2627 }
2628 }
2629 Expression::Image(_, function, _) => {
2630 let subject = function.return_type();
2631 match subject {
2632 ReturnType::Function(_, codomain) => *codomain,
2633 ReturnType::Permutation(inner) => *inner,
2634 ReturnType::Sequence(inner) => *inner,
2636 _ => bug!(
2637 "Invalid image operation: expected the operand to be a function or permutation, got {self}: {subject}"
2638 ),
2639 }
2640 }
2641 Expression::ImageSet(_, function, _) => {
2642 let subject = function.return_type();
2643 match subject {
2644 ReturnType::Function(_, codomain) => ReturnType::Set(Box::new(*codomain)),
2645 ReturnType::Permutation(inner) => ReturnType::Set(inner),
2646 _ => bug!(
2647 "Invalid imageSet operation: expected the operand to be a function or permutation, got {self}: {subject}"
2648 ),
2649 }
2650 }
2651 Expression::PreImage(_, function, _) => {
2652 let subject = function.return_type();
2653 match subject {
2654 ReturnType::Function(domain, _) => ReturnType::Set(Box::new(*domain)),
2655 _ => bug!(
2656 "Invalid preImage operation: expected the operand to be a function, got {self}: {subject}"
2657 ),
2658 }
2659 }
2660 Expression::Restrict(_, function, new_domain) => {
2661 let subject = function.return_type();
2662 match subject {
2663 ReturnType::Function(_, codomain) => {
2664 ReturnType::Function(Box::new(new_domain.return_type()), codomain)
2665 }
2666 _ => bug!(
2667 "Invalid preImage operation: expected the operand to be a function, got {self}: {subject}"
2668 ),
2669 }
2670 }
2671 Expression::Inverse(..) => ReturnType::Bool,
2672 Expression::PermInverse(_, p) => p.return_type(),
2673 Expression::Compose(_, g, _h) => g.return_type(),
2674 Expression::LexLt(..) => ReturnType::Bool,
2675 Expression::LexGt(..) => ReturnType::Bool,
2676 Expression::LexLeq(..) => ReturnType::Bool,
2677 Expression::LexGeq(..) => ReturnType::Bool,
2678 Expression::FlatLexLt(..) => ReturnType::Bool,
2679 Expression::FlatLexLeq(..) => ReturnType::Bool,
2680 Expression::Active(..) => ReturnType::Bool,
2681 Expression::ToSet(_, other) => {
2682 let subject = other.return_type();
2683 match subject {
2684 ReturnType::Matrix(domain) => ReturnType::Set(Box::new(*domain)),
2685 ReturnType::MSet(domain) => ReturnType::Set(Box::new(*domain)),
2686 ReturnType::Function(domain, codomain) => {
2687 ReturnType::Set(Box::new(ReturnType::Tuple(vec![*domain, *codomain])))
2688 }
2689 ReturnType::Relation(domains) => {
2690 ReturnType::Set(Box::new(ReturnType::Tuple(domains)))
2691 }
2692 _ => bug!(
2693 "Invalid toSet operation: expected the operand to be a mset, matrix, relation, or function, got {self}: {subject}"
2694 ),
2695 }
2696 }
2697 Expression::ToMSet(_, other) => {
2698 let subject = other.return_type();
2699 match subject {
2700 ReturnType::Set(domain) => ReturnType::MSet(Box::new(*domain)),
2701 ReturnType::Function(domain, codomain) => {
2702 ReturnType::MSet(Box::new(ReturnType::Tuple(vec![*domain, *codomain])))
2703 }
2704 ReturnType::Relation(domains) => {
2705 ReturnType::MSet(Box::new(ReturnType::Tuple(domains)))
2706 }
2707 _ => bug!(
2708 "Invalid toMSet operation: expected the operand to be a set, relation, or function, got {self}: {subject}"
2709 ),
2710 }
2711 }
2712 Expression::ToRelation(_, function) => {
2713 let subject = function.return_type();
2714 match subject {
2715 ReturnType::Function(domain, codomain) => {
2716 ReturnType::Relation(vec![*domain, *codomain])
2717 }
2718 _ => bug!(
2719 "Invalid toRelation operation: expected the operand to be a function, got {self}: {subject}"
2720 ),
2721 }
2722 }
2723 Expression::RelationProj(_, relation, projections) => {
2724 let subject = relation.return_type();
2725 match subject {
2726 ReturnType::Relation(domains) => {
2727 let new_doms = domains
2728 .iter()
2729 .zip(projections.iter())
2730 .filter_map(|(domain, included)| {
2731 if included.is_none() {
2732 Some(domain.clone())
2734 } else {
2735 None
2736 }
2737 })
2738 .collect();
2739 ReturnType::Relation(new_doms)
2740 }
2741 _ => bug!(
2742 "Invalid RelationProj operation: expected the operand to be a relation, got {self}: {subject}"
2743 ),
2744 }
2745 }
2746 Expression::Pred(_, ev) => ev.return_type(),
2747 Expression::Succ(_, ev) => ev.return_type(),
2748 Expression::Card(..) => ReturnType::Int,
2749 Expression::Subsequence(_, _, _) => ReturnType::Bool,
2750 Expression::Substring(_, _, _) => ReturnType::Bool,
2751 Expression::AttributeAsConstraint(_, _, _, _) => ReturnType::Bool,
2752 }
2753 }
2754}
2755
2756impl Expression {
2757 pub fn for_each_expr_child<'a>(&'a self, f: &mut impl FnMut(&'a Expression)) {
2759 match self {
2760 Expression::AbstractLiteral(_, alit) => match alit {
2762 AbstractLiteral::Set(v) | AbstractLiteral::MSet(v) | AbstractLiteral::Tuple(v) => {
2763 for expr in v {
2764 f(expr);
2765 }
2766 }
2767 AbstractLiteral::Partition(two_d_v) => {
2768 for part in two_d_v {
2769 for expr in part {
2770 f(expr);
2771 }
2772 }
2773 }
2774 AbstractLiteral::Matrix(v, _domain) => {
2775 for expr in v {
2776 f(expr);
2777 }
2778 }
2779 AbstractLiteral::Record(rs) => {
2780 for r in rs {
2781 f(&r.value);
2782 }
2783 }
2784 AbstractLiteral::Sequence(v) => {
2785 for expr in v {
2786 f(expr);
2787 }
2788 }
2789 AbstractLiteral::Function(vs) => {
2790 for (a, b) in vs {
2791 f(a);
2792 f(b);
2793 }
2794 }
2795 AbstractLiteral::Variant(v) => {
2796 f(&v.value);
2797 }
2798 AbstractLiteral::Relation(vs) => {
2799 for exprs in vs {
2800 for expr in exprs {
2801 f(expr);
2802 }
2803 }
2804 }
2805 AbstractLiteral::Permutation(cycles) => {
2806 for cycle in cycles {
2807 for expr in cycle {
2808 f(expr);
2809 }
2810 }
2811 }
2812 },
2813 Expression::Root(_, vs) => {
2814 for expr in vs {
2815 f(expr);
2816 }
2817 }
2818
2819 Expression::DominanceRelation(_, m1)
2821 | Expression::TypeAnnotation(_, m1, _)
2822 | Expression::DomainAnnotation(_, m1, _)
2823 | Expression::ToInt(_, m1)
2824 | Expression::Abs(_, m1)
2825 | Expression::Sum(_, m1)
2826 | Expression::Product(_, m1)
2827 | Expression::Min(_, m1)
2828 | Expression::Max(_, m1)
2829 | Expression::Not(_, m1)
2830 | Expression::Or(_, m1)
2831 | Expression::And(_, m1)
2832 | Expression::Neg(_, m1)
2833 | Expression::PermInverse(_, m1)
2834 | Expression::Defined(_, m1)
2835 | Expression::AllDiff(_, m1)
2836 | Expression::SatAllDifferentComparisons(_, m1)
2837 | Expression::SmtDistinct(_, m1)
2838 | Expression::Factorial(_, m1)
2839 | Expression::Range(_, m1)
2840 | Expression::Participants(_, m1)
2841 | Expression::Parts(_, m1)
2842 | Expression::ToSet(_, m1)
2843 | Expression::ToMSet(_, m1)
2844 | Expression::ToRelation(_, m1)
2845 | Expression::Pred(_, m1)
2846 | Expression::Succ(_, m1)
2847 | Expression::Card(_, m1)
2848 | Expression::RecordField(_, m1, _)
2849 | Expression::Active(_, m1, _) => {
2850 f(m1);
2851 }
2852
2853 Expression::Table(_, m1, m2)
2855 | Expression::NegativeTable(_, m1, m2)
2856 | Expression::ShortTable(_, m1, m2)
2857 | Expression::Bubble(_, m1, m2)
2858 | Expression::Imply(_, m1, m2)
2859 | Expression::Iff(_, m1, m2)
2860 | Expression::Difference(_, m1, m2)
2861 | Expression::Union(_, m1, m2)
2862 | Expression::In(_, m1, m2)
2863 | Expression::Intersect(_, m1, m2)
2864 | Expression::Supset(_, m1, m2)
2865 | Expression::SupsetEq(_, m1, m2)
2866 | Expression::Subset(_, m1, m2)
2867 | Expression::SubsetEq(_, m1, m2)
2868 | Expression::Eq(_, m1, m2)
2869 | Expression::Neq(_, m1, m2)
2870 | Expression::Geq(_, m1, m2)
2871 | Expression::Leq(_, m1, m2)
2872 | Expression::Gt(_, m1, m2)
2873 | Expression::Lt(_, m1, m2)
2874 | Expression::CatchUndef(_, m1, m2)
2875 | Expression::SafeDiv(_, m1, m2)
2876 | Expression::UnsafeDiv(_, m1, m2)
2877 | Expression::SafeMod(_, m1, m2)
2878 | Expression::UnsafeMod(_, m1, m2)
2879 | Expression::UnsafePow(_, m1, m2)
2880 | Expression::SafePow(_, m1, m2)
2881 | Expression::Minus(_, m1, m2)
2882 | Expression::PairwiseSum(_, m1, m2)
2883 | Expression::PairwiseProduct(_, m1, m2)
2884 | Expression::Image(_, m1, m2)
2885 | Expression::ImageSet(_, m1, m2)
2886 | Expression::PreImage(_, m1, m2)
2887 | Expression::Inverse(_, m1, m2)
2888 | Expression::Compose(_, m1, m2)
2889 | Expression::Restrict(_, m1, m2)
2890 | Expression::Apart(_, m1, m2)
2891 | Expression::Together(_, m1, m2)
2892 | Expression::Party(_, m1, m2)
2893 | Expression::LexLt(_, m1, m2)
2894 | Expression::LexLeq(_, m1, m2)
2895 | Expression::LexGt(_, m1, m2)
2896 | Expression::LexGeq(_, m1, m2)
2897 | Expression::Subsequence(_, m1, m2)
2898 | Expression::Substring(_, m1, m2) => {
2899 f(m1);
2900 f(m2);
2901 }
2902
2903 Expression::UnsafeIndex(_, m, vs) | Expression::SafeIndex(_, m, vs) => {
2905 f(m);
2906 for v in vs {
2907 f(v);
2908 }
2909 }
2910 Expression::UnsafeSlice(_, m, vs)
2912 | Expression::SafeSlice(_, m, vs)
2913 | Expression::RelationProj(_, m, vs) => {
2914 f(m);
2915 for e in vs.iter().flatten() {
2916 f(e);
2917 }
2918 }
2919
2920 Expression::SatElement(_, m1, m2, m3)
2922 | Expression::AtLeast(_, m1, m2, m3)
2923 | Expression::AtMost(_, m1, m2, m3)
2924 | Expression::Gcc(_, m1, m2, m3)
2925 | Expression::GccWeak(_, m1, m2, m3) => {
2926 f(m1);
2927 f(m2);
2928 f(m3);
2929 }
2930
2931 Expression::AllDifferentExcept(_, m1, m2)
2933 | Expression::ElementId(_, m1, m2)
2934 | Expression::IndexOf(_, m1, m2) => {
2935 f(m1);
2936 f(m2);
2937 }
2938
2939 Expression::InDomain(_, m, _) => {
2941 f(m);
2942 }
2943
2944 Expression::Flatten(_, opt, m) => {
2946 if let Some(e) = opt {
2947 f(e);
2948 }
2949 f(m);
2950 }
2951
2952 Expression::AttributeAsConstraint(_, target, _, val) => {
2954 f(target);
2955 if let Some(v) = val {
2956 f(v);
2957 }
2958 }
2959
2960 Expression::MinionReify(_, m, _) | Expression::MinionReifyImply(_, m, _) => {
2962 f(m);
2963 }
2964
2965 Expression::AuxDeclaration(_, _, m) => {
2967 f(m);
2968 }
2969
2970 Expression::SatObjective(_, _, m) | Expression::SATInt(_, _, m, _) => {
2972 f(m);
2973 }
2974
2975 Expression::Comprehension(_, _)
2977 | Expression::Atomic(_, _)
2978 | Expression::FromSolution(_, _)
2979 | Expression::Metavar(_, _)
2980 | Expression::FlatAbsEq(_, _, _)
2981 | Expression::FlatMinusEq(_, _, _)
2982 | Expression::FlatProductEq(_, _, _, _)
2983 | Expression::MinionDivEqUndefZero(_, _, _, _)
2984 | Expression::MinionModuloEqUndefZero(_, _, _, _)
2985 | Expression::MinionPow(_, _, _, _)
2986 | Expression::FlatAllDiff(_, _)
2987 | Expression::FlatTable(..)
2988 | Expression::FlatShortTable(..)
2989 | Expression::FlatMinEq(_, _, _)
2990 | Expression::FlatSumGeq(_, _, _)
2991 | Expression::FlatSumLeq(_, _, _)
2992 | Expression::FlatIneq(_, _, _, _)
2993 | Expression::FlatWatchedLiteral(_, _, _)
2994 | Expression::FlatWeightedSumLeq(_, _, _, _)
2995 | Expression::FlatWeightedSumGeq(_, _, _, _)
2996 | Expression::MinionWInIntervalSet(_, _, _)
2997 | Expression::MinionWInSet(_, _, _)
2998 | Expression::MinionElementOne(_, _, _, _)
2999 | Expression::FlatLexLt(_, _, _)
3000 | Expression::FlatLexLeq(_, _, _) => {}
3001 }
3002 }
3003
3004 pub fn for_each_expression<'a>(&'a self, f: &mut impl FnMut(&'a Expression)) {
3006 f(self);
3007 self.for_each_expr_child(&mut |child| child.for_each_expression(f));
3008 }
3009
3010 pub fn any_expression(&self, mut predicate: impl FnMut(&Expression) -> bool) -> bool {
3014 fn visit(expr: &Expression, predicate: &mut impl FnMut(&Expression) -> bool) -> bool {
3015 if predicate(expr) {
3016 return true;
3017 }
3018
3019 let mut found = false;
3020 expr.for_each_expr_child(&mut |child| {
3021 if !found {
3022 found = visit(child, predicate);
3023 }
3024 });
3025 found
3026 }
3027
3028 visit(self, &mut predicate)
3029 }
3030
3031 pub fn any_expression_descendant(
3033 &self,
3034 mut predicate: impl FnMut(&Expression) -> bool,
3035 ) -> bool {
3036 let mut found = false;
3037 self.for_each_expr_child(&mut |child| {
3038 if !found {
3039 found = child.any_expression(&mut predicate);
3040 }
3041 });
3042 found
3043 }
3044}
3045
3046impl Expression {
3047 pub(crate) fn invalidate_cached_content_hash(&self) {
3049 let metadata = self.meta_ref();
3050 metadata
3051 .cached_content_hash
3052 .store(NO_HASH, Ordering::Relaxed);
3053 }
3054
3055 pub(crate) fn cached_content_hash(&self) -> u64 {
3057 let stored = self.meta_ref().cached_content_hash.load(Ordering::Relaxed);
3058 if stored != NO_HASH {
3059 HASH_HITS.fetch_add(1, Ordering::Relaxed);
3060 return stored;
3061 }
3062 HASH_MISSES.fetch_add(1, Ordering::Relaxed);
3063 self.calculate_content_hash()
3064 }
3065
3066 #[allow(unused_variables)]
3071 pub(crate) fn content_hash_from_child_hashes(
3072 &self,
3073 child_hashes: &mut impl Iterator<Item = u64>,
3074 ) -> u64 {
3075 fn child_hash(child_hashes: &mut impl Iterator<Item = u64>) -> u64 {
3076 child_hashes
3077 .next()
3078 .expect("expression content hash missing child hash")
3079 }
3080
3081 let mut hasher = DefaultHasher::new();
3082 std::mem::discriminant(self).hash(&mut hasher);
3083 match self {
3084 Expression::AbstractLiteral(_, alit) => match alit {
3086 AbstractLiteral::Set(v)
3087 | AbstractLiteral::MSet(v)
3088 | AbstractLiteral::Tuple(v)
3089 | AbstractLiteral::Sequence(v) => {
3090 for expr in v {
3091 child_hash(child_hashes).hash(&mut hasher);
3092 }
3093 }
3094 AbstractLiteral::Matrix(v, domain) => {
3095 domain.hash(&mut hasher);
3096 for expr in v {
3097 child_hash(child_hashes).hash(&mut hasher);
3098 }
3099 }
3100 AbstractLiteral::Record(rs) => {
3101 for r in rs {
3102 r.name.hash(&mut hasher);
3103 child_hash(child_hashes).hash(&mut hasher);
3104 }
3105 }
3106 AbstractLiteral::Function(vs) => {
3107 for (a, b) in vs {
3108 child_hash(child_hashes).hash(&mut hasher);
3109 child_hash(child_hashes).hash(&mut hasher);
3110 }
3111 }
3112 AbstractLiteral::Variant(v) => {
3113 v.name.hash(&mut hasher);
3114 child_hash(child_hashes).hash(&mut hasher);
3115 }
3116 AbstractLiteral::Relation(v) => {
3117 for exprs in v {
3118 for expr in exprs {
3119 child_hash(child_hashes).hash(&mut hasher);
3120 }
3121 }
3122 }
3123 AbstractLiteral::Partition(v) => {
3124 for exprs in v {
3125 for expr in exprs {
3126 child_hash(child_hashes).hash(&mut hasher);
3127 }
3128 }
3129 }
3130 AbstractLiteral::Permutation(v) => {
3131 for exprs in v {
3132 for expr in exprs {
3133 child_hash(child_hashes).hash(&mut hasher);
3134 }
3135 }
3136 }
3137 },
3138 Expression::Root(_, vs) => {
3139 for expr in vs {
3140 child_hash(child_hashes).hash(&mut hasher);
3141 }
3142 }
3143
3144 Expression::DominanceRelation(_, m1)
3146 | Expression::ToInt(_, m1)
3147 | Expression::Abs(_, m1)
3148 | Expression::Sum(_, m1)
3149 | Expression::Product(_, m1)
3150 | Expression::Min(_, m1)
3151 | Expression::Max(_, m1)
3152 | Expression::Not(_, m1)
3153 | Expression::Or(_, m1)
3154 | Expression::And(_, m1)
3155 | Expression::Neg(_, m1)
3156 | Expression::PermInverse(_, m1)
3157 | Expression::Defined(_, m1)
3158 | Expression::AllDiff(_, m1)
3159 | Expression::SatAllDifferentComparisons(_, m1)
3160 | Expression::SmtDistinct(_, m1)
3161 | Expression::Factorial(_, m1)
3162 | Expression::Participants(_, m1)
3163 | Expression::Parts(_, m1)
3164 | Expression::Range(_, m1)
3165 | Expression::ToSet(_, m1)
3166 | Expression::ToMSet(_, m1)
3167 | Expression::ToRelation(_, m1)
3168 | Expression::Pred(_, m1)
3169 | Expression::Succ(_, m1)
3170 | Expression::Card(_, m1) => {
3171 child_hash(child_hashes).hash(&mut hasher);
3172 }
3173 Expression::TypeAnnotation(_, m1, domain) => {
3174 child_hash(child_hashes).hash(&mut hasher);
3175 domain.hash(&mut hasher);
3176 }
3177 Expression::DomainAnnotation(_, m1, domain) => {
3178 child_hash(child_hashes).hash(&mut hasher);
3179 domain.hash(&mut hasher);
3180 }
3181
3182 Expression::Table(_, m1, m2)
3184 | Expression::NegativeTable(_, m1, m2)
3185 | Expression::ShortTable(_, m1, m2)
3186 | Expression::Bubble(_, m1, m2)
3187 | Expression::Imply(_, m1, m2)
3188 | Expression::Iff(_, m1, m2)
3189 | Expression::Difference(_, m1, m2)
3190 | Expression::Union(_, m1, m2)
3191 | Expression::In(_, m1, m2)
3192 | Expression::Intersect(_, m1, m2)
3193 | Expression::Supset(_, m1, m2)
3194 | Expression::SupsetEq(_, m1, m2)
3195 | Expression::Subset(_, m1, m2)
3196 | Expression::SubsetEq(_, m1, m2)
3197 | Expression::Eq(_, m1, m2)
3198 | Expression::Neq(_, m1, m2)
3199 | Expression::Geq(_, m1, m2)
3200 | Expression::Leq(_, m1, m2)
3201 | Expression::Gt(_, m1, m2)
3202 | Expression::Lt(_, m1, m2)
3203 | Expression::Apart(_, m1, m2)
3204 | Expression::Together(_, m1, m2)
3205 | Expression::Party(_, m1, m2)
3206 | Expression::CatchUndef(_, m1, m2)
3207 | Expression::SafeDiv(_, m1, m2)
3208 | Expression::UnsafeDiv(_, m1, m2)
3209 | Expression::SafeMod(_, m1, m2)
3210 | Expression::UnsafeMod(_, m1, m2)
3211 | Expression::UnsafePow(_, m1, m2)
3212 | Expression::SafePow(_, m1, m2)
3213 | Expression::Minus(_, m1, m2)
3214 | Expression::PairwiseSum(_, m1, m2)
3215 | Expression::PairwiseProduct(_, m1, m2)
3216 | Expression::Image(_, m1, m2)
3217 | Expression::ImageSet(_, m1, m2)
3218 | Expression::PreImage(_, m1, m2)
3219 | Expression::Inverse(_, m1, m2)
3220 | Expression::Compose(_, m1, m2)
3221 | Expression::Restrict(_, m1, m2)
3222 | Expression::LexLt(_, m1, m2)
3223 | Expression::LexLeq(_, m1, m2)
3224 | Expression::LexGt(_, m1, m2)
3225 | Expression::LexGeq(_, m1, m2)
3226 | Expression::Subsequence(_, m1, m2)
3227 | Expression::Substring(_, m1, m2) => {
3228 child_hash(child_hashes).hash(&mut hasher);
3229 child_hash(child_hashes).hash(&mut hasher);
3230 }
3231 Expression::UnsafeIndex(_, m, vs) | Expression::SafeIndex(_, m, vs) => {
3233 child_hash(child_hashes).hash(&mut hasher);
3234 for v in vs {
3235 child_hash(child_hashes).hash(&mut hasher);
3236 }
3237 }
3238
3239 Expression::UnsafeSlice(_, m, vs)
3241 | Expression::SafeSlice(_, m, vs)
3242 | Expression::RelationProj(_, m, vs) => {
3243 child_hash(child_hashes).hash(&mut hasher);
3244 for v in vs {
3245 match v {
3246 Some(e) => child_hash(child_hashes).hash(&mut hasher),
3247 None => 0u64.hash(&mut hasher),
3248 }
3249 }
3250 }
3251
3252 Expression::SatElement(_, m1, m2, m3)
3254 | Expression::AtLeast(_, m1, m2, m3)
3255 | Expression::AtMost(_, m1, m2, m3)
3256 | Expression::Gcc(_, m1, m2, m3)
3257 | Expression::GccWeak(_, m1, m2, m3) => {
3258 child_hash(child_hashes).hash(&mut hasher);
3259 child_hash(child_hashes).hash(&mut hasher);
3260 child_hash(child_hashes).hash(&mut hasher);
3261 }
3262
3263 Expression::AllDifferentExcept(_, m1, m2)
3265 | Expression::ElementId(_, m1, m2)
3266 | Expression::IndexOf(_, m1, m2) => {
3267 child_hash(child_hashes).hash(&mut hasher);
3268 child_hash(child_hashes).hash(&mut hasher);
3269 }
3270
3271 Expression::RecordField(_, m, n) | Expression::Active(_, m, n) => {
3273 child_hash(child_hashes).hash(&mut hasher);
3274 n.hash(&mut hasher);
3275 }
3276
3277 Expression::InDomain(_, m, d) => {
3279 child_hash(child_hashes).hash(&mut hasher);
3280 d.hash(&mut hasher);
3281 }
3282
3283 Expression::Flatten(_, opt, m) => {
3285 if let Some(e) = opt {
3286 child_hash(child_hashes).hash(&mut hasher);
3287 }
3288 child_hash(child_hashes).hash(&mut hasher);
3289 }
3290
3291 Expression::AttributeAsConstraint(_, target, attr, val) => {
3293 child_hash(child_hashes).hash(&mut hasher);
3294 attr.hash(&mut hasher);
3295 if let Some(v) = val {
3296 child_hash(child_hashes).hash(&mut hasher);
3297 }
3298 }
3299
3300 Expression::MinionReify(_, m, a) | Expression::MinionReifyImply(_, m, a) => {
3302 child_hash(child_hashes).hash(&mut hasher);
3303 a.hash(&mut hasher);
3304 }
3305
3306 Expression::AuxDeclaration(_, r, m) => {
3308 r.hash(&mut hasher);
3309 child_hash(child_hashes).hash(&mut hasher);
3310 }
3311
3312 Expression::SatObjective(_, minimise, _) => {
3314 minimise.hash(&mut hasher);
3315 child_hash(child_hashes).hash(&mut hasher);
3316 }
3317 Expression::SATInt(_, enc, m, bounds) => {
3318 enc.hash(&mut hasher);
3319 child_hash(child_hashes).hash(&mut hasher);
3320 bounds.hash(&mut hasher);
3321 }
3322
3323 Expression::Comprehension(_, c) => c.hash(&mut hasher),
3325
3326 Expression::Atomic(_, a) => a.hash(&mut hasher),
3328 Expression::FromSolution(_, a) => a.hash(&mut hasher),
3329 Expression::Metavar(_, u) => u.hash(&mut hasher),
3330
3331 Expression::FlatAbsEq(_, a1, a2) | Expression::FlatMinusEq(_, a1, a2) => {
3333 a1.hash(&mut hasher);
3334 a2.hash(&mut hasher);
3335 }
3336
3337 Expression::FlatProductEq(_, a1, a2, a3)
3339 | Expression::MinionDivEqUndefZero(_, a1, a2, a3)
3340 | Expression::MinionModuloEqUndefZero(_, a1, a2, a3)
3341 | Expression::MinionPow(_, a1, a2, a3) => {
3342 a1.hash(&mut hasher);
3343 a2.hash(&mut hasher);
3344 a3.hash(&mut hasher);
3345 }
3346
3347 Expression::FlatShortTable(_, inputs, rows) => {
3348 inputs.hash(&mut hasher);
3349 rows.hash(&mut hasher);
3350 }
3351 Expression::FlatTable(_, inputs, rows, negative) => {
3352 inputs.hash(&mut hasher);
3353 rows.hash(&mut hasher);
3354 negative.hash(&mut hasher);
3355 }
3356
3357 Expression::FlatAllDiff(_, vs) => {
3359 for v in vs {
3360 v.hash(&mut hasher);
3361 }
3362 }
3363
3364 Expression::FlatMinEq(_, vs, a)
3366 | Expression::FlatSumGeq(_, vs, a)
3367 | Expression::FlatSumLeq(_, vs, a) => {
3368 for v in vs {
3369 v.hash(&mut hasher);
3370 }
3371 a.hash(&mut hasher);
3372 }
3373
3374 Expression::FlatIneq(_, a1, a2, lit) => {
3376 a1.hash(&mut hasher);
3377 a2.hash(&mut hasher);
3378 lit.hash(&mut hasher);
3379 }
3380
3381 Expression::FlatWatchedLiteral(_, r, l) => {
3383 r.hash(&mut hasher);
3384 l.hash(&mut hasher);
3385 }
3386
3387 Expression::FlatWeightedSumLeq(_, lits, atoms, a)
3389 | Expression::FlatWeightedSumGeq(_, lits, atoms, a) => {
3390 for l in lits {
3391 l.hash(&mut hasher);
3392 }
3393 for at in atoms {
3394 at.hash(&mut hasher);
3395 }
3396 a.hash(&mut hasher);
3397 }
3398
3399 Expression::MinionWInIntervalSet(_, a, vs) | Expression::MinionWInSet(_, a, vs) => {
3401 a.hash(&mut hasher);
3402 for v in vs {
3403 v.hash(&mut hasher);
3404 }
3405 }
3406
3407 Expression::MinionElementOne(_, vs, a1, a2) => {
3409 for v in vs {
3410 v.hash(&mut hasher);
3411 }
3412 a1.hash(&mut hasher);
3413 a2.hash(&mut hasher);
3414 }
3415
3416 Expression::FlatLexLt(_, v1, v2) | Expression::FlatLexLeq(_, v1, v2) => {
3418 for v in v1 {
3419 v.hash(&mut hasher);
3420 }
3421 for v in v2 {
3422 v.hash(&mut hasher);
3423 }
3424 }
3425 };
3426
3427 hasher.finish()
3428 }
3429
3430 pub(crate) fn calculate_content_hash(&self) -> u64 {
3432 let mut hashes = Vec::new();
3433 self.for_each_expr_child(&mut |child| hashes.push(child.cached_content_hash()));
3434 let mut child_hashes = hashes.into_iter();
3435 let result = self.content_hash_from_child_hashes(&mut child_hashes);
3436 self.meta_ref()
3437 .cached_content_hash
3438 .store(result, Ordering::Relaxed);
3439 result
3440 }
3441}
3442
3443#[cfg(test)]
3444mod tests {
3445 use crate::matrix_expr;
3446
3447 use super::*;
3448
3449 #[test]
3450 fn list_inspection_borrows_expression_elements_without_cloning_the_list() {
3451 let list = matrix_expr![
3452 Expression::from(Literal::Int(1)),
3453 Expression::from(Literal::Int(2))
3454 ];
3455
3456 assert_eq!(list.list_len(), Some(2));
3457 assert!(list.is_list());
3458 assert!(matches!(list.unwrap_list_cow(), Some(Cow::Borrowed(_))));
3459 }
3460
3461 #[test]
3462 fn list_inspection_materialises_literal_elements_only_when_they_are_requested() {
3463 let list = Expression::Atomic(
3464 Metadata::new(),
3465 Atom::Literal(Literal::AbstractLiteral(
3466 AbstractLiteral::matrix_implied_indices(vec![Literal::Int(1), Literal::Int(2)]),
3467 )),
3468 );
3469
3470 assert_eq!(list.list_len(), Some(2));
3471 assert!(list.is_list());
3472 assert!(matches!(list.unwrap_list_cow(), Some(Cow::Owned(_))));
3473 assert_eq!(
3474 list.unwrap_list_cow().map(Cow::into_owned),
3475 list.unwrap_list()
3476 );
3477 }
3478
3479 #[test]
3480 fn list_length_looks_through_annotations() {
3481 let list = Expression::DomainAnnotation(
3482 Metadata::new(),
3483 Moo::new(matrix_expr![Expression::from(Literal::Int(1))]),
3484 Domain::int(vec![Range::Bounded(0, 1)]),
3485 );
3486
3487 assert_eq!(list.list_len(), Some(1));
3488 assert!(matches!(list.unwrap_list_cow(), Some(Cow::Borrowed(_))));
3489 }
3490}