1-- The quotient multigraph of a partition of the vertex set, in which every2-- class is one vertex and an edge keeps its identity: the class of a vertex,3-- refinement of partitions, and the edges crossing a set of classes.4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.GraphTheory.Multigraph.Quotient10import Connectivity1112-- The class of v: the union of the classes containing v, which under a13-- partition is the one class containing v.14def classesContaining (P v : Set) : Set:= { X ∈ P | v ∈ X }15def classOf (P v : Set) : Set:=⋃(classesContaining(P, v))1617theorem classOf.membership (P v z : Set)18shows z ∈ classOf(P, v) ↔∃ X ∈ P, v ∈ X ∧ z ∈ X19proof20simp [classOf, classesContaining, union.membership]2122theorem classOf.eq_of_member (P v X : Set)23requires apart : ∀ X ∈ P, ∀ Y ∈ P, X ≠ Y → Disjoint(X, Y)24requiresclass : X ∈ P25requires member : v ∈ X26shows classOf(P, v) = X27proof28ext z29rw classOf.membership30constructor31 . intro inUnion32obtain⟨Y, classY, vInY, inY⟩:= inUnion33have same : X = Y34by_contra different35exact apart with X, class, Y, classY, different, v, member, vInY36cc37 . intro inX38exact⟨X, class, member, inX⟩3940theorem classOf.member (V P v : Set)41requires partition : Partition(V, P)42requires vertex : v ∈ V43shows classOf(P, v) ∈ P ∧ v ∈ classOf(P, v)44proof45obtain⟨X, class, member⟩:= partition.right.right with v, vertex46rw classOf.eq_of_member with partition.right.left, class, member47exact⟨class, member⟩4849theorem classOf.eq_iff (V P u v : Set)50requires partition : Partition(V, P)51requires first : u ∈ V52requires second : v ∈ V53shows classOf(P, u) = classOf(P, v) ↔ (∃ X ∈ P, u ∈ X ∧ v ∈ X)54proof55have apart := partition.right.left56constructor57 . intro equal58obtain⟨X, classX, uInX⟩:= partition.right.right with u, first59obtain⟨Y, classY, vInY⟩:= partition.right.right with v, second60have classU := classOf.eq_of_member with apart, classX, uInX61have classV := classOf.eq_of_member with apart, classY, vInY62witness X63refine⟨classX, uInX, _⟩64cc65 . intro common66obtain⟨X, class, uInX, vInX⟩:= common67have classU := classOf.eq_of_member with apart, class, uInX68have classV := classOf.eq_of_member with apart, class, vInX69cc7071-- A vertex lies in a union of classes exactly when its class is one of them.72theorem classOf.mem_union_iff (V P Y v : Set)73requires partition : Partition(V, P)74requires subfamily : Y ⊆ P75requires vertex : v ∈ V76shows v ∈⋃(Y) ↔ classOf(P, v) ∈ Y77proof78have apart := partition.right.left79constructor80 . intro inUnion81obtain⟨Z, inY, inZ⟩:= union.membership.forward with inUnion82have classZ := subfamily with Z, inY83rw classOf.eq_of_member with apart, classZ, inZ84exact inY85 . intro inY86obtain⟨X, class, member⟩:= partition.right.right with v, vertex87rw classOf.eq_of_member with apart, class, member at inY88exact union.membership.backward with⟨X, inY, member⟩8990-- A partition refines another when every class of the first lies in a class91-- of the second.92predicate Refines (P Q : Set) :=∀ X ∈ P, ∃ Y ∈ Q, X ⊆ Y9394-- The quotient multigraph: the vertices are the classes, and an edge joins95-- the classes of its ends. Edges inside a class become loops; the crossing96-- classes of F are its edges joining distinct classes.97def quotientEnd (E P endpoint : Set) : Set:=98 { p ∈ E × P |∃ e ∈ E, p = (e, classOf(P, endpoint(e))) }99100def crossingClasses (P leftEnd rightEnd F : Set) : Set:=101 { e ∈ F | classOf(P, leftEnd(e)) ≠ classOf(P, rightEnd(e)) }102103theorem quotientEnd.relates (E P endpoint e X : Set)104requires related : relates(quotientEnd(E, P, endpoint), e, X)105shows e ∈ E ∧ X = classOf(P, endpoint(e))106proof107obtain⟨_, f, inE, equation⟩:= related108obtain⟨rfl, value⟩:= orderedPair.injective with equation109exact⟨inE, value⟩110111theorem quotientEnd.relates_class (V E P endpoint e : Set)112requires function : endpoint : E → V113requires partition : Partition(V, P)114requires edge : e ∈ E115shows relates(quotientEnd(E, P, endpoint), e, classOf(P, endpoint(e)))116proof117have vertex := FunctionBetween.apply_closed with function, edge118obtain⟨class, _⟩:= classOf.member with partition, vertex119exact quotientEnd.membership.backward120with⟨(product.pair with edge, class), e, edge, rfl⟩121122theorem quotientEnd.function (V E P endpoint : Set)123requires function : endpoint : E → V124requires partition : Partition(V, P)125shows quotientEnd(E, P, endpoint) : E → P126proof127constructor128 . intros p member129exact member.left130constructor131 . intros x y relatedY z relatedZ132obtain⟨_, valueY⟩:= quotientEnd.relates with relatedY133obtain⟨_, valueZ⟩:= quotientEnd.relates with relatedZ134cc135 . intros x edge136have vertex := FunctionBetween.apply_closed with function, edge137obtain⟨class, _⟩:= classOf.member with partition, vertex138witness classOf(P, endpoint(x))139exact⟨class,140 (quotientEnd.relates_class with function, partition, edge)⟩141142theorem quotientEnd.graph (V E P leftEnd rightEnd : Set)143requires graph : Graph(V, E, leftEnd, rightEnd)144requires partition : Partition(V, P)145shows Graph(P, E, quotientEnd(E, P, leftEnd), quotientEnd(E, P, rightEnd))146proof147constructor148 . exact quotientEnd.function with graph.left, partition149 . exact quotientEnd.function with graph.right, partition150151theorem quotientEnd.value (V E P leftEnd rightEnd e : Set)152requires graph : Graph(V, E, leftEnd, rightEnd)153requires partition : Partition(V, P)154requires edge : e ∈ E155shows quotientEnd(E, P, leftEnd)(e) = classOf(P, leftEnd(e)) ∧156 quotientEnd(E, P, rightEnd)(e) = classOf(P, rightEnd(e))157proof158constructor159 . exact FunctionBetween.apply_value with160 (quotientEnd.function with graph.left, partition), edge,161 (quotientEnd.relates_class with graph.left, partition, edge)162 . exact FunctionBetween.apply_value with163 (quotientEnd.function with graph.right, partition), edge,164 (quotientEnd.relates_class with graph.right, partition, edge)165166-- Edges within a class contribute nothing to crossing a union of classes, so167-- crossing in the quotient is crossing in the graph.168theorem crossing.quotient (V E P leftEnd rightEnd F Y : Set)169requires graph : Graph(V, E, leftEnd, rightEnd)170requires partition : Partition(V, P)171requires edges : F ⊆ E172requires classes : Y ⊆ P173shows crossing(quotientEnd(E, P, leftEnd), quotientEnd(E, P, rightEnd), F, Y)174= crossing(leftEnd, rightEnd, F, ⋃(Y))175proof176ext e177 by_cases inF : e ∈ F178 . have inE := edges with e, inF179obtain⟨leftValue, rightValue⟩:=180 quotientEnd.value with graph, partition, inE181have leftIn := FunctionBetween.apply_closed with graph.left, inE182have rightIn := FunctionBetween.apply_closed with graph.right, inE183have leftIff := classOf.mem_union_iff with partition, classes, leftIn184have rightIff := classOf.mem_union_iff with partition, classes, rightIn185simp [crossing, leftValue, rightValue, leftIff, rightIff]186 . simp [crossing, inF]187188-- F connects the classes of P in the quotient when its crossing edges do: an189-- edge inside a class is a loop of the quotient and leaves no vertex set.190theorem Connects.quotient_iff (V E P leftEnd rightEnd F : Set)191requires graph : Graph(V, E, leftEnd, rightEnd)192requires partition : Partition(V, P)193requires edges : F ⊆ E194shows Connects(P, quotientEnd(E, P, leftEnd), quotientEnd(E, P, rightEnd), F)195↔ Connects(P, quotientEnd(E, P, leftEnd), quotientEnd(E, P, rightEnd),196 crossingClasses(P, leftEnd, rightEnd, F))197proof198have crossingSubset : crossingClasses(P, leftEnd, rightEnd, F) ⊆ F199intros e member200exact member.left201constructor202 . intros connected X classX Y classY A start closed203have closedF : ClosedUnder(quotientEnd(E, P, leftEnd),204 quotientEnd(E, P, rightEnd), F, A)205intros e inF206 by_cases same : classOf(P, leftEnd(e)) = classOf(P, rightEnd(e))207 . have inE := edges with e, inF208obtain⟨leftValue, rightValue⟩:=209 quotientEnd.value with graph, partition, inE210simp [leftValue, rightValue, same]211 . exact closed with e, ⟨inF, same⟩212exact connected with X, classX, Y, classY, A, start, closedF213 . intros connected X classX Y classY214have joined := connected with X, classX, Y, classY215exact Joined.monotone with crossingSubset, joined216