Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
00f4eb5
test
Jan 24, 2026
6165595
Revert "test"
Jan 25, 2026
38e69bf
Merge branch 'master' of https://github.com/DavidLedvinka/mathlib4
Jan 26, 2026
97b18e8
Merge branch 'master' of https://github.com/DavidLedvinka/mathlib4
Jan 29, 2026
72423dd
Merge branch 'master' of https://github.com/DavidLedvinka/mathlib4
Feb 1, 2026
0ba4995
erge branch 'master' of https://github.com/DavidLedvinka/mathlib4
Feb 2, 2026
606e9d8
Merge branch 'master' of https://github.com/DavidLedvinka/mathlib4
Feb 5, 2026
f753b22
Merge branch 'master' of https://github.com/DavidLedvinka/mathlib4
Feb 8, 2026
3adde15
Merge branch 'master' of https://github.com/DavidLedvinka/mathlib4
Feb 9, 2026
c56ec98
Merge branch 'master' of https://github.com/DavidLedvinka/mathlib4
Feb 10, 2026
261cdd6
draft
Feb 11, 2026
35566bb
fix
Feb 11, 2026
acbb85a
test
Feb 11, 2026
de7c035
typo
Feb 11, 2026
fb67fc0
fix again
Feb 11, 2026
3e648c0
small updates
Feb 11, 2026
63d15b4
documentation add
Feb 11, 2026
9cc29c7
mk_all
Feb 12, 2026
f663d26
test
Feb 12, 2026
5a3665c
tests
Feb 12, 2026
d86ec02
metaMify
Feb 12, 2026
72f61fd
fix division bug
Feb 12, 2026
10d53e4
fix year
Feb 12, 2026
9a858c0
fix unintended addition
DavidLedvinka Feb 13, 2026
911ea8b
fix typo
DavidLedvinka Feb 13, 2026
ac76289
Update Mathlib/Tactic/Linarith/NNRealPreprocessor.lean
DavidLedvinka Feb 13, 2026
c05eaa3
Update Mathlib/Tactic/Linarith/Preprocessing.lean
DavidLedvinka Feb 13, 2026
867d3aa
impliment suggestions
Feb 13, 2026
706f1a7
Update Rify.lean
DavidLedvinka Feb 14, 2026
af275a7
fix
Feb 15, 2026
ba6377a
Merge branch 'linarith_for_nnreal' of https://github.com/DavidLedvink…
Feb 15, 2026
4f23e02
re-add Qify
Feb 15, 2026
2f99e41
update
Feb 16, 2026
6d4c105
delete accidental test code
Feb 16, 2026
4d8dc87
Merge branch 'master' into linarith_for_nnreal
Feb 18, 2026
6977b75
Update Mathlib/Tactic/Rify.lean
DavidLedvinka Feb 18, 2026
c61b056
Update Mathlib/Tactic/Linarith/Preprocessing.lean
DavidLedvinka Feb 18, 2026
a3989c0
adjustments
Feb 18, 2026
37efab3
ci: rerun
Feb 18, 2026
e6520a4
Update Mathlib/Tactic/Rify.lean
DavidLedvinka Feb 19, 2026
aaee6c3
Merge branch 'master' into linarith_for_nnreal
Feb 19, 2026
3ab28e1
Merge branch 'linarith_for_nnreal' of https://github.com/DavidLedvink…
Feb 19, 2026
76b275e
Merge branch 'master' into linarith_for_nnreal
DavidLedvinka Feb 19, 2026
6bd751e
Update Mathlib/Tactic/Rify.lean
DavidLedvinka Feb 21, 2026
9249463
Update Mathlib/Tactic/Rify.lean
DavidLedvinka Feb 21, 2026
028b601
Update Mathlib/Tactic/Linarith/NNRealPreprocessor.lean
DavidLedvinka Feb 21, 2026
25b74ce
Update Mathlib/Tactic/Linarith/NNRealPreprocessor.lean
DavidLedvinka Feb 21, 2026
c2036ba
Update Mathlib/Tactic/Linarith/NNRealPreprocessor.lean
DavidLedvinka Feb 21, 2026
c5b10eb
apply suggestions
Feb 21, 2026
669cbcb
add comment
Feb 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -6826,6 +6826,7 @@ public import Mathlib.Tactic.Linarith
public import Mathlib.Tactic.Linarith.Datatypes
public import Mathlib.Tactic.Linarith.Frontend
public import Mathlib.Tactic.Linarith.Lemmas
public import Mathlib.Tactic.Linarith.NNRealPreprocessor
public import Mathlib.Tactic.Linarith.Oracle.FourierMotzkin
public import Mathlib.Tactic.Linarith.Oracle.SimplexAlgorithm
public import Mathlib.Tactic.Linarith.Oracle.SimplexAlgorithm.Datatypes
Expand Down
18 changes: 18 additions & 0 deletions Mathlib/Data/NNReal/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ typeclass. For lemmas about subtraction and addition see lemmas about `OrderedSu
theorem sub_div (a b c : ℝ≥0) : (a - b) / c = a / c - b / c :=
tsub_div _ _ _

/-- This lemma is needed for the `norm_cast` simp set. Outside of this use case `Nat.coe_sub`
should be used. -/
@[norm_cast]
protected theorem coe_sub_of_lt {a b : ℝ≥0} (h : a < b) :
Comment thread
DavidLedvinka marked this conversation as resolved.
((b - a : ℝ≥0) : ℝ) = b - a := NNReal.coe_sub h.le

end Sub

section Csupr
Expand Down Expand Up @@ -210,6 +216,18 @@ set_option backward.isDefEq.respectTransparency false in

end Csupr

section rify

@[rify_simps] lemma toReal_eq (a b : ℝ≥0) : a = b ↔ (a : ℝ) = (b : ℝ) := by simp

@[rify_simps] lemma toReal_le (a b : ℝ≥0) : a ≤ b ↔ (a : ℝ) ≤ (b : ℝ) := by simp

@[rify_simps] lemma toReal_lt (a b : ℝ≥0) : a < b ↔ (a : ℝ) < (b : ℝ) := by simp

@[rify_simps] lemma toReal_ne (a b : ℝ≥0) : a ≠ b ↔ (a : ℝ) ≠ (b : ℝ) := by simp

end rify

@[simp]
theorem range_coe : range toReal = Ici 0 := Subtype.range_coe

Expand Down
1 change: 1 addition & 0 deletions Mathlib/Tactic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public import Mathlib.Tactic.Linarith
public import Mathlib.Tactic.Linarith.Datatypes
public import Mathlib.Tactic.Linarith.Frontend
public import Mathlib.Tactic.Linarith.Lemmas
public import Mathlib.Tactic.Linarith.NNRealPreprocessor
public import Mathlib.Tactic.Linarith.Oracle.FourierMotzkin
public import Mathlib.Tactic.Linarith.Oracle.SimplexAlgorithm
public import Mathlib.Tactic.Linarith.Oracle.SimplexAlgorithm.Datatypes
Expand Down
77 changes: 77 additions & 0 deletions Mathlib/Tactic/Linarith/NNRealPreprocessor.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/-
Copyright (c) 2026 David Ledvinka. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: David Ledvinka
-/
module

public meta import Mathlib.Tactic.Linarith
public meta import Mathlib.Tactic.Rify
public import Mathlib.Data.NNReal.Basic

/-!
# NNReal linarith preprocessing

This file contains a `linarith` preprocessor for converting (in)equalities in `ℝ≥0` to `ℝ`.

By overriding the behaviour of the placeholder preprocessor `nnrealToReal` (which does nothing
unless this file is imported) `linarith` can still be used without importing `NNReal`.
-/

public meta section

namespace Mathlib.Tactic.Linarith

open Lean Meta

/--
`isNNRealProp tp` is true iff `tp` is an inequality or equality between nonnegative real numbers
or the negation thereof.
-/
partial def isNNRealProp (e : Expr) : MetaM Bool := succeeds do
let (_, _, .const ``NNReal _, _, _) ← e.ineqOrNotIneq? | failure

/-- If `e` is of the form `((x : ℝ≥0) : ℝ)`, `NNReal.toReal e` returns `x`. -/
def isNNRealtoReal (e : Expr) : Option Expr :=
match e with
| .app (.const ``NNReal.toReal _) n => some n
| _ => none

/--
`getNNRealComparisons e` returns a list of all subexpressions of `e` of the form `(x : ℝ)`.
-/
partial def getNNRealCoes (e : Expr) : List Expr :=
match isNNRealtoReal e with
| some x => [x]
| none => match e.getAppFnArgs with
| (``HAdd.hAdd, #[_, _, _, _, a, b]) => getNNRealCoes a ++ getNNRealCoes b
| (``HMul.hMul, #[_, _, _, _, a, b]) => getNNRealCoes a ++ getNNRealCoes b
| (``HSub.hSub, #[_, _, _, _, a, b]) => getNNRealCoes a ++ getNNRealCoes b
| (``HDiv.hDiv, #[_, _, _, _, a, _]) => getNNRealCoes a
| (``Neg.neg, #[_, _, a]) => getNNRealCoes a
| _ => []

/-- If `e : ℝ≥0`, returns a proof of `0 ≤ (e : ℝ)`. -/
def mk_toReal_nonneg_prf (e : Expr) : MetaM (Option Expr) :=
try commitIfNoEx (mkAppM ``NNReal.coe_nonneg #[e])
catch e => do
trace[linarith] "Got exception when using `coe_nonneg` {e.toMessageData}"
return none

initialize nnrealToRealTransform.set fun l => do
let l ← l.mapM fun e => do
let t ← whnfR (← instantiateMVars (← inferType e))
if ← isNNRealProp t then
return (← Rify.rifyProof e t).1
else
return e
let atoms : List Expr ← withNewMCtxDepth <| AtomM.run .reducible do
for e in l do
let (_, _, a, b) ← (← inferType e).ineq?
discard <| (getNNRealCoes a).mapM AtomM.addAtom
discard <| (getNNRealCoes b).mapM AtomM.addAtom
return (← get).atoms.toList
let nonneg_pfs : List Expr ← atoms.filterMapM mk_toReal_nonneg_prf
return nonneg_pfs ++ l

end Mathlib.Tactic.Linarith
13 changes: 12 additions & 1 deletion Mathlib/Tactic/Linarith/Preprocessing.lean
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,23 @@ def removeNe : GlobalBranchingPreprocessor where
transform := removeNe_aux
end removeNe

/-- Definition overidden in `Mathlib.Tactic.Linarith.NNRealPreprocessor`. -/
initialize nnrealToRealTransform : IO.Ref (List Expr → MetaM (List Expr)) ← IO.mkRef pure

/--
Comment thread
DavidLedvinka marked this conversation as resolved.
If `h` is an equality or inequality between NNReals, `nnrealToReal` lifts this inequality to the
Reals. It also adds the facts that the reals involved are nonnegative. To avoid adding the same
nonnegativity facts many times, it is a global preprocessor. This preprocessor does nothing unless
`Mathlib.Tactic.Linarith.NNRealPreprocessor` is imported -/
def nnrealToReal : GlobalPreprocessor where
description := "move nnreals to reals"
transform l := do (← nnrealToRealTransform.get) l

/--
The default list of preprocessors, in the order they should typically run.
-/
def defaultPreprocessors : List GlobalBranchingPreprocessor :=
[filterComparisons, removeNegations, natToInt, strengthenStrictInt,
[filterComparisons, removeNegations, nnrealToReal, natToInt, strengthenStrictInt,
compWithZero, cancelDenoms]

/--
Expand Down
24 changes: 23 additions & 1 deletion Mathlib/Tactic/Rify.lean
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ module

public import Mathlib.Data.Rat.Cast.Order
public import Mathlib.Data.Real.Basic
public import Mathlib.Tactic.Zify
public import Mathlib.Tactic.Qify -- shake: keep (for `@[qify_simps]`)

/-!
# `rify` tactic

The `rify` tactic is used to shift propositions from `ℕ`, `ℤ` or `` to `ℝ`.
The `rify` tactic is used to shift propositions from `ℕ`, `ℤ`, `ℚ` or `ℝ≥0` to `ℝ`.

Although less useful than its cousins `zify` and `qify`, it can be useful when your
goal or context already involves real numbers.
Expand Down Expand Up @@ -78,11 +79,32 @@ macro_rules
simp -decide only [zify_simps, qify_simps, rify_simps, push_cast, $args,*]
$[at $location]?)

/-- The `Simp.Context` generated by `rify` (with no optional arguments or local context). -/
def mkRifyContext : MetaM Simp.Context := do
let result ← #[`zify_simps, `qify_simps, `rify_simps, `push_cast].mapM fun ext ↦ do
let some ext ← getSimpExtension? ext | failure
ext.getTheorems
Simp.mkContext {failIfUnchanged := false} (simpTheorems := result)

/-- Translate a proof and the proposition into rified form. -/
def rifyProof (proof : Expr) (prop : Expr) : MetaM (Expr × Expr) := do
let (r, _) ← simp prop (← mkRifyContext)
Zify.applySimpResultToProp' proof prop r

@[rify_simps] lemma ratCast_eq (a b : ℚ) : a = b ↔ (a : ℝ) = (b : ℝ) := by simp
@[rify_simps] lemma ratCast_le (a b : ℚ) : a ≤ b ↔ (a : ℝ) ≤ (b : ℝ) := by simp
@[rify_simps] lemma ratCast_lt (a b : ℚ) : a < b ↔ (a : ℝ) < (b : ℝ) := by simp
@[rify_simps] lemma ratCast_ne (a b : ℚ) : a ≠ b ↔ (a : ℝ) ≠ (b : ℝ) := by simp

/- The following lemmas are included in `Mathlib.Data.NNReal.Basic` (so that they
don't need to be imported when using this tactic for `ℕ, ℤ`, or `ℚ`)

`@[rify_simps] lemma toReal_eq (a b : ℝ≥0) : a = b ↔ (a : ℝ) = (b : ℝ) := by simp`
`@[rify_simps] lemma toReal_le (a b : ℝ≥0) : a ≤ b ↔ (a : ℝ) ≤ (b : ℝ) := by simp`
`@[rify_simps] lemma toReal_lt (a b : ℝ≥0) : a < b ↔ (a : ℝ) < (b : ℝ) := by simp`
`@[rify_simps] lemma toReal_ne (a b : ℝ≥0) : a ≠ b ↔ (a : ℝ) ≠ (b : ℝ) := by simp`
-/

@[rify_simps] lemma ofNat_rat_real (a : ℕ) [a.AtLeastTwo] :
((ofNat(a) : ℚ) : ℝ) = (ofNat(a) : ℝ) := rfl

Expand Down
Comment thread
DavidLedvinka marked this conversation as resolved.
File renamed without changes.
26 changes: 26 additions & 0 deletions MathlibTest/Linarith/NNReal.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Mathlib.Tactic.Linarith.NNRealPreprocessor
import Mathlib.Data.ENNReal.Operations
import Mathlib.Data.ENNReal.Inv

open NNReal

example {a b c : ℝ≥0} (h1 : 2 * a < b + 1) (h2 : b ≤ c) : a < (c + 1) / 2 := by
linarith

example {a b c d : ℝ≥0} (h1 : 3 * a + 2 * b ≤ 5 * c + 7) (h2 : c ≤ d) : a ≤ (5 * d + 7) / 3 := by
linarith

example {a b c d e : ℝ≥0} (h1 : (a + b) / 2 + c ≤ d) (h2 : d ≤ e) : a ≤ 2 * e := by
linarith

example {a b c d : ℝ≥0} (h1 : (a + 3 * b) / 4 < c + 1) (h2 : c ≤ d) : a < 4 * (d + 1) := by
linarith

example {a b c d : ℝ≥0} (h1 : 2 * a + b ≤ 3 * c) (h2 : c < d + 5) : a < (3 * (d + 5)) / 2 := by
linarith

example {a b c d : ℝ≥0} (h1 : a + b ≤ c) (h2 : c ≤ d / 2) : a ≤ d / 2 := by
linarith

example {a b c d : ℝ≥0} (h1 : a + b ≤ 2 * c + 3) (h2 : c ≤ d) : a ≤ 2 * d + 3 := by
linarith
32 changes: 32 additions & 0 deletions MathlibTest/Rify.lean
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Mathlib.Tactic.Linarith
import Mathlib.Tactic.Rify
import Mathlib.Data.NNReal.Basic

set_option linter.unusedVariables false

Expand Down Expand Up @@ -36,3 +37,34 @@ example {n k : ℕ} (h₁ : 8 ≤ n) (h₂ : 2 * k > n) (h₃ : k + 1 < n) :
have f₂ : n - (k + 1) ≤ n := by rify [f₁]; linarith
rify [f₁, f₂] at *
linarith

/- ℝ≥0 Tests -/

open NNReal
Comment thread
DavidLedvinka marked this conversation as resolved.

example {a : ℝ≥0} {b : ℝ} (ha : 8 ≤ a) (hb : 2 * b ≤ a + 2) :
(0 : ℝ) < a - b - 1 := by
rify at ha hb
linarith

example {a : ℝ≥0} {b : ℝ} (ha : 8 ≤ a) (hb : (2 : ℚ) * b ≤ b + 2) :
(0 : ℝ) < a - b - 1 := by
rify at ha hb
linarith

example (a b c : ℝ≥0) (h : a - b < c) (hab : b ≤ a) : a < b + c := by
rify [hab] at h ⊢
linarith

example {a : ℝ≥0} (h : 8 ≤ a) : (0 : ℝ) < a - 1 := by
rify at h
linarith

example {a b : ℝ≥0} (h : 2 * b ≤ a + 2) (h' : 8 ≤ a) : (0 : ℝ) ≤ 3 * a - 4 - 4 * b := by
rify at *
linarith

example {a b : ℝ≥0} (h₁ : 8 ≤ a) (h₂ : 2 * b > a) (h₃ : b + 1 < a) :
a - (b + 1) + 3 ≤ a := by
rify [h₃] at *
linarith
Loading