Zulip Chat Archive

Stream: Is there code for X?

Topic: (list.cons a l) ≠ l


Eric Wieser (Jul 27 2020 at 11:57):

The statement appears trivial, but I was surprised that simp couldn't solve it for me

@[simp] lemma cons_ne_self {α : Type u} (a : α) (l : list α) : (list.cons a l)  l := begin
  induction l,
  { simp },
  simp only [not_and, ne.def],
  rintro ⟨⟩,
  exact l_ih,
end

Does this belong in mathlib, or is it too trivial? I note that nat.succ_ne_self exists, but isn't tagged as @[simp]...

Chris Wong (Jul 27 2020 at 12:56):

Does simp work for ≠? I've only seen it for = and <->

Mario Carneiro (Jul 27 2020 at 12:58):

no

Mario Carneiro (Jul 27 2020 at 12:58):

however you can mark any theorem T as a simp lemma and it will treat it as a proof of T = true

Eric Wieser (Jul 27 2020 at 13:01):

Does that mean that almost all non-equality / iff lemmas with no implications should be marked simp?

Mario Carneiro (Jul 27 2020 at 13:02):

almost all lemmas could be marked simp, that doesn't make it a good idea

Mario Carneiro (Jul 27 2020 at 13:03):

In this case, I'm not sure why you thought simp would solve the theorem

Mario Carneiro (Jul 27 2020 at 13:03):

unless this exact lemma already exists with @[simp]

Eric Wieser (Jul 27 2020 at 13:04):

I was expecting that this lemma might already exist.

Utensil Song (Jul 27 2020 at 13:07):

This doesn't feel simp. But I did try other automatic tactics and none kills it in one line.

Mario Carneiro (Jul 27 2020 at 13:25):

@[simp] lemma cons_ne_self {α} (a : α) (l : list α) : list.cons a l  l :=
mt (congr_arg list.length) $ ne_of_gt $ nat.lt_succ_self _

Eric Wieser (Jul 27 2020 at 13:34):

Can list.no_confusion be used here?

Ruben Van de Velde (Jul 27 2020 at 13:38):

I don't think so - l could be a list.cons

Eric Wieser (Jul 27 2020 at 13:58):

Can also get it with

@[simp] theorem cons_ne_self {α : Type u} :  (a : α) (l : list α), (a :: l)  l
| a nil := list.cons_ne_nil a list.nil
| a (h :: t) := λ hyp, cons_ne_self h t $ (cons.inj hyp).right

which doesn't rely on list.length

Utensil Song (Jul 27 2020 at 14:06):

import tactic

universe u

open list

example {α : Type u} :  (a : α) (l : list α), (cons a l)  l
| a nil := by simp
| a (cons h t) := begin
  solve_by_elim,
end

Weird, this closes the goals but

equation compiler failed to create auxiliary declaration '_example._main._pack.equations._eqn_2'
nested exception message:
invalid equation lemma, unexpected form

Reid Barton (Jul 27 2020 at 14:06):

maybe try not using example?

Gabriel Ebner (Jul 27 2020 at 14:08):

Wow, I never realized you could have recursive examples.

Utensil Song (Jul 27 2020 at 14:12):

Oh then Lean demands a using_well_founded.

Eric Wieser (Jul 27 2020 at 14:18):

Pr'd as #3584

Utensil Song (Jul 27 2020 at 14:34):

/-
failed to prove recursive application is decreasing, well founded relation
  @has_well_founded.r (Σ' (a : α), list α)
    (@psigma.has_well_founded α (λ (a : α), list α) (@has_well_founded_of_has_sizeof α (default_has_sizeof α))
       (λ (a : α), @has_well_founded_of_has_sizeof (list α) (@list.has_sizeof α (default_has_sizeof α))))
The nested exception contains the failure state for the decreasing tactic.
nested exception message:
invalid apply tactic, failed to unify
  0 < 0
with
  ?m_1 < ?m_1 + ?m_2
state:
α : Type u,
cons_ne_self : ∀ (_p : Σ' (a : α), list α), _p.fst :: _p.snd ≠ _p.snd,
a h : α,
t : list α,
a : α,
l : list α
⊢ 0 < 0
-/
lemma cons_ne_self {α : Type u} :  (a : α) (l : list α), (cons a l)  l
| a nil := by simp
| a (cons h t) := by simp [cons_ne_self]
using_well_founded {
  dec_tac := well_founded_tactics.default_dec_tac
}

Utensil Song (Jul 27 2020 at 14:34):

Why would this lead to 0 < 0?

Reid Barton (Jul 27 2020 at 14:37):

simp probably just used the lemma to prove itself directly, and then obviously wasn't able to prove that the call was on something smaller

Reid Barton (Jul 27 2020 at 14:37):

This is a common annoyance when using "apply anything" tactics in conjunction with the equation compiler.

Mario Carneiro (Jul 27 2020 at 14:39):

try simp [cons_ne_self h t]

Utensil Song (Jul 27 2020 at 14:43):

Beautiful, it works!

(Lean is right to complain, without the proper hint (i.e. h t), this is really not "decreasing")

Eric Wieser (Jul 27 2020 at 15:13):

Mario Carneiro said:

@[simp] lemma cons_ne_self {α} (a : α) (l : list α) : list.cons a l  l :=
mt (congr_arg list.length) $ ne_of_gt $ nat.lt_succ_self _
@[simp] lemma cons_ne_self {α} (a : α) (l : list α) : list.cons a l  l :=
mt (congr_arg list.length) (nat.succ_ne_self _)

is better than that proof, if we really want the proof to depend on list.length

Utensil Song (Jul 27 2020 at 15:19):

list and nat are two faces of the same coin

Utensil Song (Jul 27 2020 at 15:19):

such a basic theorem probably should not depend on length or nat

Mario Carneiro (Jul 27 2020 at 15:20):

I don't see why, this is what libraries are for - you don't have to prove everything from the axioms

Eric Wieser (Jul 27 2020 at 15:22):

Turns out I'm wrong anyway, list.length is defined within lean itself, not within mathlib where our lemmas are

Utensil Song (Jul 27 2020 at 15:22):

I like the proof in another context because it's the most intuitive proof for me.

Utensil Song (Jul 27 2020 at 15:23):

Not so sure in the library itself though

Mario Carneiro (Jul 27 2020 at 15:23):

In isolation, sure

Mario Carneiro (Jul 27 2020 at 15:24):

but when it comes to minimizing the sum of the sizes of all proofs through reordering, this looks like an improvement

Eric Wieser (Jul 27 2020 at 19:11):

Note my claim about reordering in the PR was actually wrong anyway.


Last updated: Dec 20 2023 at 11:08 UTC