Zulip Chat Archive

Stream: new members

Topic: Proof Over Inductive Prop


Marcus Rossel (Jan 14 2021 at 17:04):

I can't figure out how to handle the following inductive proposition in a proof.
Sorry for not having a MWE - I hope the code is understandable anyway:

inductive has_path_from_to (g : digraph ι) : ι  ι  Prop
  | direct {i i' : ι} : (g.has_edge_from_to i i')  has_path_from_to i i'
  | composite {i i' : ι} (iₘ : ι) : has_path_from_to i iₘ  has_path_from_to iₘ i'  has_path_from_to i i'

I'm trying to prove:

lemma edges_inv_path_inv {g g' : digraph ι} {i i' : ι} (h : g.edges = g'.edges) :
  (g.has_path_from_to i i')  (g'.has_path_from_to i i')
  | (has_path_from_to.direct p) := begin
      rw [has_edge_from_to, h] at p,
      exact has_path_from_to.direct p
    end
  | (has_path_from_to.composite iₘ p_α p_ω) := begin
      sorry -- ?
    end

The goal state at the sorry is:

ι: Type u_1
_inst_1: decidable_eq ι
g g': digraph ι
i i': ι
h: g.edges = g'.edges
edges_inv_path_inv: g.has_path_from_to i i'  g'.has_path_from_to i i'
iₘ: ι
p_α: g.has_path_from_to i iₘ
p_ω: g.has_path_from_to iₘ i'
 g'.has_path_from_to i i'

I thought it would be possible to inductively use edges_inv_path_inv on p_α and p_ω, since they are "smaller" than g.has_path_from_to i i'. But If I try to use edges_inv_path_inv p_α , Lean complains that p_α doesn't have the required type g.has_path_from_to i i', which makes sense from how edges_inv_path_inv is defined in the goal state.
What I don't get is, of what use the recursive edges_inv_path_inv is, if it can only be used on g.has_path_from_to i i'?

Alex J. Best (Jan 14 2021 at 17:07):

Try moving i i'right of the colon, recursion can only happens on those arguments in lean.

Yakov Pechersky (Jan 14 2021 at 17:07):

You need to generalize on your i i'

Marcus Rossel (Jan 14 2021 at 17:38):

Awesome that worked! Now I have:

lemma edges_inv_path_inv {g g' : digraph ι} (h : g.edges = g'.edges) :
   {i i' : ι}, (g.has_path_from_to i i')  (g'.has_path_from_to i i')
  | i i' (has_path_from_to.direct p) := -- doesn't matter
  | i i' (has_path_from_to.composite iₘ p_α p_ω) := begin
      have p_α', from edges_inv_path_inv p_α,
      have p_ω', from edges_inv_path_inv p_ω,
      exact has_path_from_to.composite iₘ p_α' p_ω'
    end

The problem I have now though is that I get ...

failed to prove recursive application is decreasing

... for both invocations of edges_inv_path_inv.
How can I prove that p_α and p_ω are "smaller" than has_path_from_to.composite iₘ p_α p_ω? I thought this inductive approach would automatically imply that.

Reid Barton (Jan 14 2021 at 17:45):

just deleting this fake tactic block should help

Reid Barton (Jan 14 2021 at 17:46):

... := has_path_from_to.composite iₘ (edges_inv_path_inv p_α) (edges_inv_path_inv p_ω)

Marcus Rossel (Jan 14 2021 at 17:48):

Reid Barton said:

just deleting this fake tactic block should help

Nope, that didn't work :oh_no: I'll try to get a MWE going...

Reid Barton (Jan 14 2021 at 17:48):

well, at least the nonworking proof is shorter now

Marcus Rossel (Jan 14 2021 at 18:03):

Ok, this produces the error:

structure digraph (ι : Type*) := (edges : ι)

namespace digraph

  variable {ι : Type*}

  def has_edge_from_to (g : digraph ι) (i i' : ι) : Prop := sorry

  inductive has_path_from_to (g : digraph ι) : ι  ι  Prop
    | direct {i i' : ι} : (g.has_edge_from_to i i')  has_path_from_to i i'
    | composite {i i' : ι} (iₘ : ι) : has_path_from_to i iₘ  has_path_from_to iₘ i'  has_path_from_to i i'

  lemma edges_inv_path_inv {g g' : digraph ι} (h : g.edges = g'.edges) :
     {i i' : ι}, (g.has_path_from_to i i')  (g'.has_path_from_to i i')
    | i i' (has_path_from_to.direct p) := sorry
    | i i' (has_path_from_to.composite iₘ p_α p_ω) := begin
        have p_α', from edges_inv_path_inv p_α,
        have p_ω', from edges_inv_path_inv p_ω,
        exact has_path_from_to.composite iₘ p_α' p_ω'
      end

end digraph

Reid Barton (Jan 14 2021 at 18:09):

The equation compiler seems not to understand that structural recursion should be happening here

Reid Barton (Jan 14 2021 at 18:09):

You can start like this

lemma edges_inv_path_inv {g g' : digraph ι} (h : g.edges = g'.edges) :
     {i i' : ι}, (g.has_path_from_to i i')  (g'.has_path_from_to i i') :=
begin
   intros i₀ i'₀ h,
   induction h with i i' h' i i' iₘ h₁ h₂ IH₁ IH₂,
 end

Marcus Rossel (Jan 14 2021 at 18:12):

Reid Barton said:

You can start like this

lemma edges_inv_path_inv {g g' : digraph ι} (h : g.edges = g'.edges) :
     {i i' : ι}, (g.has_path_from_to i i')  (g'.has_path_from_to i i') :=
begin
   intros i₀ i'₀ h,
   induction h with i i' h' i i' iₘ h₁ h₂ IH₁ IH₂,
 end

Awesome, I was able to prove it from there. Thanks @Reid Barton !


Last updated: Dec 20 2023 at 11:08 UTC