Zulip Chat Archive

Stream: mathlib4

Topic: Equivalence Relation for Walks on Graphs


Fred Rajasekaran (Oct 01 2025 at 20:44):

I'm trying to define an equivalence relation for certain types of walks on simple graphs, but it's been somewhat challenging.

I am considering walks that have loops (consecutive visits to the same vertex) allowed which I defined an inductive type for (similar to how walks are in mathlib now). I am considering walks on the complete graph on n vertices, and I would like to establish an equivalence relation in which two walks are equivalent if they are the same up to a permutation of the vertices.

However, the inductive type LoopWalk u v depends on the starting and ending vertices, so in order to even write the statement that one walk is equal to another after relabeling the vertices by some permutation, I need to provide a proof that the endpoints are the same under the permutation. I'm having some trouble implementing this.

For example, in identityWalkMap, I'm not sure how to state the lemma correctly, and I had to modify loopWalkEquiv to be in its current form (requiring a proof that the endpoints are the same). Any advice for proving the equivalence relation properties in LoopWalkSetoid would also be greatly appreciated.

import Mathlib.Combinatorics.SimpleGraph.DeleteEdges
import Mathlib.Data.Finset.Basic

universe u v w

namespace SimpleGraph

variable {V : Type u} {V' : Type v}
variable (G : SimpleGraph V) (G' : SimpleGraph V')

/-A walk on a simple graph that allows consecutive visits to the same vertex.-/
inductive LoopWalk' : V  V  Type u
  | nil {u : V} : LoopWalk' u u
  | cons {u v w : V} (h : G.Adj u v) (p : LoopWalk' v w) : LoopWalk' u w
  | loop {u v : V} (p : LoopWalk' u v): LoopWalk' u v
  deriving DecidableEq

namespace LoopWalk'

variable {G}

/- The length of a walk is the number of edges/darts along it. -/
def length {u v : V} : G.LoopWalk' u v  
  | nil => 0
  | cons _ q => q.length.succ
  | loop q => q.length.succ

/-The pushforward of a graph homorphism to LoopWalks.-/
protected def map (f : G g G') {u v : V} : G.LoopWalk' u v  G'.LoopWalk' (f u) (f v)
  | nil => nil
  | cons h p => cons (f.map_adj h) (p.map f)
  | loop p => loop (p.map f)

variable (n k : )
variable (K : SimpleGraph (Fin n)) (hk : K = completeGraph (Fin n))
variable (s : Equiv.Perm (Fin n))
variable {u v: Fin n}

/-A permuation of Fin n induces a graph isomorphims on the complete graph.-/
def permMap' (s : Equiv.Perm (Fin n)) : K g K where
  toEquiv:= s
  map_rel_iff':=by
    intros a b
    rw[hk]
    rw[top_adj, top_adj]
    simp

/-The pushforward of a permutation on (Fin n) to walks on the complete graph.-/
def permMapWalk (s : Equiv.Perm (Fin n)) (p : K.LoopWalk' u v) : K.LoopWalk' (s u) (s v):=
  p.map K (permMap' n K hk s)


/-The type of all closed LoopWalks-/
abbrev ClosedLoopWalk (G : SimpleGraph V) := Σ u : V, G.LoopWalk' u u

/-The type of closed LoopWalks with length k -/
abbrev FixLengthClosedLoopWalk (k : ) (G : SimpleGraph V) :=
   {p : ClosedLoopWalk G // p.2.length = k}

/-Two walks p and q are equivalent if there exists a permuation s such that q is the pushforward of
p under s.-/
def loopWalkEquiv (p q : FixLengthClosedLoopWalk k K): Prop :=
   (s : Equiv.Perm (Fin n)),  (h_eq : s p.1.1 = q.1.1),
    h_eq  (permMapWalk n K hk s p.1.2) = q.1.2

/-The identity permutation induces the identity map on LoopWalks.-/
lemma identityWalkMap (s : Equiv.Perm (Fin n)) (p : K.LoopWalk' u v) (hs : s = Equiv.refl (Fin n)):
  p.map K (permMap' n K hk s) = p := by sorry

/-This relation above defines an equivalence relation.-/
def LoopWalkSetoid : Setoid (FixLengthClosedLoopWalk k K) where
  r := loopWalkEquiv n k K hk
  iseqv := by
    constructor
    · intro x
      let s := Equiv.refl (Fin n)
      unfold loopWalkEquiv
      use s
      have hs (y : Fin n):  s y = y := by
        unfold s
        simp
      use hs x.1.1
      sorry
    · sorry
    · sorry

end LoopWalk'
end SimpleGraph

Thomas Waring (Oct 02 2025 at 15:50):

You might try taking a look at the API for SimpleGraph.Walk — particular the use of SimpleGraph.Walk.copy. I'm by no means confident with this kind of thing but I made a start at implementing something along those lines in your formalism, which let me state & prove your lemma loopWalkEquiv (mostly using simp).

import Mathlib.Combinatorics.SimpleGraph.DeleteEdges
import Mathlib.Data.Finset.Basic

universe u v w

namespace SimpleGraph

variable {V : Type u} {V' : Type v}
variable (G : SimpleGraph V) (G' : SimpleGraph V')

/-A walk on a simple graph that allows consecutive visits to the same vertex.-/
inductive LoopWalk' : V  V  Type u
  | nil {u : V} : LoopWalk' u u
  | cons {u v w : V} (h : G.Adj u v) (p : LoopWalk' v w) : LoopWalk' u w
  | loop {u v : V} (p : LoopWalk' u v): LoopWalk' u v
  deriving DecidableEq

namespace LoopWalk'

variable {G}

protected def copy {u v u' v'} (p : G.LoopWalk' u v) (hu : u = u') (hv : v = v') : G.LoopWalk' u' v' :=
  hu  hv  p

@[simp]
theorem copy_rfl_rfl {u v} (p : G.LoopWalk' u v) : p.copy rfl rfl = p := rfl

@[simp]
theorem copy_copy {u v u' v' u'' v''} (p : G.LoopWalk' u v)
    (hu : u = u') (hv : v = v') (hu' : u' = u'') (hv' : v' = v'') :
    (p.copy hu hv).copy hu' hv' = p.copy (hu.trans hu') (hv.trans hv') := by
  subst_vars
  rfl

@[simp]
theorem copy_nil {u u'} (hu : u = u') : (LoopWalk'.nil : G.LoopWalk' u u).copy hu hu = LoopWalk'.nil := by
  subst_vars
  rfl

theorem copy_cons {u v w u' w'} (h : G.Adj u v) (p : G.LoopWalk' v w) (hu : u = u') (hw : w = w') :
    (LoopWalk'.cons h p).copy hu hw = LoopWalk'.cons (hu  h) (p.copy rfl hw) := by
  subst_vars
  rfl

@[simp]
theorem cons_copy {u v w v' w'} (h : G.Adj u v) (p : G.LoopWalk' v' w') (hv : v' = v) (hw : w' = w) :
    LoopWalk'.cons h (p.copy hv hw) = (LoopWalk'.cons (hv  h) p).copy rfl hw := by
  subst_vars
  rfl

theorem copy_loop {u v u' v'} (p : G.LoopWalk' u v) (hu : u = u') (hv : v = v') :
    (LoopWalk'.loop p).copy hu hv = LoopWalk'.loop (p.copy hu hv) := by
  subst_vars
  rfl

@[simp]
theorem loop_copy {u v u' v'} (p : G.LoopWalk' u' v') (hu : u' = u) (hv : v' = v) :
    LoopWalk'.loop (p.copy hu hv) = (LoopWalk'.loop p).copy hu hv := by
  subst_vars
  rfl

/- The length of a walk is the number of edges/darts along it. -/
def length {u v : V} : G.LoopWalk' u v  
  | nil => 0
  | cons _ q => q.length.succ
  | loop q => q.length.succ

/-The pushforward of a graph homorphism to LoopWalks.-/
protected def map (f : G g G') {u v : V} : G.LoopWalk' u v  G'.LoopWalk' (f u) (f v)
  | nil => nil
  | cons h p => cons (f.map_adj h) (p.map f)
  | loop p => loop (p.map f)

variable (n k : )
-- variable (K : SimpleGraph (Fin n)) (hk : K = completeGraph (Fin n))
abbrev K := completeGraph (Fin n)
variable (s : Equiv.Perm (Fin n))
variable {u v: Fin n}

/-A permuation of Fin n induces a graph isomorphims on the complete graph.-/
def permMap' (s : Equiv.Perm (Fin n)) : (K n) g (K n) where
  toEquiv:= s
  map_rel_iff':=by
    intros a b
    rw[top_adj, top_adj]
    simp

/-The pushforward of a permutation on (Fin n) to walks on the complete graph.-/
def permMapWalk (s : Equiv.Perm (Fin n)) (p : (K n).LoopWalk' u v) : (K n).LoopWalk' (s u) (s v):=
  p.map (K n) (permMap' n s)


/-The type of all closed LoopWalks-/
abbrev ClosedLoopWalk (G : SimpleGraph V) := Σ u : V, G.LoopWalk' u u

/-The type of closed LoopWalks with length k -/
abbrev FixLengthClosedLoopWalk (k : ) (G : SimpleGraph V) :=
   {p : ClosedLoopWalk G // p.2.length = k}

/-Two walks p and q are equivalent if there exists a permuation s such that q is the pushforward of
p under s.-/
def loopWalkEquiv (p q : FixLengthClosedLoopWalk k (K n)): Prop :=
   (s : Equiv.Perm (Fin n)),  (h_eq : s p.1.1 = q.1.1),
    (permMapWalk n s p.1.2).copy h_eq h_eq = q.1.2

/-The identity permutation induces the identity map on LoopWalks.-/
lemma identityWalkMap (p : (K n).LoopWalk' u v) :
    p.map (K n) (permMap' n <| Equiv.refl (Fin n)) = p.copy (by simp [permMap']) (by simp [permMap']) := by
  simp only [permMap', copy_rfl_rfl]
  induction p
  case nil => simp [LoopWalk'.map]
  case cons h p ih => simpa [LoopWalk'.map]
  case loop p ih => simpa [LoopWalk'.map]


/-This relation above defines an equivalence relation.-/
def LoopWalkSetoid : Setoid (FixLengthClosedLoopWalk k (K n)) where
  r := loopWalkEquiv n k
  iseqv := by
    constructor
    · intro x
      let s := Equiv.refl (Fin n)
      unfold loopWalkEquiv
      use s
      have hs (y : Fin n):  s y = y := by
        unfold s
        simp
      use hs x.1.1
      have : _ := identityWalkMap n x.val.2
      simpa using this
    · sorry
    · sorry

end LoopWalk'
end SimpleGraph

(To make life easier I removed hypotheses like (K : SimpleGraph (Fin n)) (hK : K = completeGraph (Fin n)) by restating the theorem for completeGraph (Fin n) directly)


Last updated: Dec 20 2025 at 21:32 UTC