(* ========================================================================= *)
(* Impossibility of Eulerian path for bridges of Koenigsberg. *)
(* ========================================================================= *)
(* ------------------------------------------------------------------------- *)
(* Definition of an undirected graph. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Connection in a graph. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Delete an edge in a graph. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Local finiteness: set of edges with given endpoint is finite. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Degree of a vertex. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Definition of Eulerian path. *)
(* ------------------------------------------------------------------------- *)
let eulerian_RULES,eulerian_INDUCT,eulerian_CASES = new_inductive_definition
`(!G a. a IN vertices G /\ edges G = {} ==> eulerian G [] (a,a)) /\
(!G a b c e es. e IN edges(G) /\ connects G e (a,b) /\
eulerian (delete_edge e G) es (b,c)
==> eulerian G (CONS e es) (a,c))`;;
(* ------------------------------------------------------------------------- *)
(* The main result. *)
(* ------------------------------------------------------------------------- *)
let EULERIAN_ODD_LEMMA = prove
(`!G:(E->bool)#(V->bool)#(E->V->bool) es ab.
eulerian G es ab
==> graph G
==>
FINITE(edges G) /\
!v. v
IN vertices G
==> (
ODD(degree G v) <=>
~(
FST ab =
SND ab) /\ (v =
FST ab \/ v =
SND ab))`,
MATCH_MP_TAC
eulerian_INDUCT THEN CONJ_TAC THENL
[SIMP_TAC[degree;
NOT_IN_EMPTY; SET_RULE `{x | F} = {}`] THEN
SIMP_TAC[
NSUM_CLAUSES;
FINITE_RULES; ARITH];
ALL_TAC] THEN
SIMP_TAC[
GRAPH_DELETE_EDGE;
FINITE_DELETE;
DELETE_EDGE_CLAUSES] THEN
REPEAT GEN_TAC THEN
DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
ASM_SIMP_TAC[
GRAPH_DELETE_EDGE] THEN STRIP_TAC THEN
X_GEN_TAC `v:V` THEN DISCH_TAC THEN
MP_TAC(ISPECL [`G:(E->bool)#(V->bool)#(E->V->bool)`; `e:E`; `v:V`]
DEGREE_DELETE_EDGE) THEN
ANTS_TAC THENL
[ASM_REWRITE_TAC[
locally_finite] THEN GEN_TAC THEN DISCH_TAC THEN
MATCH_MP_TAC
FINITE_SUBSET THEN
EXISTS_TAC `edges(G:(E->bool)#(V->bool)#(E->V->bool))` THEN
ASM_SIMP_TAC[
SUBSET;
IN_ELIM_THM];
ALL_TAC] THEN
DISCH_THEN SUBST1_TAC THEN
MP_TAC(ISPECL [`G:(E->bool)#(V->bool)#(E->V->bool)`; `e:E`]
TERMINI_IN_VERTICES) THEN
ASM_REWRITE_TAC[] THEN
FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [connects]) THEN
DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[
IN_INSERT;
NOT_IN_EMPTY] THEN
ASM_CASES_TAC `b:V = a` THEN ASM_REWRITE_TAC[] THENL
[REWRITE_TAC[SET_RULE `{a,a} = {v} <=> v = a`] THEN
COND_CASES_TAC THEN ASM_SIMP_TAC[
ODD_ADD; ARITH];
ALL_TAC] THEN
ASM_REWRITE_TAC[SET_RULE `{a,b} = {v} <=> a = b /\ a = v`] THEN
COND_CASES_TAC THEN ASM_SIMP_TAC[
ODD_ADD; ARITH] THEN ASM_MESON_TAC[]);;
let EULERIAN_ODD = prove
(`!G es a b.
graph G /\
eulerian G es (a,b)
==> !v. v
IN vertices G
==> (
ODD(degree G v) <=> ~(a = b) /\ (v = a \/ v = b))`,
REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
DISCH_THEN(MP_TAC o MATCH_MP
EULERIAN_ODD_LEMMA) THEN
ASM_SIMP_TAC[
FST;
SND]);;
(* ------------------------------------------------------------------------- *)
(* Now the actual Koenigsberg configuration. *)
(* ------------------------------------------------------------------------- *)
let KOENIGSBERG = prove
(`!G. vertices(G) = {0,1,2,3} /\
edges(G) = {10,20,30,40,50,60,70} /\
termini G (10) = {0,1} /\
termini G (20) = {0,2} /\
termini G (30) = {0,3} /\
termini G (40) = {1,2} /\
termini G (50) = {1,2} /\
termini G (60) = {2,3} /\
termini G (70) = {2,3}
==> ~(?es a b.
eulerian G es (a,b))`,
GEN_TAC THEN STRIP_TAC THEN
MP_TAC(ISPEC `G:(num->bool)#(num->bool)#(num->num->bool)`
EULERIAN_ODD) THEN
REWRITE_TAC[
NOT_EXISTS_THM] THEN
REPEAT(MATCH_MP_TAC
MONO_FORALL THEN GEN_TAC) THEN
DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN ANTS_TAC THENL
[ASM_REWRITE_TAC[graph] THEN GEN_TAC THEN
REWRITE_TAC[
IN_INSERT;
NOT_IN_EMPTY] THEN STRIP_TAC THEN
ASM_REWRITE_TAC[SET_RULE
`{a,b} = {x,y} <=> a = x /\ b = y \/ a = y /\ b = x`] THEN
MESON_TAC[];
ALL_TAC] THEN
ASM_REWRITE_TAC[
IN_INSERT;
NOT_IN_EMPTY] THEN
SIMP_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
ASM_REWRITE_TAC[degree; edges] THEN
SIMP_TAC[TAUT `a
IN s /\ k
IN t <=> ~(a
IN s ==> ~(k
IN t))`] THEN
ASM_REWRITE_TAC[
IN_INSERT;
NOT_IN_EMPTY] THEN
SIMP_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
ASM_REWRITE_TAC[
IN_INSERT;
NOT_IN_EMPTY; ARITH] THEN
REWRITE_TAC[DE_MORGAN_THM] THEN
REWRITE_TAC[SET_RULE `{x | x = a \/ P(x)} = a
INSERT {x | P(x)}`] THEN
REWRITE_TAC[SET_RULE `{x | x = a} = {a}`] THEN
SIMP_TAC[
NSUM_CLAUSES;
FINITE_INSERT;
FINITE_EMPTY] THEN
REWRITE_TAC[
IN_INSERT;
NOT_IN_EMPTY; ARITH] THEN
ASM_REWRITE_TAC[localdegree;
IN_INSERT;
NOT_IN_EMPTY; ARITH] THEN
REWRITE_TAC[SET_RULE `{a,b} = {x} <=> x = a /\ a = b`] THEN
DISCH_THEN(fun th ->
MP_TAC(SPEC `0` th) THEN MP_TAC(SPEC `1` th) THEN
MP_TAC(SPEC `2` th) THEN MP_TAC(SPEC `3` th)) THEN
REWRITE_TAC[ARITH] THEN ARITH_TAC);;
(******
Maybe for completeness I should show the contrary: existence of Eulerian
circuit/walk if we do have the right properties, assuming the graph is
connected; cf:
http://math.arizona.edu/~lagatta/class/fa05/m105/graphtheorynotes.pdf
*****)