Zulip Chat Archive
Stream: lean4
Topic: Lean doesn't unfold HAnd.hAnd
Jun Yoshida (Jan 09 2023 at 01:55):
The rfl
in the second line in the following code produces an error:
example : 0x10 * 0x10 = 0x100 := rfl
example : 0x10 &&& 0x10 = 0x10 := rfl -- error
What is the difference between these operators?
I note that the second is a definitional equality as the following compiles:
example : 0x10 &&& 0x10 = 0x10 := by
conv => lhs; pattern HAnd.hAnd; change Nat.land
pcpthm (Jan 09 2023 at 06:11):
This is because Nat.bitwise
used by the definition of Nat.land
is using a well-founded recursion. My understanding is that reduction of a well-founded recursion is possibly non-terminating and thus isn't applied blindly.
I also want to know what is the best way to deal with such functions.
Jun Yoshida (Jan 09 2023 at 07:54):
That sounds right. I tried providing a hand-made instance and verified the following compiles:
def land' (x y : Nat) : Nat := aux x x y Nat.le.refl
where
aux : (n x y : Nat) → n ≥ x → Nat
| 0, _, _, _ => 0
| _+1, 0, _, _ => 0
| _+1, 1, y, _ => y % 2
| n+1, x+2, y, h =>
have : x/2 + 1 ≤ n := Nat.le_of_lt_succ $ calc
x/2 + 1 = (x+2)/2 := Eq.symm $ Nat.add_div_right x (Nat.zero_lt_succ 1)
_ < (x+2) := Nat.div_lt_self (Nat.zero_lt_succ _) (Nat.lt_succ_self 1)
_ ≤ n+1 := h
aux n (x/2 + 1) (y/2) this <<< 1
instance : AndOp Nat := ⟨land'⟩
example : 0x10 &&& 0x10 = 0x10 := rfl
Jun Yoshida (Jan 09 2023 at 08:01):
reduction of a well-founded recursion is possibly non-terminating
I was surprised that the following takes 4-5 seconds to compile:
example : 0xFF &&& 0xFF = 0xFF := by conv => lhs; whnf
Jun Yoshida (Jan 09 2023 at 08:06):
IMHO, Nat.bitwise
should be written without well-founded recursion.
Shreyas Srinivas (Jan 09 2023 at 09:39):
If you are using mathlib4, there is a version called bitwise' whose definition is lean3 style. Perhaps that helps?
Shreyas Srinivas (Jan 09 2023 at 09:40):
There are corresponding land', lor', etc.
Jun Yoshida (Jan 09 2023 at 10:42):
I checked the source of Mathlib4/Init/Data/Nat/Bitwise.lean
in mathlib4. It looks depending on binaryRec
which uses well-founded recursion, right?
Shreyas Srinivas (Jan 09 2023 at 11:30):
True. Normally when using bitwise, unfold
followed by cases works
Jun Yoshida (Jan 10 2023 at 02:52):
Are there any technique to handle such functions with elaborator/tactic? For example, it is boring and actually hard to prove things like 0xFEEDFFFFFFFF &&& 0xFFFFDEADFFFF &&& 0xFFFFFFFFBEEF = 0xFEEDDEADBEEF
by unfolding definitions by hand. With the current implementation of Nat.land
, it is, I think, hard also for Lean compiler since it takes a lot of time and memories.
Mario Carneiro (Jan 10 2023 at 03:14):
This is a job for norm_num
Mario Carneiro (Jan 10 2023 at 03:15):
it's not a high priority though :(
James Gallicchio (Jan 10 2023 at 03:15):
Jun Yoshida said:
IMHO,
Nat.bitwise
should be written without well-founded recursion.
(I think doing it structurally would be waaaay slower, since IIRC the kernel has special handling for div/mod on nats?)
Jun Yoshida (Jan 10 2023 at 03:57):
Mario Carneiro said:
This is a job for
norm_num
Cool! It enables "proof by (tedious) computation" that I sometimes see in papers. Thank you for letting me know. Yet, I have to tell the plugin how to handle with bit operators...
Jun Yoshida (Jan 10 2023 at 04:01):
James Gallicchio said:
(I think doing it structurally would be waaaay slower, since IIRC the kernel has special handling for div/mod on nats?)
Nat.land
, Nat.lor
, ... are anyway implemented by C codes, so I think they can be more "proof-oriented" in Lean codes.
Jun Yoshida (Jan 10 2023 at 04:06):
I found that Lean server (in VS code REPL) crashes with the following:
example : 0xFEEDFFFFFFFF &&& 0xFFFFDEADFFFF &&& 0xFFFFFFFFBEEF = 0xFEEDDEADBEEF := by conv => lhs;
Mario Carneiro (Jan 10 2023 at 04:47):
Jun Yoshida said:
James Gallicchio said:
(I think doing it structurally would be waaaay slower, since IIRC the kernel has special handling for div/mod on nats?)
Nat.land
,Nat.lor
, ... are anyway implemented by C codes, so I think they can be more "proof-oriented" in Lean codes.
Not exactly. The C code for Nat.land
et al is only used by the compiler, not the kernel, so if you are trying to use it in a proof by rfl
or by decide
you still have to care about the performance of the lean model of the operation.
Mario Carneiro (Jan 10 2023 at 04:48):
Only +
,-
,*
,/
,%
,<
on Nat
are overridden in the kernel as well as the compiler
Jun Yoshida (Jan 10 2023 at 05:00):
Ah, that is right. I am sorry for my imprecise statement. I am not sure that well-founded recursion is faster than stractural recursion from kernel point of view. In my experience, wf seems slower.
Mario Carneiro (Jan 10 2023 at 05:16):
It is more complex. More importantly, it often simply doesn't reduce due to hitting a theorem
, which is treated the same as opaque
and will block reduction to a constructor. Reducing proofs by well founded recursion requires reducing the proof of well foundedness, so this usually gets stuck
James Gallicchio (Jan 10 2023 at 06:22):
And with those large nats I would imagine that doing 2^48 reduction steps would not be performant in the kernel, compared to doing 48 steps + reducing the well-foundedness proof
Mario Carneiro (Jan 10 2023 at 06:59):
You can implement it as doing 48 steps without reducing any well-foundedness proof by doing structural induction on a fuel variable. Even if the initial value of the fuel variable is 2^48 or so it won't step any more than necessary because the kernel works from the outside in using whnf to evaluate stuff so if 48 steps of recursion suffices then it won't work out the rest
Mario Carneiro (Jan 10 2023 at 07:00):
which looks like what Jun Yoshida 's land'
function is doing
James Gallicchio (Jan 10 2023 at 07:16):
Ahh I see, sorry for misunderstanding
Jun Yoshida (Jan 10 2023 at 13:19):
Thank you for elaborating my example. Yes, every well-founded recursion w.r.t. Nat.lt
can be transformed into a structural recursion in the same idea. But, writing examples, I realized that the resulting functions become complicated and far from the straightforward implementation. I now agree that definitions should be kept concise. Reduction is not always the best way to prove equations.
Jun Yoshida (Jan 10 2023 at 13:20):
So, what should I do is probably to write the proof of hAnd_eq_land' : ∀ (x y : Nat), x &&& y = land' x y
and to do something like rw [hAnd_eq_land']; cong => lhs; whnf
.
Jun Yoshida (Jan 10 2023 at 13:21):
Thank you for comments and advice.
Mario Carneiro (Jan 10 2023 at 17:27):
I think another way to spell congr => lhs; whnf
is rfl
Last updated: Dec 20 2023 at 11:08 UTC