use conjure_cp::rule_engine::{ApplicationError, ApplicationError::RuleNotApplicable, RuleEffect};
/// An atom is only genuinely ready for a flat solver-level comparison (`FlatLexLt`/`FlatLexLeq`,
/// reference to a still-abstract domain (e.g. a set or tuple field) is wrapped in `Expr::Atomic`
pub fn collect_cmp_exprs(cmp_op: &Expr, lhs_fields: Vec<Expr>, rhs_fields: Vec<Expr>) -> Expr {
/// operator actually matches its own type. A scalar field has no list/lex structure of its own,
/// so a lexicographic operator must be downgraded to its plain counterpart; a still-abstract field
/// `Some(Vec<Atom>)` if the vectors direct children expressions are all atomic, otherwise `None`.
/// auxiliary and the total number of children. It is consulted before the model-wide symbol table
/// Child domains are derived once and reused for the rewrite. Deriving the domain of an expression
/// can enumerate its whole value set, and expression clones start with an empty domain cache, so
let child_domains: Vec<Option<DomainPtr>> = children.iter().map(to_aux_var_domain).collect();
/// * `None` if `Expr` is a `Atom`, or `Expr` does not have a domain (for example, if it is a `Bubble`).
pub fn to_aux_var_in(expr: &Expr, symbols: &mut SymbolTable) -> Option<(Reference, Expr)> {
/// since `introduce_element_from_index` shifts a non-1-based index onto `element`'s own positions.
/// Anything else -- a reference, or a literal still holding compound elements -- is left alone:
/// hoisting it into an auxiliary here would hide it from the representation rules that lower it.
trace!(expr=%expr, why = "matrix indexing is not element-lowerable", "to_aux_var() failed");
trace!(expr=%expr, why = "could not find the domain of the expression", "to_aux_var() failed");
fn materialise_aux_var(expr: &Expr, symbols: &SymbolTable, domain: &DomainPtr) -> ToAuxVarOutput {
/// Returns the new `SymbolTable`, modified to contain this auxiliary variable in the symbol table.
/// `Some(minimum)` iff `values` is a contiguous run of `Literal::Int`s starting at `minimum` --
/// Given a decoded position `digit` (a decision-variable expression, not necessarily constant --
/// Shared between `TuplePacked` and `RecordPacked`'s own digit-decoding, since a packed field or
/// matrix of those values, dynamically indexed by `digit` -- the Minion backend already supports
/// that (the same shape `FunctionExplicit::values_matrix` uses). A *compound* (tuple or record)
/// value can't take that path: indexing a matrix of compound elements by a non-constant position
/// silently produces an unresolved literal handed straight to the solver ("expected a literal but
/// decoded recursively by this same function -- reusing `digit`, since every candidate is keyed by
/// the same packed position. A field that's itself a contiguous int range (the common case) hits
/// The compound-value case of [`unpack_literal_digit`]: `None` unless every value is a tuple (or
/// every value is a record with the same field names) -- guaranteed for a genuine packed field's
/// back to the -- still correct, if unreduced until something else eliminates it -- generic path
pub(crate) fn checked_short_table_row(expr: &Expr, width: usize) -> Option<Vec<(usize, Expr)>> {