Zulip Chat Archive

Stream: new members

Topic: Proving properties of an existential witness


Mark Fischer (Feb 23 2024 at 14:48):

Is it possible to prove properties of an existential witness? This is a silly example, but say:

def foo (a b : ) : Prop := c, a + b = c

Is there a way to express that foo a b → a ≤ c where c is the witness to the truth of foo a b?

Mark Fischer (Feb 23 2024 at 14:53):

By inspecting this proof, you can see that it is possible to use the witness from the antecedent as a witness to the consequent

example (a b : ): foo a b  c, a  c :=
  have hle := λ{c : }(h : a + b = c)  le_iff_exists_add.mpr b, h.symm
  λc, h  c, hle h

but of course, you don't need to. You can ignore the antecedent altogether:

example (a b : ): foo a b  c, a  c :=
  λ_  a, Nat.le.refl

Matt Diamond (Feb 23 2024 at 16:02):

Is there a way to express that foo a b → a ≤ c where c is the witness to the truth of foo a b?

sure: foo a b → a ≤ (foo a b).choose

Mark Fischer (Feb 23 2024 at 16:38):

That makes sense to me! Though foo is a proposition, not a proof, that's easy to fix

Mark Fischer (Feb 23 2024 at 17:32):

Been trying to prove this, but I'm not sure how to work it:

import Mathlib

def foo (a b : ) : Prop := c, a + b = c

example (a b : ) : (h : foo a b)  a  h.choose := by
  intro h₁
  match h₂ : h₁ with
  | x ,h₃ =>
    have h₄ : h₁.choose = a + b := sorry
    simp only [h₄]
    exact Nat.le_add_right a b

Paul Rowe (Feb 23 2024 at 17:43):

I think what you need is h₁.choose_spec which tells you the property that is satisfied by h₁.choose

Paul Rowe (Feb 23 2024 at 17:45):

So, since your equality is the reverse order of the property, you can replace your sorry with h₁.choose_spec.symm to make Lean happy

Mark Fischer (Feb 23 2024 at 18:08):

Yup, that works :)

example (a b : ) : (h : foo a b)  a  h.choose := by
  intro h₁
  have h₂ : h₁.choose = a + b := h₁.choose_spec.symm
  simp only [h₂]
  exact Nat.le_add_right a b

Though, I have a followup question. It feels like intro returns both the value and the property, but it doesn't give me a way to connect it back to the output.

example (a b : ) : (h : foo a b)  a  h.choose := by
  intro x, heq
  sorry

Here's it feels like x = h.choose should be true, but I don't really have access to this fact?

Mark Fischer (Feb 23 2024 at 18:11):

Ah, right, nevermind, I do get access to that fact using the match statement. Looks good.

Eric Wieser (Feb 23 2024 at 18:20):

Here's it feels like x = h.choose should be true, but I don't really have access to this fact?

In general it's unprovable, you can only prove it here because there is only one possible witness

Matt Diamond (Feb 23 2024 at 18:45):

good point... a proof about h.choose is going to be pointless in contexts where you've destructured the existential

in those contexts, all you need is a lemma of the form ∀ {x}, p x → q x... the fact that x is an existential witness is irrelevant

Mark Fischer (Feb 23 2024 at 19:04):

I would expect something like this to work.

let t₁ := foo.choose
let t₂ := foo.choose
have h : t₁ = t₂ := rfl

This isn't how it works, but I have a lingering intuition that when I destructure, I should somehow have access to how that value connects back to the value it was destructured from...

let t₁, _ := foo
let t₂ := foo.choose
have h : t₁ = t₂ := rfl

but that doesn't work. That or I'm off base on what the destructuring even does here, I think it uses choice underneath as well.

Eric Wieser (Feb 23 2024 at 19:12):

Maybe it helps to realize that (Exists.intro x hx).choose = x is usually unprovable

Eric Wieser (Feb 23 2024 at 19:12):

(destructuring has some extra complications that are a distraction here; you need a different syntax to destruct things without forgetting what they are)

Mark Fischer (Feb 23 2024 at 19:30):

I think that makes sense. Choice doesn't give me back any particular element (for example, the witness I just used).

What I'm thinking is generally closer to (Exists.intro x hx).choose = (Exists.intro x hx).choose though sometimes lean doesn't see it that way right away. Esp, when destructuring since that information is lost.

But this has been a helpful exercise in wrapping my head around what's happening.

Paul Rowe (Feb 23 2024 at 20:34):

Treq said:

This isn't how it works, but I have a lingering intuition that when I destructure, I should somehow have access to how that value connects back to the value it was destructured from...

I wonder if you are looking for something like

set t₁ := h₁.choose with g₁

This adds two hypotheses: t₁ : ℕ := Exists.choose h₁ and g₁ : t₁ = Exists.choose h₁ Then you can use rw to substitute back and forth with t₁ and Exists.choose h₁ as necessary.

In other words, let is great if you just need to define a value of a certain type and it doesn't matter how you got it. set ... with is useful if you need to retain the defining equation of what you are declaring.

Please feel free to ignore if I have completely missed the mark.


Last updated: May 02 2025 at 03:31 UTC