Zulip Chat Archive
Stream: new members
Topic: induction Target occurs more than once
Jakub Nowak (Aug 27 2025 at 21:02):
Can someone help me get around this error? Or even better, help me understand it so I can fix it myself. :)
import Mathlib
open SimpleGraph
variable {V : Type u} {G : SimpleGraph V}
private def odd_cycle_of_odd_walk_step [DecidableEq V] {u v : V}
(pref : G.Walk u v) (suf : G.Walk v u) :
Σ w : V, G.Walk w w :=
match suf with
| .nil => ⟨u, Walk.nil⟩ -- unreachable
| .cons' v w u hAdj suf' =>
if h : w ∈ pref.support then
let pref_pre_part : G.Walk u w := pref.takeUntil w h
let pref_cycle_part : G.Walk w v := pref.dropUntil w h
let cycle : G.Walk v v := .cons hAdj pref_cycle_part
if cycle.length.bodd then
⟨v, cycle⟩
else
odd_cycle_of_odd_walk_step pref_pre_part suf'
else
odd_cycle_of_odd_walk_step (pref.concat hAdj) suf'
private def odd_cycle_of_odd_walk [DecidableEq V] (p : G.Walk u u) : Σ v : V, G.Walk v v :=
odd_cycle_of_odd_walk_step .nil p
theorem odd_cycle_of_odd_walk.is_odd_cycle [DecidableEq V] (p : G.Walk u u) (hOdd : p.length.bodd) :
(odd_cycle_of_odd_walk p).snd.IsCycle ∧ (odd_cycle_of_odd_walk p).snd.length.bodd := by
unfold odd_cycle_of_odd_walk
induction p
-- error:
-- Invalid target: Target (or one of its indices) occurs more than once
-- u
Aaron Liu (Aug 27 2025 at 23:00):
What do you want your induction hypothesis to be?
Jakub Nowak (Aug 27 2025 at 23:41):
Ah, right, I should have asked myself that. induction p doesn't really even makes sense here. The induction should be on the suf variable and the induction hypothesis should probably be pref.isPath → (pref.append suf).length.bodd → (odd_cycle_of_odd_walk_step pref suf).snd.isCycle ∧ (odd_cycle_of_odd_walk_step pref suf).snd.length.bodd to make the proof work.
Aaron Liu (Aug 27 2025 at 23:46):
and what is your goal in this case? I want to find out where p went
Jakub Nowak (Aug 27 2025 at 23:48):
The goal is (odd_cycle_of_odd_walk_step .nil p).snd.isCycle ∧ (odd_cycle_of_odd_walk_step .nil p).snd.length.bodd.
Which is the induction hypothesis with pref = .nil and suf = p.
Aaron Liu (Aug 27 2025 at 23:49):
I don't get it, what are pref and suf here?
Aaron Liu (Aug 27 2025 at 23:50):
are they free or bound?
Aaron Liu (Aug 27 2025 at 23:54):
maybe you can write out the type of the induction principle you want to use
Jakub Nowak (Aug 28 2025 at 00:03):
Like this I think:
(∀ {u v : V} (pref : G.Walk u v), pref.isPath → (pref.append .nil).length.bodd →
(odd_cycle_of_odd_walk_step pref .nil).snd.isCycle ∧ (odd_cycle_of_odd_walk_step pref .nil).snd.length.bodd) →
(∀ {u v w : V} (pref : G.Walk u v) (h : G.Adj v w) (p : G.Walk w u), pref.isPath → (pref.append (.cons h p)).length.bodd →
(odd_cycle_of_odd_walk_step pref (.cons h p)).snd.isCycle ∧ (odd_cycle_of_odd_walk_step pref (.cons h p)).snd.length.bodd) →
∀ {u : V} (pref : G.Walk u v) (p : G.Walk v u), pref.isPath → (pref.append p).length.bodd →
(odd_cycle_of_odd_walk_step pref p).snd.isCycle ∧ (odd_cycle_of_odd_walk_step pref p).snd.length.bodd
Aaron Liu (Aug 28 2025 at 00:06):
oh that doesn't look too bad
Jakub Nowak (Aug 28 2025 at 00:06):
After abstracting the goal away:
(∀ {u v : V} (pref : G.Walk u v), pref.isPath → (pref.append .nil).length.bodd → motive pref .nil) →
(∀ {u v w : V} (pref : G.Walk u v) (h : G.Adj v w) (p : G.Walk w u), pref.isPath → (pref.append (.cons h p)).length.bodd → motive pref (.cons h p)) →
∀ {u : V} (pref : G.Walk u v) (p : G.Walk v u), pref.isPath → (pref.append p).length.bodd →
motive pref p
Jakub Nowak (Aug 28 2025 at 00:07):
So to answer your question, pref is free and suf (which I renamed to p) is the target variable?
Aaron Liu (Aug 28 2025 at 00:11):
yeah I have some incantations which will get you that induction
Jakub Nowak (Aug 28 2025 at 00:25):
Got it working like this:
import Mathlib
open SimpleGraph
variable {V : Type u} {G : SimpleGraph V}
private def odd_cycle_of_odd_walk_step [DecidableEq V] {u v : V}
(pref : G.Walk u v) (suf : G.Walk v u) :
Σ w : V, G.Walk w w :=
match suf with
| .nil => ⟨u, Walk.nil⟩ -- unreachable
| .cons' v w u hAdj suf' =>
if h : w ∈ pref.support then
let pref_pre_part : G.Walk u w := pref.takeUntil w h
let pref_cycle_part : G.Walk w v := pref.dropUntil w h
let cycle : G.Walk v v := .cons hAdj pref_cycle_part
if cycle.length.bodd then
⟨v, cycle⟩
else
odd_cycle_of_odd_walk_step pref_pre_part suf'
else
odd_cycle_of_odd_walk_step (pref.concat hAdj) suf'
private def odd_cycle_of_odd_walk [DecidableEq V] (p : G.Walk u u) : Σ v : V, G.Walk v v :=
odd_cycle_of_odd_walk_step .nil p
theorem odd_cycle_of_odd_walk_step.is_odd_cycle [DecidableEq V] (pref : G.Walk u v) (p : G.Walk v u)
(hP : p.IsPath) (hOdd : (pref.append p).length.bodd) :
(odd_cycle_of_odd_walk_step pref p).snd.IsCycle ∧ (odd_cycle_of_odd_walk_step pref p).snd.length.bodd := by
induction p
sorry
theorem odd_cycle_of_odd_walk.is_odd_cycle [DecidableEq V] (p : G.Walk u u) (hP : p.IsPath) (hOdd : p.length.bodd) :
(odd_cycle_of_odd_walk p).snd.IsCycle ∧ (odd_cycle_of_odd_walk p).snd.length.bodd :=
odd_cycle_of_odd_walk_step.is_odd_cycle .nil p (by simp_all) (by simp_all)
Couldn't get it work without helper function.
Jakub Nowak (Aug 28 2025 at 00:33):
MrQubo said:
After abstracting the goal away:
(∀ {u v : V} (pref : G.Walk u v), pref.isPath → (pref.append .nil).length.bodd → motive pref .nil) → (∀ {u v w : V} (pref : G.Walk u v) (h : G.Adj v w) (p : G.Walk w u), pref.isPath → (pref.append (.cons h p)).length.bodd → motive pref (.cons h p)) → ∀ {u : V} (pref : G.Walk u v) (p : G.Walk v u), pref.isPath → (pref.append p).length.bodd → motive pref p
That is wrong. That's just cases. .-. I forgot about induction hypothesis, this should be like this:
(∀ {u v : V} (pref : G.Walk u v), pref.isPath → (pref.append .nil).length.bodd → motive pref .nil) →
(∀ {u v w : V} (pref : G.Walk u v) (h : G.Adj v w) (p : G.Walk w u), pref.isPath → (pref.append (.cons h p)).length.bodd →
(∀ {u : V} (pref : G.Walk u w), pref.isPath → (pref.append p).length.bodd → motive pref p) →
motive pref (.cons h p)) →
∀ {u : V} (pref : G.Walk u v) (p : G.Walk v u), pref.isPath → (pref.append p).length.bodd →
motive pref p
Aaron Liu (Aug 28 2025 at 00:35):
I think this works?
theorem odd_cycle_of_odd_walk.is_odd_cycle [DecidableEq V] (p : G.Walk u u) (hOdd : p.length.bodd) :
(odd_cycle_of_odd_walk p).snd.IsCycle ∧ (odd_cycle_of_odd_walk p).snd.length.bodd := by
unfold odd_cycle_of_odd_walk
rw [← p.nil_append] at hOdd
let v := u
set pref : G.Walk u v := .nil
have hPath : pref.IsPath := .nil
change G.Walk v u at p
change (pref.append p).length.bodd = true at hOdd
change (odd_cycle_of_odd_walk_step pref p).snd.IsCycle ∧
(odd_cycle_of_odd_walk_step pref p).snd.length.bodd = true
clear_value v pref
induction p with
| nil => sorry
| cons h p ih => sorry
Jakub Nowak (Aug 28 2025 at 00:44):
Oh, that's interesting. I think, it's kinda the same as with helper function, just done more manually. The trick with let v := u and change looks like an useful way to resolve this "Target (or one of its indices) occurs more than once" error in other scenarios.
Thank you very much for your time!
Last updated: Dec 20 2025 at 21:32 UTC