16.9. Linear Integer Arithmetic
The linear integer arithmetic solver implements a model-based decision procedure for linear integer arithmetic.
The solver can process four categories of linear polynomial constraints (where p is a linear polynomial):
- Equality
p = 0- Divisibility
d ∣ p- Inequality
p ≤ 0- Disequality
p ≠ 0
It is complete for linear integer arithmetic, and it additionally supports Nat, Fin, BitVec, UInt8–UInt64, USize, Int8–Int64, and ISize by rewriting them to integers.
While this mechanism is not directly extensible, homomorphism rules can be used to map additional types to a supported domain.
Nonlinear terms (e.g. x * x) are allowed, and are represented as variables.
The solver is additionally capable of propagating information back to the metaphorical grind whiteboard, which can trigger further progress from the other subsystems.
By default, it is enabled; it can be disabled using the flag -lia
Examples of Linear Integer Arithmetic
All of these statements can be proved using the linear integer arithmetic solver. In the first example, the left-hand side must be a multiple of 2, and thus cannot be 5:
example {x y : Int} : 2 * x + 4 * y ≠ 5 := x:Inty:Int⊢ 2 * x + 4 * y ≠ 5
All goals completed! 🐙
The solver supports mixing equalities and inequalities:
example {x y : Int} :
2 * x + 3 * y = 0 →
1 ≤ x →
y < 1 := x:Inty:Int⊢ 2 * x + 3 * y = 0 → 1 ≤ x → y < 1
All goals completed! 🐙
It also supports linear divisibility constraints:
example (a b : Int) :
2 ∣ a + 1 →
2 ∣ b + a →
¬ 2 ∣ b + 2 * a := a:Intb:Int⊢ 2 ∣ a + 1 → 2 ∣ b + a → ¬2 ∣ b + 2 * a
All goals completed! 🐙
Without lia, grind cannot prove the statement:
example (a b : Int) :
2 ∣ a + 1 →
2 ∣ b + a →
¬ 2 ∣ b + 2 * a := a:Intb:Int⊢ 2 ∣ a + 1 → 2 ∣ b + a → ¬2 ∣ b + 2 * a
All goals completed! 🐙
16.9.1. Rational Solutions
The solver is complete for linear integer arithmetic.
However, the search can become vast with very few constraints, but the solver was not designed to perform massive case-analysis.
The qlia option to grind reduces the search space by instructing the solver to accept rational solutions.
With this option, the solver is likely to be faster, but it is incomplete.
Rational Solutions
The following example has a rational solution, but does not have integer solutions:
example {x y : Int} :
27 ≤ 13 * x + 11 * y →
13 * x + 11 * y ≤ 30 →
-10 ≤ 9 * x - 7 * y →
9 * x - 7 * y > 4 := x:Inty:Int⊢ 27 ≤ 13 * x + 11 * y → 13 * x + 11 * y ≤ 30 → -10 ≤ 9 * x - 7 * y → 9 * x - 7 * y > 4
All goals completed! 🐙
Because it uses the rational solution, grind fails to refute the negation of the goal when +qlia is specified:
example {x y : Int} :
27 ≤ 13 * x + 11 * y →
13 * x + 11 * y ≤ 30 →
-10 ≤ 9 * x - 7 * y →
9 * x - 7 * y > 4 := x:Inty:Int⊢ 27 ≤ 13 * x + 11 * y → 13 * x + 11 * y ≤ 30 → -10 ≤ 9 * x - 7 * y → 9 * x - 7 * y > 4
All goals completed! 🐙
The rational model constructed by the solver is in the section Assignment satisfying linear constraints in the goal diagnostics.
16.9.2. Nonlinear Constraints
The solver currently does support nonlinear constraints, and treats nonlinear terms such as x * x as variables.
Nonlinear Terms
The linear integer arithmetic solver fails to prove this theorem:
example (x : Int) : x * x ≥ 0 := x:Int⊢ x * x ≥ 0
All goals completed! 🐙
From the perspective of the linear integer arithmetic solver, it is equivalent to:
example {y : Int} (x : Int) : y ≥ 0 := y:Intx:Int⊢ y ≥ 0
All goals completed! 🐙
This can be seen by setting the option trace.grind.lia.assert to true, which traces all constraints processed by the solver.
example (x : Int) : x*x ≥ 0 := x:Int⊢ x * x ≥ 0
set_option trace.grind.lia.assert true in
All goals completed! 🐙
The term x ^ 2 is “quoted” in 「x ^ 2」 + 1 ≤ 0 to indicate that x ^ 2 is treated as a variable.
16.9.3. Division and Modulus
The solver supports linear division and modulo operations.
16.9.4. Algebraic Processing
The solver normalizes commutative (semi)ring expressions.
16.9.5. Propagating Information
The solver also implements model-based theory combination, which is a mechanism for propagating equalities back to the metaphorical shared whiteboard.
These additional equalities may in turn trigger new congruences.
Model-based theory combination increases the size of the search space; it can be disabled using the option grind -mbtc.
Propagating Equalities
In the example above, the linear inequalities and disequalities imply y = 0:
example (f : Int → Int) (x y : Int) :
f x = 0 →
0 ≤ y → y ≤ 1 → y ≠ 1 →
f (x + y) = 0 := f:Int → Intx:Inty:Int⊢ f x = 0 → 0 ≤ y → y ≤ 1 → y ≠ 1 → f (x + y) = 0
All goals completed! 🐙
Consequently x = x + y, so f x = f (x + y) by congruence.
Without model-based theory combination, the proof gets stuck:
example (f : Int → Int) (x y : Int) :
f x = 0 →
0 ≤ y → y ≤ 1 → y ≠ 1 →
f (x + y) = 0 := f:Int → Intx:Inty:Int⊢ f x = 0 → 0 ≤ y → y ≤ 1 → y ≠ 1 → f (x + y) = 0
All goals completed! 🐙
16.9.6. Other Types
The LIA solver can also process linear constraints that contain Nat, Fin, BitVec, UInt8–UInt64, USize, Int8–Int64, and ISize.
Internally, it converts them into integer constraints using homomorphism rewrites.
Natural Numbers as Linear Integer Arithmetic
Embedding Fixed-Size Types Into Integer Arithmetic
These examples embed fixed-size types into integer arithmetic.
example (a b c : Fin 11) : a ≤ 2 → b ≤ 3 → c = a + b → c ≤ 5 := a:Fin 11b:Fin 11c:Fin 11⊢ a ≤ 2 → b ≤ 3 → c = a + b → c ≤ 5
All goals completed! 🐙
example (a : Fin 2) : a ≠ 0 → a ≠ 1 → False := a:Fin 2⊢ a ≠ 0 → a ≠ 1 → False
All goals completed! 🐙
example (a b c : UInt64) : a ≤ 2 → b ≤ 3 → c - a - b = 0 → c ≤ 5 := a:UInt64b:UInt64c:UInt64⊢ a ≤ 2 → b ≤ 3 → c - a - b = 0 → c ≤ 5
All goals completed! 🐙
16.9.7. Implementation Notes
The implementation of the linear integer arithmetic solver is inspired by Section 4 of Jovanović and de Moura (2023)Dejan Jovanović and Leonardo de Moura, 2023. “Cutting to the Chase: Solving Linear Integer Arithmetic”. In Automated Deduction: CADE '23. (LNCS 6803). Compared to the paper, it includes several enhancements and modifications such as:
-
extended constraint support (equality and disequality),
-
an optimized encoding of the
Cooper-Leftrule using a “big”-disjunction instead of fresh variables, and -
decision variable tracking for case splits (disequalities,
Cooper-Left,Cooper-Right).
The solver procedure builds a model (that is, an assignment of the variables in the term) incrementally, resolving conflicts through constraint generation.
For example, given a partial model {x := 1} and constraint 3 ∣ 3 * y + x + 1:
-
The solver cannot extend the model to
ybecause3 ∣ 3 * y + 2is unsatisfiable. -
Thus, it resolves the conflict by generating the implied constraint
3 ∣ x + 1. -
The new constraint forces the solver to find a new assignment for
x.
When assigning a variable y, the solver considers:
-
The best upper and lower bounds (inequalities).
-
A divisibility constraint.
-
All disequality constraints where
yis the maximal variable.
The Cooper-Left and Cooper-Right rules handle the combination of inequalities and divisibility.
For unsatisfiable disequalities p ≠ 0, the solver generates the case split: p + 1 ≤ 0 ∨ -p + 1 ≤ 0.