Zulip Chat Archive
Stream: new members
Topic: help with lean proofs for new number system
prodgang (Apr 01 2025 at 20:57):
Hello, I've recently finished writing up some results about a new number system I've been working on. The results are legit (including some nice heyting algebras) and to dispel crackpot allegations, I had hoped to also formalize the proofs in lean but struggled with the nested inductions they kept producing. Would anyone be willing to help me with this?
The main results are summarized here and my failed lean proofs are here.
I apologize if this is not the appropriate place to be posting this, let me know if there is a better option. Many thanks!
Notification Bot (Apr 02 2025 at 03:47):
This topic was moved here from #maths > help with lean proofs for new number system by Johan Commelin.
Jz Pan (Apr 02 2025 at 08:27):
I think you shouldn't use axiom prod_pad (ps : List prod_num) : prod_num.pli (ps ++ [prod_num.p0]) = prod_num.pli ps
. You should call your pre_prod_num
, define an equivalence relation on it, and define prod_num
as a quotient type of it. Ideally you should also provide DecidableEq pre_prod_num
instances, etc.
prodgang (Apr 02 2025 at 13:31):
Thanks will try this out. What makes you think it would be easier?
Matt Diamond (Apr 02 2025 at 21:42):
In general it's a good idea to avoid axioms if you can, and the "Type
is quotient of preType
" pattern is common in Mathlib
Eric Wieser (Apr 02 2025 at 22:29):
I think this result might already exist in mathlib as docs#Nat.factorization
(your "prods" type is trivially isomorphic to mathlib's ℕ →₀ ℕ
)
Eric Wieser (Apr 02 2025 at 22:31):
prodgang said:
my failed lean proofs are here.
It's very important when sharing Lean proofs to also commit the lakefile.*
and lake-manifest.json
files that should have been generated with lake new
. Can you add these?
Kevin Buzzard (Apr 02 2025 at 23:00):
Eric Wieser said:
I think this result might already exist in mathlib as docs#Nat.factorization(your "prods" type is trivially isomorphic to mathlib's
ℕ →₀ ℕ
)
Is this true? That type is Additive (PNat)
. The type in question has terms like [p0,p0,p0]
and [p0]
which both eval to 1, and terms like [[p0],p0]
and [[[p0]]]
and [[p0,p0],p0]
that all eval to 2 etc.
Eric Wieser (Apr 02 2025 at 23:08):
The bit I crossed out or the other bit?
Eric Wieser (Apr 02 2025 at 23:09):
On reflection I think you're right though, they're not isomorphic after all!
Eric Wieser (Apr 02 2025 at 23:31):
Jz Pan said:
You should call your
pre_prod_num
, define an equivalence relation on it, and defineprod_num
as a quotient type of it.
Or define an inductive predicate:
inductive PreProdNum : Type
| p0 : PreProdNum
| pli (l : List PreProdNum) : PreProdNum
inductive PreProdNum.IsProper : PreProdNum → Prop
/-- p0 is proper. -/
| p0 : IsProper .p0
/-- A concatenation is proper if all elements are, and the last element is not `p0`. -/
| concat (ps ps' : List PreProdNum) (hps : ∀ p ∈ ps, p.IsProper) (hps' : ∀ p ∈ ps', p.IsProper):
IsProper (.pli <| ps ++ [.pli ps'])
abbrev ProdNum := {p : PreProdNum // p.IsProper }
Jz Pan (Apr 03 2025 at 05:49):
Eric Wieser said:
Or define an inductive predicate
Good idea! At first I want to define PreProdNum.pli
by requiring the tail of the list is not equal to p0
, but seems that it's not possible:
inductive Test : Type
| zero : Test
| test (a b : Test) (hb : b ≠ Test.zero) : Test -- not possible
Jz Pan (Apr 03 2025 at 06:05):
Do you think this is better?
inductive PreProdNum : Type
| p0 : PreProdNum
| pli (l : List PreProdNum) : PreProdNum
def PreProdNum.IsProper : PreProdNum → Prop
| p0 => True
| pli (l : List PreProdNum) => l.getLast? ≠ some p0
-- TODO: `DecidableEq PreProdNum` and `DecidablePred PreProdNum.IsProper`
@[simp]
theorem PreProdNum.isProper_p0 : p0.IsProper := trivial
@[simp]
theorem PreProdNum.isProper_pli_iff (l : List PreProdNum) :
(pli l).IsProper ↔ l.getLast? ≠ some p0 := Iff.rfl
example : (PreProdNum.pli []).IsProper := by simp
abbrev ProdNum := { p : PreProdNum // p.IsProper }
Jz Pan (Apr 03 2025 at 06:19):
I don't know how to write this sorry
, as I need to use DecidableEq PreProdNum
recursively...
instance : DecidableEq PreProdNum
| .p0, .p0 => .isTrue rfl
| .p0, .pli _ => .isFalse nofun
| .pli _, .p0 => .isFalse nofun
| .pli l1, .pli l2 => sorry
instance : DecidablePred PreProdNum.IsProper
| .p0 => .isTrue trivial
| .pli l =>
if h : l.getLast? = some .p0 then
.isFalse (by simp [PreProdNum.IsProper, h])
else
.isTrue h
prodgang (Apr 03 2025 at 11:30):
Eric Wieser said:
It's very important when sharing Lean proofs to also commit the
lakefile.*
andlake-manifest.json
files that should have been generated withlake new
. Can you add these?
Apologies - fixed.
prodgang (Apr 03 2025 at 11:31):
Eric Wieser said:
On reflection I think you're right though, they're not isomorphic after all!
Prods do end up being isomorphic to nats - thats the first big theorem im trying to prove (its not trivial).
Aaron Liu (Apr 03 2025 at 12:48):
Since they're isomorphic to Nat
, you could "cheat" and just implement them as Nat
:
import Mathlib
def ProdNum := Nat
@[inline]
def ProdNum.toNat : ProdNum ≃ Nat := Equiv.refl _
instance : Zero ProdNum := ⟨ProdNum.toNat.symm 0⟩
def ProdNum.ofList (xs : List ProdNum) : ProdNum :=
go xs 1 1
where
go (xs : List ProdNum) (n : Nat) (acc : Nat) : ProdNum :=
match xs with
| [] => acc
| x :: xs =>
let n := n + 1
let n := n + Nat.find
(show (∃ m, Nat.Prime (n + m)) by
obtain ⟨m, hnm, hm⟩ := Nat.exists_infinite_primes n
use m - n
rwa [add_tsub_cancel_of_le hnm])
go xs n (acc * n ^ toNat x)
-- etc
Eric Wieser (Apr 03 2025 at 12:57):
Jz Pan said:
Do you think this is better?
def PreProdNum.IsProper : PreProdNum → Prop | p0 => True | pli (l : List PreProdNum) => l.getLast? ≠ some p0
this doesn't work, you're missing the fact that everything in l
is also proper
Eric Wieser (Apr 03 2025 at 12:58):
The nice thing about my spelling is you get a possibly-useful induction principle
prodgang (Apr 03 2025 at 13:20):
Yeah there definitely needs to be an easy to use induction. I need to be able to implement proofs like this one
prodgang (Apr 03 2025 at 13:26):
Eric Wieser said:
abbrev ProdNum := {p : PreProdNum // p.IsProper }
It seems like this would ban prods from ending with zeros. But its very important I can pad with zeros because there are binary relations which require both arguments to be the same length. It should just be that padding with zeros preserves equality
Jz Pan (Apr 03 2025 at 19:20):
So it's best to use quotient type approach.
Eric Wieser (Apr 03 2025 at 20:31):
I suspect that padding with zeros is not useful after all
Eric Wieser (Apr 03 2025 at 20:31):
If the padding is irrelevant, then by definition you should not need to add it
Kyle Miller (Apr 03 2025 at 20:36):
Jz Pan said:
So it's best to use quotient type approach.
If it's possible to normalize terms, often it's better to define a type using normalized terms, and then define a normalization function — this is the quotient map. You don't need to use Quot
/Quotient
to have quotient types. A quotient is any type that satisfies the universal property.
Eric Wieser (Apr 03 2025 at 20:47):
Here's an example of defining the graft operation without introducing trailing zeros:
@[simp]
def PreProdNum.sup : PreProdNum → PreProdNum → PreProdNum
| .p0, x => x
| x, .p0 => x
| .pli xs, .pli ys => .pli (supList xs ys)
where
supList : List PreProdNum → List PreProdNum → List PreProdNum
| [], ys => ys
| xs, [] => xs
| (x :: xs), (y :: ys) => x.sup y :: supList xs ys
Eric Wieser (Apr 03 2025 at 20:51):
Proving
theorem PreProdNum.IsProper.sup {x y : PreProdNum} (hx : x.IsProper) (hy : y.IsProper) :
(x.sup y).IsProper := by
looks to be quite fiddly though, so perhaps this definition (or the definition of IsProper
isn't the most convenient
Jz Pan (Apr 04 2025 at 06:21):
Eric Wieser said:
this doesn't work, you're missing the fact that everything in
l
is also proper
I try to fix it with this:
inductive PreProdNum : Type
| p0 : PreProdNum
| pli (l : List PreProdNum) : PreProdNum
def PreProdNum.IsProper : PreProdNum → Prop
| p0 => True
| pli (l : List PreProdNum) => l.getLast? ≠ some p0 ∧ ∀ n, (l.getD n p0).IsProper
but it complains for termination proof in PreProdNum.IsProper
...
Jz Pan (Apr 04 2025 at 06:25):
OK this works, but a little bit stupid:
inductive PreProdNum : Type
| p0 : PreProdNum
| pli (l : List PreProdNum) : PreProdNum
def PreProdNum.IsProper : PreProdNum → Prop
| p0 => True
| pli [] => True
| pli (x :: xs) => x.IsProper ∧ (pli xs).IsProper ∧ (x :: xs).getLast? ≠ some p0
Jz Pan (Apr 04 2025 at 06:26):
prodgang said:
Eric Wieser said:
abbrev ProdNum := {p : PreProdNum // p.IsProper }
It seems like this would ban prods from ending with zeros. But its very important I can pad with zeros because there are binary relations which require both arguments to be the same length. It should just be that padding with zeros preserves equality
You can define the "pad zero" function by l.getD n .p0
.
Last updated: May 02 2025 at 03:31 UTC