This module implements a model-based decision procedure for linear integer arithmetic, inspired by Section 4 of "Cutting to the Chase: Solving Linear Integer Arithmetic". Our implementation includes several enhancements and modifications: Key Features:
- Extended constraint support (equality and disequality)
- Optimized encoding of
Cooper-Leftrule using "big"-disjunction instead of fresh variables - Decision variable tracking for case splits (disequalities,
Cooper-Left,Cooper-Right)
Constraint Types: We handle four categories of linear polynomial constraints (where p is a linear polynomial):
Implementation Details:
- Polynomials use
Int.Linear.Polywith sorted linear monomials (leading monomial contains max variable) - Equalities are eliminated eagerly
- Divisibility constraints are maintained in solved form (one constraint per variable) using
Div-Solve
Model Construction:
The procedure builds a model incrementally, resolving conflicts through constraint generation.
For example:
Given a partial model {x := 1} and constraint 3 ∣ 3*y + x + 1:
- Cannot extend to
ybecause3 ∣ 3*y + 2is unsatisfiable - Generate implied constraint
3 ∣ x + 1 - Force model update for
x
Variable Assignment:
When assigning a variable y, we consider:
- Best upper and lower bounds (inequalities)
- Divisibility constraint
- Disequality constraints
Cooper-LeftandCooper-Rightrules handle the combination of inequalities and divisibility. For unsatisfiable disequalities p ≠ 0, we generate case split:p + 1 ≤ 0 ∨ -p + 1 ≤ 0
Contradiction Handling:
- Check dependency on decision variables
- If independent, use contradiction to close current grind goal
- Otherwise, trigger backtracking
Optimization: We employ rational approximation for model construction:
- Continue with rational solutions when integer solutions aren't immediately found
- Helps identify simpler unsatisfiability proofs before full integer model construction
- expr (h : Expr) : EqCnstrProof
- core (p₁ p₂ : Poly) (h : Expr) : EqCnstrProof
- norm (c : EqCnstr) : EqCnstrProof
- divCoeffs (c : EqCnstr) : EqCnstrProof
- subst (x : Var) (c₁ c₂ : EqCnstr) : EqCnstrProof
- ofLeGe (c₁ c₂ : LeCnstr) : EqCnstrProof
Instances For
A divisibility constraint and its justification/proof.
- d : Int
- p : Poly
- h : DvdCnstrProof
- id : Nat
Unique id for caching proofs in
ProofM
Instances For
- expr (h : Expr) : DvdCnstrProof
- norm (c : DvdCnstr) : DvdCnstrProof
- divCoeffs (c : DvdCnstr) : DvdCnstrProof
- solveCombine (c₁ c₂ : DvdCnstr) : DvdCnstrProof
- solveElim (c₁ c₂ : DvdCnstr) : DvdCnstrProof
- elim (c : DvdCnstr) : DvdCnstrProof
- ofEq (x : Var) (c : EqCnstr) : DvdCnstrProof
- subst (x : Var) (c₁ : EqCnstr) (c₂ : DvdCnstr) : DvdCnstrProof
Instances For
- expr (h : Expr) : LeCnstrProof
- notExpr (p : Poly) (h : Expr) : LeCnstrProof
- norm (c : LeCnstr) : LeCnstrProof
- divCoeffs (c : LeCnstr) : LeCnstrProof
- combine (c₁ c₂ : LeCnstr) : LeCnstrProof
- subst (x : Var) (c₁ : EqCnstr) (c₂ : LeCnstr) : LeCnstrProof
- ofLeDiseq (c₁ : LeCnstr) (c₂ : DiseqCnstr) : LeCnstrProof
- ofDiseqSplit (c₁ : DiseqCnstr) (decVar : FVarId) (h : UnsatProof) (decVars : Array FVarId) : LeCnstrProof
Instances For
A disequality constraint and its justification/proof.
- p : Poly
- h : DiseqCnstrProof
- id : Nat
Instances For
- expr (h : Expr) : DiseqCnstrProof
- core (p₁ p₂ : Poly) (h : Expr) : DiseqCnstrProof
- norm (c : DiseqCnstr) : DiseqCnstrProof
- divCoeffs (c : DiseqCnstr) : DiseqCnstrProof
- neg (c : DiseqCnstr) : DiseqCnstrProof
- subst (x : Var) (c₁ : EqCnstr) (c₂ : DiseqCnstr) : DiseqCnstrProof
Instances For
A proof of False.
Remark: We will later add support for a backtraking search inside of cutsat.
- dvd (c : DvdCnstr) : UnsatProof
- le (c : LeCnstr) : UnsatProof
- eq (c : EqCnstr) : UnsatProof
- diseq (c : DiseqCnstr) : UnsatProof
Instances For
Equations
- Lean.Meta.Grind.Arith.Cutsat.instInhabitedDvdCnstr = { default := { d := 0, p := Int.Linear.Poly.num 0, h := Lean.Meta.Grind.Arith.Cutsat.DvdCnstrProof.expr default, id := 0 } }
Instances For
State of the cutsat procedure.
Mapping from variables to their denotations.
Mapping from
Exprto a variable representing it.Mapping from variables to divisibility constraints. Recall that we keep the divisibility constraint in solved form. Thus, we have at most one divisibility per variable.
Mapping from variables to their "lower" bounds. We say a relational constraint
cis a lower bound for a variablexifxis the maximal variable inc, andxcoefficient incis negative.Mapping from variables to their "upper" bounds. We say a relational constraint
cis a upper bound for a variablexifxis the maximal variable inc, andxcoefficient incis positive.- diseqs : PArray (PArray DiseqCnstr)
Mapping from variables to their disequalities. We say a disequality constraint
cis a disequality for a variablexifxis the maximal variable inc. Mapping from terms (e.g.,
x + 2*y + 2,3*x,5) to polynomials representing them. These are terms used to propagate equalities between this module and the congruence closure module.Mapping from variable to occurrences. For example, an entry
x ↦ {y, z}means thatxmay occur indvdCnstrs,lowers, oruppersof variablesyandz. Ifxoccurs indvdCnstrs[y],lowers[y], oruppers[y], thenyis inoccurs[x], but the reverse is not true. Ifxis inelimStack, thenoccurs[x]is the empty set.Partial assignment being constructed by cutsat.
- nextCnstrId : Nat
Next unique id for a constraint.
- caseSplits : Bool
caseSplitsistrueif cutsat is searching for model and already performed case splits. This information is used to decide whether a conflict should immediately close the currentgrindgoal or not. - conflict? : Option UnsatProof
conflict?issome ..if a contradictory constraint was derived. This field is only set whencaseSplitsistrue. Otherwise, we can convertUnsatProofinto a Lean term and close the currentgrindgoal. Cache decision variables used when splitting on disequalities. This is necessary because the same disequality may be in different conflicts.
Instances For
Equations
- One or more equations did not get rendered due to their size.