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-Left
rule 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.Poly
with 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
y
because3 ∣ 3*y + 2
is 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-Left
andCooper-Right
rules 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
Expr
to 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
c
is a lower bound for a variablex
ifx
is the maximal variable inc
, andx
coefficient inc
is negative.Mapping from variables to their "upper" bounds. We say a relational constraint
c
is a upper bound for a variablex
ifx
is the maximal variable inc
, andx
coefficient inc
is positive.- diseqs : PArray (PArray DiseqCnstr)
Mapping from variables to their disequalities. We say a disequality constraint
c
is a disequality for a variablex
ifx
is 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 thatx
may occur indvdCnstrs
,lowers
, oruppers
of variablesy
andz
. Ifx
occurs indvdCnstrs[y]
,lowers[y]
, oruppers[y]
, theny
is inoccurs[x]
, but the reverse is not true. Ifx
is inelimStack
, thenoccurs[x]
is the empty set.Partial assignment being constructed by cutsat.
- nextCnstrId : Nat
Next unique id for a constraint.
- caseSplits : Bool
caseSplits
istrue
if cutsat is searching for model and already performed case splits. This information is used to decide whether a conflict should immediately close the currentgrind
goal or not. - conflict? : Option UnsatProof
conflict?
issome ..
if a contradictory constraint was derived. This field is only set whencaseSplits
istrue
. Otherwise, we can convertUnsatProof
into a Lean term and close the currentgrind
goal. 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.