// If you triggered this assertion, you either made a variant of this enum that is too big, or you
/// `shortTable(sequence(x1, x2, ...), {{(position, value), ...}, ...})` uses one-based positions.
/// Minion sparse table with zero-based positions and numeric values; omitted inputs are wildcards.
/// TODO: make this compatible with Set Difference calculations - need to change return type and domain for this expression and write a set comprehension rule.
/// Partition Operator: test if a list of elements are not all contained in one part of the partition
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#abs)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#alldiff)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#min)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#sumgeq)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#sumleq)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#ineq)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#minuseq)
/// documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#weightedsumleq)
/// documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#weightedsumleq)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#minuseq)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#product)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#div_undefzero)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#mod_undefzero)
/// + [Github comment about `pow` semantics](https://github.com/minion/minion/issues/40#issuecomment-2595914891)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#pow)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#reify)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#reifyimply)
/// `w-inintervalset(x, [a1,a2, b1,b2, … ])` ensures that the value of x belongs to one of the
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#w-inintervalset)
/// `w-inset(x, [v1, v2, … ])` ensures that the value of `x` is one of the explicitly given values `v1`, `v2`, etc.
/// This constraint enforces membership in a specific set of discrete values rather than intervals.
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#w-inset)
/// + [Minion documentation](https://minion-solver.readthedocs.io/en/stable/usage/constraints.html#element_one)
/// This expression is for encoding ints for the SAT solver, it stores the encoding type, the vector of booleans and the min/max for the int.
/// Addition over a pair of expressions (i.e. a + b) rather than a vec-expr like Expression::Sum.
/// Multiplication over a pair of expressions (i.e. a * b) rather than a vec-expr like Expression::Product.
if matches!(matrix.as_ref(), Expression::Atomic(_, Atom::Literal(Literal::AbstractLiteral(AbstractLiteral::Matrix(entries, _)))) if entries.is_empty())
"Domain of {self} needed to be a matrix, set, mset, sequence, relation, function, or partition for cardinality"
/// This is true for both forms of matrix literals: those with elements of type [`Literal`] and
/// Unlike [`Expression::unwrap_list`], a matrix held as an [`Atom::Literal`] is not unwrapped,
/// Prefer this over [`Expression::unwrap_list`] when the expression is already owned: it moves
/// It is generally undefined to edit the length of a matrix unless it is a list (as defined by
/// `return_type` panics for a reference whose declaration has no domain yet -- a value letting
/// A function is defined only on its own domain -- `total` means defined for every value *in* that
/// domain, not defined everywhere -- so an argument that can fall outside it has no image there. A
/// partial function may also be undefined inside its domain, and a sequence is defined only on
/// `1..|s|`. When the length varies, every member of the domain still has the prefix `1..minSize`;
/// Anything this cannot work out counts as undefinable. Safety has to be conservative: treating a
/// partial application as total lets its definedness be reasoned away, and the constraint it sits
!matches!(attr.partiality, PartialityAttr::Total) || !argument_always_in(argument, from)
/// Answers false whenever that cannot be established, including for domains that are equivalent
if let Some(max_atom_category) = Biplate::<Atom>::universe_bi(&x).iter().map(|x| x.category_of()).max()
if let Some(max_declaration_category) = Biplate::<DeclarationPtr>::universe_bi(&x).iter().map(|x| x.category_of()).max()
"Invalid indexing operation: expected the operand to be a collection, got {self}: {subject_ty}"
"Invalid indexing operation: expected the operand to be a collection, got {self}: {matrix_type}"
// rather than calling .return_type on a and b which sometimes errors on references that don't have domains
// use custom function that extracts return type from atomic references based on each declaration variant
"Invalid image operation: expected the operand to be a function or permutation, got {self}: {subject}"
"Invalid imageSet operation: expected the operand to be a function or permutation, got {self}: {subject}"
"Invalid toSet operation: expected the operand to be a mset, matrix, relation, or function, got {self}: {subject}"
"Invalid toMSet operation: expected the operand to be a set, relation, or function, got {self}: {subject}"
/// Unlike [`Uniplate::universe`], this does not construct an owned copy of the traversed tree.
pub fn any_expression(&self, mut predicate: impl FnMut(&Expression) -> bool) -> bool {
fn visit(expr: &Expression, predicate: &mut impl FnMut(&Expression) -> bool) -> bool {