Zulip Chat Archive
Stream: lean4
Topic: struggling with a proof
Arthur Paulino (Apr 06 2022 at 12:54):
I'm trying to clear out this sorry
but I'm having two problems:
- I'm not being able to use
induction
onl
because Lean is complaining about a "type mismatch when assigning motive" - Even if I succeeded at using induction, I'm afraid I wouldn't be able to go much further because I don't see a reference to
consume
in the context:
ctx : Context
n : String
es : NEList Expression
ns : NEList String
h : NEList.noDup ns = true
p✝ : Program
l? : Option (NEList String)
p : Program
hs : Option.isSome l? = true
l : NEList String := Option.get l? hs
⊢ NEList.noDup l = true
consume
is a function that consumes an NEList
. So what I'm trying to prove is basically that if the initial NEList
doesn't have duplicated values, then the resulting NEList
won't either.
Leonardo de Moura (Apr 06 2022 at 14:30):
Disclaimer: I did not download/try your example on my machine. So, take the following suggestion with a grain of salt :)
The notation
let (l?, p) := consume p ns es
<rest>
is syntax sugar for
match consume p ns es with
| (l?, p) => <rest>
In the match
-expression we can annotate discriminants to get a hypotheses stating they are equal to the pattern. Example:
match h : consume p ns es with
| (l?, p) => <rest>
If you use this annotation, we will have h : consume p ns es = (l?, p)
in your local context.
We currently do not have a similar notation for the let
syntax sugar above.
Leonardo de Moura (Apr 06 2022 at 14:38):
For the first issue, it seems to be a bug in the induction tactic when the variable is a let
-declaration. I will take a look.
In the meantime, you can make progress by using let_fun
instead
let_fun l : NEList String := l?.get hs
let_fun x := v; b
is sugar for (fun x => b) v
Leonardo de Moura (Apr 06 2022 at 14:48):
BTW, you can also simplify
if hs : l?.isSome then
let l := l?.get hs
have : l.noDup := sorry
return curry l this p
else
return (← p.runIO ctx).2
to
match l? with
| some l =>
have : l.noDup := sorry
return curry l this p
| none =>
return (← p.runIO ctx).2
or
if let some l := l? then
have : l.noDup := sorry
return curry l this p
else
return (← p.runIO ctx).2
Leonardo de Moura (Apr 06 2022 at 14:50):
You can also combine the consume
match with the one above and write
match h : consume p ns es with
| (some l, p) =>
have : l.noDup := sorry
curry l this p
| _ => (p.run ctx).2
Arthur Paulino (Apr 06 2022 at 15:07):
Yeah that's precisely how it was before but I changed it as an attempt to get consume
in my context
Leonardo de Moura (Apr 06 2022 at 15:09):
Note that, you will now have h : consume p ns es = ...
Arthur Paulino (Apr 06 2022 at 15:15):
Oh right! It's actually slightly different. Thanks!!
Arthur Paulino (Apr 06 2022 at 15:20):
I will try it when I get home
Arthur Paulino (Apr 06 2022 at 20:56):
Not sure if this is hard, or tricky, or if I'm simply not competent enough, but how would you prove this one?
theorem eqqIffEq [BEq α] {a b : α} : a == b ↔ a = b := sorry
Mauricio Collares (Apr 06 2022 at 21:01):
It's provable if you replace BEq
by LawfulBEq
, but you're out of luck if your BEq instance is not lawful.
Arthur Paulino (Apr 06 2022 at 21:14):
Thanks! I didn't know about LawfulBEq
!
theorem eqIffBEq [BEq α] [LawfulBEq α] {a b : α} : a == b ↔ a = b := by
constructor
· intro h; exact eq_of_beq h
· intro h; simp [h]
Arthur Paulino (Apr 07 2022 at 14:07):
Why is it that sometimes we end up with infeasible inductive hypotheses? Is it a symptom os flawed definitions? In this example I can't seem to be able to use hn
without assuming something false:
inductive NEList (α : Type)
| uno : α → NEList α
| cons : α → NEList α → NEList α
def NEList.contains [BEq α] : NEList α → α → Bool
| uno a, x => a == x
| cons a as, x => a == x || as.contains x
def NEList.noDupAux [BEq α] (l : List α) : NEList α → Bool
| .uno a => ¬ l.contains a
| .cons a r => ¬ l.contains a && ¬ r.contains a && noDupAux (a :: l) r
def NEList.noDup [BEq α] (l : NEList α) : Bool :=
noDupAux [] l
mutual
inductive Value
| nil : Value
| bool : Bool → Value
| int : Int → Value
| float : Float → Value
| list : Array Value → Value
| str : String → Value
| error : String → Value
| curry : (l : NEList String) → l.noDup → Program → Value
deriving Inhabited
inductive Expression
| atom : Value → Expression
| var : String → Expression
| not : Expression → Expression
| app : String → NEList Expression → Expression
| add : Expression → Expression → Expression
| mul : Expression → Expression → Expression
| eq : Expression → Expression → Expression
| ne : Expression → Expression → Expression
| lt : Expression → Expression → Expression
| le : Expression → Expression → Expression
| gt : Expression → Expression → Expression
| ge : Expression → Expression → Expression
inductive Program
| skip : Program
| sequence : Program → Program → Program
| attribution : String → Program → Program
| ifElse : Expression → Program → Program → Program
| whileLoop : Expression → Program → Program
| evaluation : Expression → Program
| fail : String → Program
deriving Inhabited
end
open NEList Program in
def consume (p : Program) :
NEList String → NEList Expression → (Option (NEList String)) × Program
| cons n ns, cons e es =>
consume (sequence (attribution n (evaluation e)) p) ns es
| cons n ns, uno e => (some ns, sequence (attribution n (evaluation e)) p)
| uno n, uno e => (none, sequence (attribution n (evaluation e)) p)
| uno _, cons .. => (none, fail "incompatible number of parameters")
theorem noDupOfNoDupAux {ns : NEList α} [BEq α] (h : NEList.noDupAux l ns) :
ns.noDup := sorry -- this is fine
theorem noDupOfConsumeNoDup
(h : NEList.noDup ns) (h' : consume p' ns es = (some l, p)) :
NEList.noDup l = true := by
induction ns with
| uno n =>
cases es with
| _ => simp [consume] at h'
| cons n ns hn =>
simp [NEList.noDup, NEList.noDupAux] at h
have hn := hn $ noDupOfNoDupAux h.2
have : consume p' (NEList.cons n ns) es = consume p' ns es := by
-- `(NEList.cons n ns)` can't be defeq to `ns`... not fine!
sorry
rw [this] at h'
exact hn h'
Any ideas what I might be doing wrong?
Mario Carneiro (Apr 07 2022 at 15:47):
the issue is usually a missing generalizing
on induction
Arthur Paulino (Apr 07 2022 at 15:55):
Thanks!!
Mario Carneiro (Apr 07 2022 at 16:02):
theorem noDupOfConsumeNoDup
(h : NEList.noDup ns) (h' : consume p' ns es = (some l, p)) :
NEList.noDup l = true := by
induction ns generalizing p' es with
| uno n => cases es <;> cases h'
| cons n ns ih =>
simp [NEList.noDup, NEList.noDupAux] at h
have h := noDupOfNoDupAux h.2
cases es with
| uno e => cases h'; exact h
| cons e es => exact ih h h'
Arthur Paulino (May 27 2022 at 23:57):
I have the impression that this should be simple, but I don't know what I'm missing
inductive Foo
| foo : Nat → Foo
| foos : Array Foo → Foo
deriving BEq
example : Foo.foo 0 ≠ Foo.foo 1 := by simp
-- Goals accomplished 🎉
example : #[0] ≠ #[1] := by simp
-- Goals accomplished 🎉
example : #[Foo.foo 0] ≠ #[Foo.foo 1] := by simp
-- unsolved goals
-- ⊢ ¬#[Foo.foo 0] = #[Foo.foo 1]
example : Foo.foos #[.foo 0] ≠ Foo.foos #[.foo 1] := by simp
-- unsolved goals
-- ⊢ ¬#[Foo.foo 0] = #[Foo.foo 1]
Can someone help me please? :pray:
Siddharth Bhat (May 28 2022 at 00:03):
inductive Foo
| foo : Nat → Foo
| foos : Array Foo → Foo
deriving BEq
example : Foo.foo 0 ≠ Foo.foo 1 := by simp
-- Goals accomplished 🎉
example : #[0] ≠ #[1] := by simp
-- Goals accomplished 🎉
example : #[Foo.foo 0] ≠ #[Foo.foo 1] := by {
unfold Not;
intros CONTRA;
exact (nomatch CONTRA);
}
-- goals accomplished
example : Foo.foos #[.foo 0] ≠ Foo.foos #[.foo 1] :=
by {
unfold Not;
intros CONTRA;
exact (nomatch CONTRA);
}
-- goals accomplished
Siddharth Bhat (May 28 2022 at 00:04):
I doubt this is the best way to write this in lean. I wrote it as I would in Coq, which is to unfold the Not
, intros
the absurd hypothesis, and then claim that the absurdity is vacuously true.
Arthur Paulino (May 28 2022 at 00:06):
Does your kernel accept it? Mine doesn't: leanprover/lean4:nightly-2022-05-18
Siddharth Bhat (May 28 2022 at 00:07):
I was on leanprover/lean4:nightly-2022-03-30
. Let me try on a newer version.
Siddharth Bhat (May 28 2022 at 00:08):
inductive Foo
| foo : Nat → Foo
| foos : Array Foo → Foo
deriving BEq
example : Foo.foo 0 ≠ Foo.foo 1 := by simp
-- Goals accomplished 🎉
example : #[0] ≠ #[1] := by simp
-- Goals accomplished 🎉
example : #[Foo.foo 0] ≠ #[Foo.foo 1] := fun CONTRA => nomatch CONTRA
example : Foo.foos #[.foo 0] ≠ Foo.foos #[.foo 1] := fun CONTRA => nomatch CONTRA
This formulation works on leanprover/lean4:nightly-2022-05-18
Siddharth Bhat (May 28 2022 at 00:10):
example : #[Foo.foo 0] ≠ #[Foo.foo 1] := by {
intros CONTRA;
exact (nomatch CONTRA);
}
in proof mode also works for me on Lean (version 4.0.0-nightly-2022-05-18, commit eb170d1f43e8, Release)
. Does it for you, @Arthur Paulino ?
Arthur Paulino (May 28 2022 at 00:11):
Yeah
example : #[Foo.foo 0] ≠ #[Foo.foo 1] := by
intro h
exact nomatch h
Arthur Paulino (May 28 2022 at 00:11):
Thanks!!
Leonardo de Moura (May 28 2022 at 01:28):
@Arthur Paulino Thanks for pointing it out. I added the missing simp
theorem.
List.of_toArray_eq_toArray (as bs : List α) : (as.toArray = bs.toArray) = (as = bs) :=
All examples should now go through using by simp
.
Last updated: Dec 20 2023 at 11:08 UTC