Deriving a proof of false #
linarith
uses an untrusted oracle to produce a certificate of unsatisfiability.
It needs to do some proof reconstruction work to turn this into a proof term.
This file implements the reconstruction.
Main declarations #
The public facing declaration in this file is proveFalseByLinarith
.
Auxiliary functions for assembling proofs #
A typesafe version of mulExpr
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
mulExpr n e
creates an Expr
representing n*e
.
When elaborated, the coefficient will be a native numeral of the same type as e
.
Equations
- Linarith.mulExpr n e = do let __discr ← Qq.inferTypeQ' e match __discr with | ⟨fst, ⟨α, e⟩⟩ => do let inst ← Qq.synthInstanceQ q(Semiring «$α») pure (Linarith.mulExpr' n inst e)
Instances For
A type-safe analogue of addExprs
.
Equations
- Linarith.addExprs' _inst [] = q(0)
- Linarith.addExprs' _inst (h :: t) = Linarith.addExprs'.go _inst h t
Instances For
Inner loop for addExprs'
.
Equations
- Linarith.addExprs'.go _inst p [] = p
- Linarith.addExprs'.go _inst p [q] = q(«$p» + «$q»)
- Linarith.addExprs'.go _inst p (q :: t) = Linarith.addExprs'.go _inst q(«$p» + «$q») t
Instances For
addExprs L
creates an Expr
representing the sum of the elements of L
, associated left.
Equations
- One or more equations did not get rendered due to their size.
- Linarith.addExprs [] = pure q(0)
Instances For
If our goal is to add together two inequalities t1 R1 0
and t2 R2 0
,
addIneq R1 R2
produces the strength of the inequality in the sum R
,
along with the name of a lemma to apply in order to conclude t1 + t2 R 0
.
Equations
- Linarith.addIneq Mathlib.Ineq.eq Mathlib.Ineq.eq = (`Linarith.eq_of_eq_of_eq, Mathlib.Ineq.eq)
- Linarith.addIneq Mathlib.Ineq.eq Mathlib.Ineq.le = (`Linarith.le_of_eq_of_le, Mathlib.Ineq.le)
- Linarith.addIneq Mathlib.Ineq.eq Mathlib.Ineq.lt = (`Linarith.lt_of_eq_of_lt, Mathlib.Ineq.lt)
- Linarith.addIneq Mathlib.Ineq.le Mathlib.Ineq.eq = (`Linarith.le_of_le_of_eq, Mathlib.Ineq.le)
- Linarith.addIneq Mathlib.Ineq.le Mathlib.Ineq.le = (`add_nonpos, Mathlib.Ineq.le)
- Linarith.addIneq Mathlib.Ineq.le Mathlib.Ineq.lt = (`add_lt_of_le_of_neg, Mathlib.Ineq.lt)
- Linarith.addIneq Mathlib.Ineq.lt Mathlib.Ineq.eq = (`Linarith.lt_of_lt_of_eq, Mathlib.Ineq.lt)
- Linarith.addIneq Mathlib.Ineq.lt Mathlib.Ineq.le = (`add_lt_of_neg_of_le, Mathlib.Ineq.lt)
- Linarith.addIneq Mathlib.Ineq.lt Mathlib.Ineq.lt = (`Left.add_neg, Mathlib.Ineq.lt)
Instances For
mkLTZeroProof coeffs pfs
takes a list of proofs of the form tᵢ Rᵢ 0
,
paired with coefficients cᵢ
.
It produces a proof that ∑cᵢ * tᵢ R 0
, where R
is as strong as possible.
Equations
- One or more equations did not get rendered due to their size.
- Linarith.mkLTZeroProof [] = Lean.throwError (Lean.toMessageData "no linear hypotheses found")
- Linarith.mkLTZeroProof [(h, c)] = do let __discr ← Linarith.mkSingleCompZeroOf c h match __discr with | (fst, t) => pure t
Instances For
step c pf npf coeff
assumes that pf
is a proof of t1 R1 0
and npf
is a proof
of t2 R2 0
. It uses mkSingleCompZeroOf
to prove t1 + coeff*t2 R 0
, and returns R
along with this proof.
Equations
- One or more equations did not get rendered due to their size.
Instances For
If prf
is a proof of t R s
, leftOfIneqProof prf
returns t
.
Equations
- Linarith.leftOfIneqProof prf = do let __do_lift ← Lean.Meta.inferType prf let __discr ← __do_lift.ineq? match __discr with | (fst, fst_1, t, snd) => pure t
Instances For
If prf
is a proof of t R s
, typeOfIneqProof prf
returns the type of t
.
Equations
- Linarith.typeOfIneqProof prf = do let __do_lift ← Lean.Meta.inferType prf let __discr ← __do_lift.ineq? match __discr with | (fst, ty, snd) => pure ty
Instances For
mkNegOneLtZeroProof tp
returns a proof of -1 < 0
,
where the numerals are natively of type tp
.
Equations
- Linarith.mkNegOneLtZeroProof tp = do let zero_lt_one ← Lean.Meta.mkAppOptM `zero_lt_one #[some tp, none, none, none, none, none] Lean.Meta.mkAppM `neg_neg_of_pos #[zero_lt_one]
Instances For
addNegEqProofs l
inspects the list of proofs l
for proofs of the form t = 0
. For each such
proof, it adds a proof of -t = 0
to the list.
Equations
- One or more equations did not get rendered due to their size.
- Linarith.addNegEqProofs [] = pure []
Instances For
proveEqZeroUsing tac e
tries to use tac
to construct a proof of e = 0
.
Equations
- Linarith.proveEqZeroUsing tac e = do let __discr ← Qq.inferTypeQ' e match __discr with | ⟨u, ⟨α, e⟩⟩ => do let _h ← Qq.synthInstanceQ q(Zero «$α») synthesizeUsing' q(«$e» = 0) tac
Instances For
The main method #
proveFalseByLinarith
is the main workhorse of linarith
.
Given a list l
of proofs of tᵢ Rᵢ 0
,
it tries to derive a contradiction from l
and use this to produce a proof of False
.
oracle : CertificateOracle
is used to search for a certificate of unsatisfiability.
The returned certificate is a map m
from hypothesis indices to natural number coefficients.
If our set of hypotheses has the form {tᵢ Rᵢ 0}
,
then the elimination process should have guaranteed that
1.\ ∑ (m i)*tᵢ = 0
,
with at least one i
such that m i > 0
and Rᵢ
is <
.
We have also that
2.\ ∑ (m i)*tᵢ < 0
,
since for each i
, (m i)*tᵢ ≤ 0
and at least one is strictly negative.
So we conclude a contradiction 0 < 0
.
It remains to produce proofs of (1) and (2). (1) is verified by calling the provided discharger
tactic, which is typically ring
. We prove (2) by folding over the set of hypotheses.
transparency : TransparencyMode
controls the transparency level with which atoms are identified.
Equations
- One or more equations did not get rendered due to their size.
- Linarith.proveFalseByLinarith transparency oracle discharger x [] = Lean.throwError (Lean.toMessageData "no args to linarith")