Zulip Chat Archive

Stream: lean4

Topic: Array gripes


James Gallicchio (Nov 02 2023 at 17:57):

this is a complain-y thread, but I am hoping to learn something:

The design of Array and GetElem just makes me feel like it's working against me in the realm of proof. Just as an example (all of these are with Std imported):

abbrev mem (x : α) (A : Array α) :=  i : Fin A.size, A[i] = x
example : ¬(mem x #[]) := by simp; intros; sorry

I didn't try very hard to prove this, but it also shouldn't be hard to prove this?

and you might ask, James, why are you using a non-standard definition of mem on arrays?? well, because this doesn't compile:

example : ¬(x  (#[] : Array α)) := by sorry

because the Membership instance (from core!) requires DecidableEq for some reason. okay fine, let's weaken the statement then:

example (x : α) [DecidableEq α] : ¬(x  (#[] : Array α)) := by sorry

but proving this requires digging into very complicated definitions. I know that the answer is probably "add more simp lemmas", but I'm really struggling to blindly believe this is the right solution, compared with re-thinking our approach.

thoughts or hope would be appreciated.

David Renshaw (Nov 02 2023 at 18:05):

abbrev mem (x : α) (A : Array α) :=  i : Fin A.size, A[i] = x
example : ¬(mem x #[]) := by
  simp
  intros y
  cases Nat.not_succ_le_zero (y) y.prop

James Gallicchio (Nov 02 2023 at 18:08):

ok, if you want an example that doesn't have an escape hatch from digging through the expressions:

example (x y : A) : x  y  ¬(mem x #[y]) := by
  simp
  intros y
  sorry

James Gallicchio (Nov 02 2023 at 18:09):

(or maybe I should generalize further to Array.push so that you can't just case on the value of Fin 1)

James Gallicchio (Nov 02 2023 at 18:11):

contrast with list, where simp can just do it:

example (x y : A) : x  y  ¬(x  [y]) := by simp
example (xs : List A) (x y : A) : ¬(x  xs)  x  y  (¬ x  xs ++ [y]) := by
  intros; simp [*]

Kyle Miller (Nov 02 2023 at 18:12):

I can't see why DecidableEq is necessary -- the type of docs#Array.instMembershipArray doesn't require it... If you check the term, the DecidableEq instance doesn't even appear.

James Gallicchio (Nov 02 2023 at 18:12):

then that must have changed since 4.2.0-rc1

Kyle Miller (Nov 02 2023 at 18:13):

I'm not saying I'm not seeing the same behavior

Kyle Miller (Nov 02 2023 at 18:14):

It seems like the real issue is some interaction with autoImplicit

Kyle Miller (Nov 02 2023 at 18:15):

Try this:

example (x : α) : ¬(x  (#[] : Array α)) := by
  sorry

James Gallicchio (Nov 02 2023 at 18:16):

oh, Joachim just changed this 4 days ago

James Gallicchio (Nov 02 2023 at 18:16):

https://github.com/leanprover/lean4/pull/2774

Kyle Miller (Nov 02 2023 at 18:16):

Oh, so he did (I just checked the blame)

Kyle Miller (Nov 02 2023 at 18:18):

Still, even with this change, I found that adding DecidableEq somehow made it go through, as did adding (x : α), or adding a variable line to introduce α

Kyle Miller (Nov 02 2023 at 18:22):

Re Array and GetElem, it seems worth adding the Array version of docs#List.mem_iff_get so that you can go back and forth between your Exists formulation and the main definition.

James Gallicchio (Nov 02 2023 at 18:25):

well, the new definition is also fine for my use case, because I can write a lemma that Array.push A x = Array.ofList (A.toList ++ [x]). But I'd prefer if that lemma were simp.

Jun Yoshida (Nov 03 2023 at 03:15):

Oh, I didn't know the membership relation on Array was changed. I agree that DecidableEq-free version is appreciated, but this is a serious breaking change (wrt my personal projects).
Specifically, the change drops the link between Membership and Array.contains, so I need to replace code like

if h : n  #[1,2,3] then sorry else sorry

to the ones using Array.contains.
So, I would like to ask if there is any plan that the core / Std has theorem like this:

theorem Array.mem_iff_contains
    {α : Type _} [DecidableEq α] {a : α} {as : Array α} :
    a  as  as.contains a :=
  sorry

The following is my solution extracted from my project (I hide it since it's huge), but I hesitate to make PR on it since the code is not clean and contains a bunch of materials.

Proof of Array.mem_iff_contains

Mario Carneiro (Nov 03 2023 at 03:16):

This should definitely be a theorem in Std (we shouldn't have shipped without it, sorry)

Mario Carneiro (Nov 03 2023 at 03:19):

In fact it seems there isn't even a decidable instance? That theorem would need to be part of it

Jun Yoshida (Nov 03 2023 at 03:23):

Mario Carneiro said:

In fact it seems there isn't even a decidable instance? That theorem would need to be part of it

I hope that Decidable (a ∈ #[1,2,3]) wouldn't go through Array.toList but just use Array.contains since the former is way slow. That is one reason we need Array.mem_iff_contains above.

Mario Carneiro (Nov 03 2023 at 03:28):

yes, that's what I mean

Jun Yoshida (Nov 03 2023 at 03:44):

I see, thanks. I just wanted to make sure I understand the situation correctly.

Mario Carneiro (Nov 03 2023 at 03:45):

I'll push a fix soon

Mario Carneiro (Nov 03 2023 at 05:44):

@Jun Yoshida fixed

Jun Yoshida (Nov 03 2023 at 05:53):

@Mario Carneiro Great! Thank you for all your efforts making the fix so quickly.


Last updated: Dec 20 2023 at 11:08 UTC