-
Notifications
You must be signed in to change notification settings - Fork 0
/
Berge.thy
2982 lines (2716 loc) · 122 KB
/
Berge.thy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(*
Author: Mohammad Abdulaziz, TUM
Author: Martin Molzer, TUM improved the automation
*)
theory Berge
imports Main "HOL-Library.Extended_Nat"
begin
subsection\<open>Paths, connected components, and symmetric differences\<close>
text\<open>Some basic definitions about the above concepts. One interesting point is the use of the
concepts of connected components, which partition the set of vertices, and the analogous
partition of edges. Juggling around between the two partitions, we get a much shorter proof for
the first direction of Berge's lemma, which is the harder one.\<close>
definition Vs where "Vs E \<equiv> \<Union> E"
lemma vs_member[iff?]: "v \<in> Vs E \<longleftrightarrow> (\<exists>e \<in> E. v \<in> e)"
unfolding Vs_def by simp
lemma vs_member_elim[elim?]:
assumes "v \<in> Vs E"
obtains e where "v \<in> e" "e \<in> E"
using assms
by(auto simp: vs_member)
lemma vs_member_intro[intro]:
assumes "v \<in> e" "e \<in> E"
shows "v \<in> Vs E"
by (meson vs_member assms)
lemma vs_transport[intro?]:
assumes "u \<in> Vs E"
assumes "\<And>e. u \<in> e \<Longrightarrow> e \<in> E \<Longrightarrow> \<exists>g \<in> F. u \<in> g"
shows "u \<in> Vs F"
by (meson assms vs_member)
lemma edges_are_Vs:
assumes "{v, v'} \<in> E"
shows "v \<in> Vs E" "v' \<in> Vs E"
using assms by blast+
locale graph_defs =
fixes E :: "'a set set"
abbreviation "graph_invar E \<equiv> (\<forall>e\<in>E. \<exists>u v. e = {u, v} \<and> u \<noteq> v) \<and> finite (Vs E)"
locale graph_abs =
graph_defs +
assumes graph: "graph_invar E"
begin
lemma finite_E: "finite E"
using finite_UnionD graph
unfolding Vs_def
by blast
end
context fixes X :: "'a set set" begin
inductive path where
path0: "path []" |
path1: "v \<in> Vs X \<Longrightarrow> path [v]" |
path2: "{v,v'} \<in> X \<Longrightarrow> path (v'#vs) \<Longrightarrow> path (v#v'#vs)"
end
value[nbe] "path {{1::nat, 2}, {2, 3}, {3, 4}} [1, 4, 3] = True"
declare path0[simp]
inductive_simps path_1[simp]: "path X [v]"
inductive_simps path_2[simp]: "path X (v # v' # vs)"
text\<open>
If a set of edges cannot be partitioned in paths, then it has a junction of 3 or more edges.
In particular, an edge from one of the two matchings belongs to the path
equivalent to one connected component. Otherwise, there will be a vertex whose degree is
more than 2.
\<close>
text\<open>
Every edge lies completely in a connected component.
\<close>
fun edges_of_path where
"edges_of_path [] = []" |
"edges_of_path [v] = []" |
"edges_of_path (v#v'#l) = {v,v'} # (edges_of_path (v'#l))"
lemma path_ball_edges: "path E p \<Longrightarrow> b \<in> set (edges_of_path p) \<Longrightarrow> b \<in> E"
by (induction p rule: edges_of_path.induct, auto)
lemma edges_of_path_index:
"Suc i < length p \<Longrightarrow> edges_of_path p ! i = {p ! i, p ! Suc i}"
proof(induction i arbitrary: p)
case 0
then obtain u v ps where "p = u#v#ps" by (metis Suc_leI Suc_le_length_iff)
thus ?case by simp
next
case (Suc i)
then obtain u v ps where "p = u#v#ps" by (metis Suc_leI Suc_le_length_iff)
hence "edges_of_path (v#ps) ! i = {(v#ps) ! i, (v#ps) ! Suc i}" using Suc.IH Suc.prems by simp
thus ?case using \<open>p = u#v#ps\<close> by simp
qed
lemma edges_of_path_length: "length (edges_of_path p) = length p - 1"
by (induction p rule: edges_of_path.induct, auto)
lemma edges_of_path_for_inner:
assumes "v = p ! i" "Suc i < length p"
obtains u w where "{u, v} = edges_of_path p ! (i - 1)" "{v, w} = edges_of_path p ! i"
proof(cases "i = 0")
case True thus ?thesis
by (metis assms diff_is_0_eq' edges_of_path_index insert_commute nat_le_linear not_one_le_zero that)
next
case False thus ?thesis by (simp add: Suc_lessD assms(1) assms(2) edges_of_path_index that)
qed
lemma path_vertex_has_edge:
assumes "length p \<ge> 2" "v \<in> set p"
obtains e where "e \<in> set (edges_of_path p)" "v \<in> e"
proof-
obtain i where idef: "v = p ! i" "i < length p" by (metis assms(2) in_set_conv_nth)
have eoplength': "Suc (length (edges_of_path p)) = length p"
using assms(1) by (auto simp: edges_of_path_length)
hence eoplength: "length (edges_of_path p) \<ge> 1" using assms(1) by simp
from idef consider (nil) "i = 0" | (gt) "i > 0" "Suc i < length p" | (last) "Suc i = length p"
by linarith
thus ?thesis
proof cases
case nil
hence "edges_of_path p ! 0 = {p ! 0, p ! 1}" using edges_of_path_index assms(1) by force
thus ?thesis using nil eoplength idef(1)
by (metis One_nat_def Suc_le_lessD insertI1 nth_mem that)
next
case last
hence "edges_of_path p ! (i -1) = {p ! (i - 1), p ! i}"
by (metis Suc_diff_le eoplength' diff_Suc_1 edges_of_path_index eoplength idef(2))
thus ?thesis using last eoplength eoplength' idef(1)
by (metis Suc_inject diff_less insertCI less_le_trans nth_mem that zero_less_one)
next
case gt
thus ?thesis using edges_of_path_for_inner idef(1) eoplength'
by (metis Suc_less_SucD in_set_conv_nth insertI1 that)
qed
qed
lemma v_in_edge_in_path:
assumes "{u, v} \<in> set (edges_of_path p)"
shows "u \<in> set p"
using assms
by (induction p rule: edges_of_path.induct, auto)
lemma v_in_edge_in_path_inj:
assumes "e \<in> set (edges_of_path p)"
obtains u v where "e = {u, v}"
using assms
by (induction p rule: edges_of_path.induct, auto)
lemma v_in_edge_in_path_gen:
assumes "e \<in> set (edges_of_path p)" "u \<in> e"
shows "u \<in> set p"
proof-
obtain u v where "e = {u, v}" using assms(1) v_in_edge_in_path_inj by blast
thus ?thesis by (metis assms empty_iff insert_commute insert_iff v_in_edge_in_path)
qed
lemma distinct_edges_of_vpath:
"distinct p \<Longrightarrow> distinct (edges_of_path p)"
using v_in_edge_in_path
by (induction p rule: edges_of_path.induct) fastforce+
lemma distinct_edges_of_paths_cons:
assumes "distinct (edges_of_path (v # p))"
shows "distinct (edges_of_path p)"
using assms
by(cases "p"; simp)
lemma hd_edges_neq_last:
assumes "{hd p, last p} \<notin> set (edges_of_path p)" "hd p \<noteq> last p" "p \<noteq> []"
shows "hd (edges_of_path (last p # p)) \<noteq> last (edges_of_path (last p # p))"
using assms
proof(induction p)
case Nil
then show ?case by simp
next
case (Cons)
then show ?case
apply (auto split: if_splits)
using edges_of_path.elims apply blast
by (simp add: insert_commute)
qed
lemma edges_of_path_append_2:
assumes "p' \<noteq> []"
shows "edges_of_path (p @ p') = edges_of_path (p @ [hd p']) @ edges_of_path p'"
using assms
proof(induction p rule: induct_list012)
case 2
obtain a p's where "p' = a # p's" using assms list.exhaust_sel by blast
thus ?case by simp
qed simp_all
lemma edges_of_path_append_3:
assumes "p \<noteq> []"
shows "edges_of_path (p @ p') = edges_of_path p @ edges_of_path (last p # p')"
proof-
from assms
have "edges_of_path (p @ p') = edges_of_path (butlast p @ last p # p')"
by (metis append.assoc append_Cons append_Nil append_butlast_last_id)
also have "... = edges_of_path (butlast p @ [last p]) @ edges_of_path (last p # p')"
using edges_of_path_append_2 by fastforce
also have "... = edges_of_path p @ edges_of_path (last p # p')"
by (simp add: assms)
finally show ?thesis .
qed
lemma edges_of_path_rev:
shows "rev (edges_of_path p) = edges_of_path (rev p)"
proof(induction "length p" arbitrary: p)
case 0
then show ?case by simp
next
case (Suc x)
then obtain a' p' where p': "p = a' # p'"
by (metis length_Suc_conv)
then have "rev (edges_of_path p') = edges_of_path (rev p')"
using Suc
by auto
then show ?case
using p' edges_of_path_append_2
apply (cases p' ;simp)
by (smt edges_of_path.simps(2) edges_of_path.simps(3) edges_of_path_append_2 insert_commute list.distinct(1) list.sel(1))
qed
lemma edges_of_path_append: "\<exists>ep. edges_of_path (p @ p') = ep @ edges_of_path p'"
proof(cases p')
case Nil thus ?thesis by simp
next
case Cons thus ?thesis using edges_of_path_append_2 by blast
qed
lemma last_v_in_last_e:
assumes "length p \<ge> 2"
shows "last p \<in> last (edges_of_path p)"
using assms
proof(induction "p" rule: induct_list012)
case 1 thus ?case by simp
next
case 2 thus ?case by simp
next
case p: (3 a b p)
then show ?case apply (auto split: if_splits)
subgoal using edges_of_path.elims by blast
subgoal by (simp add: Suc_leI)
done
qed
lemma hd_v_in_hd_e:
assumes "length p \<ge> 2"
shows "hd p \<in> hd (edges_of_path p)"
proof-
obtain a b ps where "p = a # b # ps"
by (metis Suc_le_length_iff assms numeral_2_eq_2)
thus ?thesis by simp
qed
lemma last_in_edge:
assumes "p \<noteq> []"
shows "\<exists>u. {u, last p} \<in> set (edges_of_path (v # p)) \<and> u \<in> set (v # p)"
using assms
proof(induction "length p" arbitrary: v p)
case 0
then show ?case by simp
next
case (Suc x)
show ?case
proof(cases p)
case Nil
then show ?thesis
using Suc
by auto
next
case p: (Cons _ p')
show ?thesis
proof(cases "p' = []")
case True
then show ?thesis
using p
by auto
next
case False
then show ?thesis
using Suc
by(auto simp add: p)
qed
qed
qed
lemma edges_of_path_append_subset:
shows "set (edges_of_path p') \<subseteq> set (edges_of_path (p @ p'))"
using edges_of_path_append
by (metis eq_iff le_supE set_append)
lemma path_edges_subset:
assumes "path E p"
shows "set (edges_of_path p) \<subseteq> E"
using assms
by (induction, simp_all)
lemma induct_list0123[consumes 0, case_names nil list1 list2 list3]:
"\<lbrakk>P []; \<And>x. P [x]; \<And>x y. P [x, y]; \<And>x y z zs. \<lbrakk> P zs; P (z # zs); P (y # z # zs) \<rbrakk> \<Longrightarrow> P (x # y # z # zs)\<rbrakk> \<Longrightarrow> P xs"
by induction_schema (pat_completeness, lexicographic_order)
lemma tl_path_is_path: "path E p \<Longrightarrow> path E (tl p)"
by (induction p rule: path.induct) (simp_all)
lemma path_concat:
assumes "path E p" "path E q" "q \<noteq> []" "p \<noteq> [] \<Longrightarrow> last p = hd q"
shows "path E (p @ tl q)"
using assms
by (induction) (simp_all add: tl_path_is_path)
lemma path_append:
assumes "path E p1" "path E p2" "p1 \<noteq> [] \<Longrightarrow> p2 \<noteq> [] \<Longrightarrow> {last p1, hd p2} \<in> E"
shows "path E (p1 @ p2)"
proof-
have "path E (last p1 # p2)" if "p1 \<noteq> []" and "p2 \<noteq> []"
by (metis assms(2) assms(3) hd_Cons_tl path_2 that(1) that(2))
thus ?thesis using assms(1) assms(2) path_concat by fastforce
qed
lemma mem_path_Vs:
assumes "path E p" "a\<in>set p"
shows "a \<in> Vs E"
using assms edges_are_Vs
by (induction, simp_all) fastforce
lemma path_suff:
assumes "path E (p1 @ p2)"
shows "path E p2"
using assms
proof(induction p1)
case (Cons a p1)
then show ?case using Cons tl_path_is_path by force
qed simp
lemma path_pref:
assumes "path E (p1 @ p2)"
shows "path E p1"
using assms
proof(induction p1)
case (Cons a p1)
then show ?case using Cons by (cases p1; auto simp add: mem_path_Vs)
qed simp
lemma rev_path_is_path:
assumes "path E p"
shows "path E (rev p)"
using assms
proof(induction)
case (path2 v v' vs)
hence "{last (rev vs @ [v']), hd [v]} \<in> E" by (simp add: insert_commute)
then show ?case using path2.IH path2.hyps(1) path_append
by (metis edges_are_Vs path1 rev.simps(2))
qed simp_all
lemma Vs_subset:
assumes "E \<subseteq> E'"
shows "Vs E \<subseteq> Vs E'"
using assms
unfolding Vs_def
by auto
lemma path_subset:
assumes "path E p" "E \<subseteq> E'"
shows "path E' p"
using assms Vs_subset
by (induction, auto)
lemma path_edges_of_path_refl: "length p \<ge> 2 \<Longrightarrow> path (set (edges_of_path p)) p"
proof (induction p rule: edges_of_path.induct)
case (3 v v' l)
thus ?case
apply (cases l)
by (auto intro: path_subset simp add: edges_are_Vs insert_commute path2)
qed simp_all
lemma edges_of_path_Vs: "Vs (set (edges_of_path p)) \<subseteq> set p"
by (meson subsetI v_in_edge_in_path_gen vs_member_elim)
subsection \<open>walks, and connected components\<close>
definition "walk_betw E u p v \<equiv> (p \<noteq> [] \<and> path E p \<and> hd p = u \<and> last p = v)"
lemma nonempty_path_walk_between[intro?]:
assumes "path E p" "p \<noteq> []" "hd p = u" "last p = v"
shows "walk_betw E u p v"
unfolding walk_betw_def using assms by simp
lemma walk_nonempty:
assumes "walk_betw E u p v"
shows [simp]: "p \<noteq> []"
using assms walk_betw_def by fastforce
lemma walk_between_nonempty_path[elim]:
assumes "walk_betw E u p v"
shows "path E p" "p \<noteq> []" "hd p = u" "last p = v"
using assms unfolding walk_betw_def by simp_all
lemma walk_reflexive:
assumes "w \<in> Vs E"
shows "walk_betw E w [w] w"
by (simp add: assms nonempty_path_walk_between)
lemma walk_symmetric:
assumes "walk_betw E u p v"
shows "walk_betw E v (rev p) u"
by (metis assms Nil_is_rev_conv hd_rev rev_path_is_path rev_rev_ident walk_betw_def)
lemma walk_transitive:
assumes "walk_betw E u p v" "walk_betw E v q w"
shows "walk_betw E u (p @ tl q) w"
using assms unfolding walk_betw_def
using path_concat append_is_Nil_conv
by (metis hd_append last_ConsL last_appendR last_tl list.exhaust_sel self_append_conv)
lemma walk_in_Vs:
assumes "walk_betw E a p b"
shows "set p \<subseteq> Vs E"
by (meson assms mem_path_Vs subset_code(1) walk_betw_def)
lemma walk_endpoints:
assumes "walk_betw E u p v"
shows [simp]: "u \<in> Vs E"
and [simp]: "v \<in> Vs E"
using assms mem_path_Vs walk_betw_def by fastforce+
lemma walk_pref:
assumes "walk_betw E u (pr @ [x] @ su) v"
shows "walk_betw E u (pr @ [x]) x"
by (metis append.assoc assms hd_append path_pref snoc_eq_iff_butlast walk_betw_def)
lemma walk_suff:
assumes "walk_betw E u (pr @ [x] @ su) v"
shows "walk_betw E x (x # su) v"
by (metis append_Cons append_Nil assms last_appendR list.distinct(1) list.sel(1) path_suff walk_betw_def)
lemma edges_are_walks:
assumes "{v, w} \<in> E"
shows "walk_betw E v [v, w] w"
using assms edges_are_Vs nonempty_path_walk_between path1 path2
by (metis insert_commute last.simps list.sel(1) list.simps(3))
lemma walk_subset:
assumes "E \<subseteq> E'"
assumes "walk_betw E u p v"
shows "walk_betw E' u p v"
using assms unfolding walk_betw_def
using path_subset by blast
lemma induct_walk_betw[case_names path1 path2, consumes 1, induct set: walk_betw]:
assumes "walk_betw E a p b"
assumes Path1: "\<And>v. v \<in> Vs E \<Longrightarrow> P v [v] v"
assumes Path2: "\<And>v v' vs b. {v, v'} \<in> E \<Longrightarrow> walk_betw E v' (v' # vs) b \<Longrightarrow> P v' (v' # vs) b \<Longrightarrow> P v (v # v' # vs) b"
shows "P a p b"
proof-
have "path E p" "p \<noteq> []" "hd p = a" "last p = b" using assms(1) by auto
thus ?thesis
proof(induction arbitrary: a b)
case path0 thus ?case by simp
next
case path1 thus ?case using Path1 by fastforce
next
case path2 thus ?case
by (metis Path2 last_ConsR list.distinct(1) list.sel(1) nonempty_path_walk_between)
qed
qed
definition connected_component where
"connected_component E v = {v'. v' = v \<or> (\<exists>p. walk_betw E v p v')}"
definition connected_components where
"connected_components E \<equiv> {vs. \<exists>v. vs = connected_component E v \<and> v \<in> (Vs E)}"
lemma in_own_connected_component: "v \<in> connected_component E v"
unfolding connected_component_def by simp
lemma in_connected_component_has_path:
assumes "v \<in> connected_component E w" "w \<in> Vs E"
obtains p where "walk_betw E w p v"
proof(cases "v = w")
case True thus ?thesis using that assms(2) walk_reflexive by metis
next
case False
then obtain p where "walk_betw E w p v"
using assms(1) unfolding connected_component_def by blast
thus ?thesis using that by blast
qed
lemma has_path_in_connected_component[intro]:
assumes "walk_betw E u p v"
shows "v \<in> connected_component E u"
unfolding connected_component_def using assms by blast
lemma connected_components_notE_singletons:
assumes "x \<notin> Vs E"
shows "connected_component E x = {x}"
proof(standard; standard)
fix y assume yconnected: "y \<in> connected_component E x"
{
assume "x \<noteq> y"
then obtain p where "walk_betw E x p y"
using yconnected unfolding connected_component_def by blast
hence "x \<in> Vs E" by simp
hence False using assms by blast
}
thus "y \<in> {x}" by blast
next
fix y assume "y \<in> {x}"
hence "x = y" by blast
thus "y \<in> connected_component E x" by (simp add: connected_component_def)
qed
lemma connected_components_member_sym:
assumes "v \<in> connected_component E w"
shows "w \<in> connected_component E v"
proof-
{
assume "v \<noteq> w"
hence "w \<in> Vs E" using connected_components_notE_singletons assms by fastforce
hence ?thesis
by (meson assms has_path_in_connected_component in_connected_component_has_path walk_symmetric)
}
thus ?thesis using assms by blast
qed
lemma connected_components_member_trans:
assumes "x \<in> connected_component E y" "y \<in> connected_component E z"
shows "x \<in> connected_component E z"
proof-
{
assume "x \<noteq> y" "y \<noteq> z"
hence "y \<in> Vs E" "z \<in> Vs E" using assms connected_components_notE_singletons by fastforce+
hence "x \<in> connected_component E z"
by (meson assms has_path_in_connected_component in_connected_component_has_path walk_transitive)
}
thus ?thesis using assms by blast
qed
lemma connected_components_member_eq:
assumes "v \<in> connected_component E w"
shows "connected_component E v = connected_component E w"
using assms connected_components_member_sym connected_components_member_trans
by (metis dual_order.antisym subsetI)
lemma connected_components_closed:
assumes v1_in_C: "v1 \<in> connected_component E v4" and
v3_in_C: "v3 \<in> connected_component E v4"
shows "v3 \<in> connected_component E v1"
using connected_components_member_eq v1_in_C v3_in_C by fastforce
lemma connected_components_closed':
assumes C_is_comp: "C \<in> connected_components E"
assumes v_in_C: "v \<in> C"
shows "C = connected_component E v"
proof-
from C_is_comp
obtain v4 where v4: "C = connected_component E v4" "v4 \<in> Vs E"
unfolding connected_components_def by blast
thus ?thesis using connected_components_member_eq v_in_C by metis
qed
lemma connected_components_disj:
assumes "C \<noteq> C'" "C \<in> connected_components E" "C' \<in> connected_components E"
shows "C \<inter> C' = {}"
by (metis assms connected_components_closed' disjoint_iff_not_equal)
lemma own_connected_component_unique:
assumes "x \<in> Vs E"
shows "\<exists>!C \<in> connected_components E. x \<in> C"
proof(standard, intro conjI)
show "connected_component E x \<in> connected_components E"
using assms connected_components_def by blast
show "x \<in> connected_component E x" using in_own_connected_component by fastforce
fix C assume "C \<in> connected_components E \<and> x \<in> C"
thus "C = connected_component E x" by (simp add: connected_components_closed')
qed
lemma edge_in_component:
assumes "{x,y} \<in> E"
shows "\<exists>C. C \<in> connected_components E \<and> {x,y} \<subseteq> C"
proof-
have "y \<in> connected_component E x"
proof(standard, standard)
show "path E [x, y]" by (metis assms edges_are_Vs insert_commute path1 path2)
qed simp_all
moreover have "x \<in> Vs E" by (meson assms edges_are_Vs)
ultimately show ?thesis
unfolding connected_components_def
using in_own_connected_component
by fastforce
qed
lemma edge_in_unique_component:
assumes "{x,y} \<in> E"
shows "\<exists>!C. C \<in> connected_components E \<and> {x,y} \<subseteq> C"
using edge_in_component connected_components_closed'
by (metis assms insert_subset)
lemma connected_component_set[intro]:
assumes "u \<in> Vs E"
assumes "\<And>x. x \<in> C \<Longrightarrow> \<exists>p. walk_betw E u p x"
assumes "\<And>x p. walk_betw E u p x \<Longrightarrow> x \<in> C"
shows "connected_component E u = C"
proof(standard; standard)
fix x
assume "x \<in> connected_component E u"
thus "x \<in> C" by (meson assms(1) assms(3) in_connected_component_has_path)
next
fix x
assume "x \<in> C"
thus "x \<in> connected_component E u" by (meson assms(2) has_path_in_connected_component)
qed
text\<open>
Now we should be able to partition the set of edges into equivalence classes
corresponding to the connected components.\<close>
definition component_edges where
"component_edges E C = {{x, y} | x y. {x, y} \<subseteq> C \<and> {x, y} \<in> E}"
lemma component_edges_disj_edges:
assumes "C \<in> connected_components E" "C' \<in> connected_components E" "C \<noteq> C'"
assumes "v \<in> component_edges E C" "w \<in> component_edges E C'"
shows "v \<inter> w = {}"
proof(intro equals0I)
fix x assume "x \<in> v \<inter> w"
hence "x \<in> C" "x \<in> C'" using assms(4, 5) unfolding component_edges_def by blast+
thus False by (metis assms(1-3) connected_components_closed')
qed
lemma component_edges_disj:
assumes "C \<in> connected_components E" "C' \<in> connected_components E" "C \<noteq> C'"
shows "component_edges E C \<inter> component_edges E C' = {}"
proof(intro equals0I, goal_cases)
case (1 y)
hence "y = {}" using assms component_edges_disj_edges by (metis IntD1 IntD2 Int_absorb)
thus False using 1 unfolding component_edges_def by blast
qed
lemma connected_component_subs_Vs:
assumes "C \<in> connected_components E"
shows "C \<subseteq> Vs E"
proof(safe)
fix x assume "x \<in> C"
from assms
obtain y where "C = connected_component E y" "y \<in> Vs E"
by (smt connected_components_def mem_Collect_eq)
thus "x \<in> Vs E" by (metis \<open>x \<in> C\<close> in_connected_component_has_path walk_endpoints(2))
qed
definition components_edges where
"components_edges E = {component_edges E C| C. C \<in> connected_components E}"
lemma connected_comp_nempty:
assumes "C \<in> connected_components E"
shows "C \<noteq> {}"
using assms unfolding connected_components_def
using in_own_connected_component by fastforce
lemma connected_comp_verts_in_verts:
assumes "v \<in> C" "C \<in> connected_components E"
shows "v \<in> Vs E"
using assms connected_component_subs_Vs by blast
lemma connected_comp_has_vert:
assumes "C \<in> connected_components E"
obtains w where "w \<in> Vs E" "C = connected_component E w"
by (metis assms connected_comp_nempty connected_comp_verts_in_verts connected_components_closed' ex_in_conv)
lemma component_edges_partition:
shows "\<Union> (components_edges E) = E \<inter> {{x,y}| x y. True}"
unfolding components_edges_def
proof(safe)
fix x y
assume "{x, y} \<in> E"
then obtain C where "{x, y} \<subseteq> C" "C \<in> connected_components E" by (meson edge_in_component)
moreover then have "{x, y} \<in> component_edges E C"
using \<open>{x, y} \<in> E\<close> component_edges_def by fastforce
ultimately show "{x, y} \<in> \<Union> {component_edges E C |C. C \<in> connected_components E}" by blast
qed (auto simp add: component_edges_def)
text\<open>Since one of the matchings is bigger, there must be one edge equivalence class
that has more edges from the bigger matching.\<close>
lemma lt_sum:
assumes "(\<Sum>x\<in>s. g x) < (\<Sum>x\<in>s. f x)"
shows "\<exists>(x::'a ) \<in> s. ((g::'a \<Rightarrow> nat) x < f x)"
using assms sum_mono
by (metis not_le)
lemma Union_lt:
assumes finite: "finite S" "finite t" "finite u" and
card_lt: "card ((\<Union> S) \<inter> t) < card ((\<Union> S) \<inter> u)" and
disj: "\<forall>s\<in>S.\<forall>s'\<in>S. s \<noteq> s' \<longrightarrow> s \<inter> s' = {}"
shows "\<exists>s\<in>S. card (s \<inter> t) < card (s \<inter> u)"
proof-
{
fix t::"'a set"
assume ass: "finite t"
have "card (\<Union>s\<in>S. s \<inter> t) = (\<Sum>s\<in>S. card (s \<inter> t))"
apply(intro card_UN_disjoint finite)
subgoal using ass by simp
subgoal using disj by auto
done
}note * = this
show ?thesis
apply (intro lt_sum)
using card_lt *[OF finite(2)] *[OF finite(3)]
by auto
qed
(*
The edges in that bigger equivalence class can be ordered in a path, since the degree of any
vertex cannot exceed 2. Also that path should start and end with edges from the bigger matching.
*)
subsection\<open>Alternating lists and auxilliary theory about them\<close>
inductive alt_list where
"alt_list P1 P2 []" |
"P1 x \<Longrightarrow> alt_list P2 P1 l \<Longrightarrow> alt_list P1 P2 (x#l)"
inductive_simps alt_list_empty: "alt_list P1 P2 []"
inductive_simps alt_list_step: "alt_list P1 P2 (x#l)"
lemma induct_list012:
"\<lbrakk>P []; \<And>x. P [x]; \<And>x y zs. \<lbrakk> P zs; P (y # zs) \<rbrakk> \<Longrightarrow> P (x # y # zs)\<rbrakk> \<Longrightarrow> P xs"
by induction_schema (pat_completeness, lexicographic_order)
lemma induct_alt_list012[consumes 1, case_names nil single sucsuc]:
assumes "alt_list P1 P2 l"
assumes "T []"
assumes "\<And>x. P1 x \<Longrightarrow> T [x]"
assumes "\<And>x y zs. P1 x \<Longrightarrow> P2 y \<Longrightarrow> T zs \<Longrightarrow> T (x#y#zs)"
shows "T l"
using assms(1)
proof(induction l rule: induct_list012)
case 1 thus ?case using assms(2) by simp
next
case (2 x) thus ?case
by (simp add: alt_list_step assms(3))
next
case (3 x y zs)
hence "T zs" by (simp add: alt_list_step)
thus ?case by (metis "3.prems" alt_list_step assms(4))
qed
lemma alternating_length:
assumes "\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
shows "length l = length (filter P1 l) + length (filter P2 l)"
using assms by (induction l) auto
lemma alternating_length_balanced:
assumes "alt_list P1 P2 l" "\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
shows "length (filter P1 l) = length (filter P2 l) \<or>
length (filter P1 l) = length (filter P2 l) + 1"
using assms by (induction l) auto
lemma alternating_eq_iff_even:
assumes "alt_list P1 P2 l" "\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
shows "length (filter P1 l) = length (filter P2 l) \<longleftrightarrow> even (length l)"
proof
assume "length (filter P1 l) = length (filter P2 l)"
thus "even (length l)" using assms alternating_length by force
next
assume "even (length l)"
thus "length (filter P1 l) = length (filter P2 l)"
using assms alternating_length_balanced
by (metis (no_types, lifting) alternating_length even_add odd_one)
qed
lemma alternating_eq_iff_odd:
assumes "alt_list P1 P2 l" "\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
shows "length (filter P1 l) = length (filter P2 l) + 1 \<longleftrightarrow> odd (length l)"
proof
assume "length (filter P1 l) = length (filter P2 l) + 1"
thus "odd (length l)" using assms alternating_length by force
next
assume "odd (length l)"
thus "length (filter P1 l) = length (filter P2 l) + 1"
using assms alternating_length_balanced alternating_eq_iff_even by blast
qed
lemma alternating_list_odd_index:
assumes "alt_list P1 P2 l" "odd n" "n < length l"
shows "P2 (l ! n)"
using assms
proof(induction arbitrary: n rule: induct_alt_list012)
case (sucsuc x y zs)
consider (l) "n = 1" | (h) "n \<ge> 2" using odd_pos sucsuc.prems(1) by fastforce
thus ?case
proof cases
case l thus ?thesis by (simp add: sucsuc.hyps(2))
next
case h
then obtain m where "n = Suc (Suc m)" using add_2_eq_Suc le_Suc_ex by blast
hence "P2 (zs ! m)" using sucsuc.IH sucsuc.prems(1, 2) by fastforce
thus ?thesis by (simp add: \<open>n = Suc (Suc m)\<close>)
qed
qed simp_all
lemma alternating_list_even_index:
assumes "alt_list P1 P2 l" "even n" "n < length l"
shows "P1 (l ! n)"
using assms
proof(induction arbitrary: n rule: induct_alt_list012)
case (sucsuc x y zs)
consider (l) "n = 0" | (h) "n \<ge> 2" using odd_pos sucsuc.prems(1) by fastforce
thus ?case
proof cases
case l thus ?thesis by (simp add: sucsuc.hyps(1))
next
case h
then obtain m where "n = Suc (Suc m)" using add_2_eq_Suc le_Suc_ex by blast
hence "P1 (zs ! m)" using sucsuc.IH sucsuc.prems(1, 2) by fastforce
thus ?thesis by (simp add: \<open>n = Suc (Suc m)\<close>)
qed
qed simp_all
lemma alternating_list_even_last:
assumes "alt_list P1 P2 l" "even (length l)" "l \<noteq> []"
shows "P2 (last l)"
proof-
have "odd (length l - 1)" by (simp add: assms(2) assms(3))
hence "P2 (l ! (length l - 1))" using alternating_list_odd_index
by (metis assms(1) assms(3) diff_less length_greater_0_conv odd_one odd_pos)
thus ?thesis using assms(3) by (simp add: last_conv_nth)
qed
lemma alternating_list_odd_last:
assumes "alt_list P1 P2 l" "odd (length l)"
shows "P1 (last l)"
proof-
have "even (length l - 1)" by (simp add: assms(2))
hence "P1 (l ! (length l - 1))" using alternating_list_even_index
using assms(1) assms(2) odd_pos by fastforce
thus ?thesis using assms(2) last_conv_nth odd_pos by force
qed
lemma alternating_list_gt_odd:
assumes "length (filter P1 l) > length (filter P2 l)"
assumes "alt_list P1 P2 l"
assumes "\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
shows "odd (length l)"
using assms alternating_eq_iff_even by fastforce
lemma alternating_list_eq_even:
assumes "length (filter P1 l) = length (filter P2 l)"
assumes "alt_list P1 P2 l" (* not actually used but complements gt_odd *)
assumes "\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
shows "even (length l)"
using assms alternating_eq_iff_even by fastforce
lemma alternating_list_eq_last':
assumes "length (filter P1 l) = length (filter P2 l)"
"\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
"l \<noteq> []"
"P2 (last l)"
shows "\<not> alt_list P2 P1 l"
by (metis alternating_eq_iff_even alternating_list_even_last assms last_in_set)
lemma alternating_list_gt:
assumes "length (filter P1 l) > length (filter P2 l)"
"\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
"alt_list P1 P2 l"
shows "P1 (hd l) \<and> P1 (last l)"
using alternating_list_odd_last assms
by (metis alt_list_step alternating_list_gt_odd filter.simps(1) list.exhaust_sel nat_neq_iff)
lemma alt_list_not_commute:
assumes "alt_list P1 P2 l"
"\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
"l \<noteq> []"
shows "\<not> alt_list P2 P1 l"
using assms
apply(cases "l = []"; simp)
by (metis alt_list.cases list.inject list.set_intros(1))
lemma alternating_list_gt_or:
assumes "length (filter P1 l) > length (filter P2 l)"
"\<forall>x\<in>set l. P1 x \<longleftrightarrow> \<not> P2 x"
shows "\<not> alt_list P2 P1 l"
using alternating_length_balanced assms by fastforce
lemma alt_list_cong_1:
assumes "alt_list P1 P2 l" "\<forall>x \<in> set l. P2 x \<longrightarrow> P3 x"
shows "alt_list P1 P3 l"
using assms
by (induction rule: induct_alt_list012)
(simp_all add: alt_list_empty alt_list_step)
lemma alt_list_cong_2:
assumes "alt_list P1 P2 l" "\<forall>x \<in> set l. P1 x \<longrightarrow> P3 x"
shows "alt_list P3 P2 l"
using assms
by (induction rule: induct_alt_list012)
(simp_all add: alt_list_empty alt_list_step)
lemma alt_list_cong:
assumes "alt_list P1 P2 l" "\<forall>x \<in> set l. P1 x \<longrightarrow> P3 x" "\<forall>x \<in> set l. P2 x \<longrightarrow> P4 x"
shows "alt_list P3 P4 l"
using assms
by (induction rule: induct_alt_list012)
(simp_all add: alt_list_empty alt_list_step)
lemma alt_list_append_1:
assumes "alt_list P1 P2 (l1 @ l2)"
shows "alt_list P1 P2 l1 \<and> (alt_list P1 P2 l2 \<or> alt_list P2 P1 l2)"
using assms
by (induction l1 rule: induct_list012)
(simp_all add: alt_list_empty alt_list_step)
lemma alt_list_append_2:
assumes "alt_list P1 P2 l1" "alt_list P2 P1 l2" "odd (length l1)"
shows "alt_list P1 P2 (l1 @ l2)"
using assms
proof (induction l1 rule: induct_list012)
case (3 x y zs)
hence "zs \<noteq> []" by force
hence "alt_list P1 P2 (zs @ l2)"
by (metis "3.IH"(1) "3.prems" alt_list_step even_Suc_Suc_iff length_Cons)
thus ?case by (metis "3.prems"(1) alt_list_step append_Cons)
qed (simp_all add: alt_list_step)
lemma alt_list_append_3:
assumes "alt_list P1 P2 l1" "alt_list P1 P2 l2" "even (length l1)"
shows "alt_list P1 P2 (l1 @ l2)"
using assms
proof (induction l1 rule: induct_list012)
case (3 x y zs)
hence "alt_list P1 P2 (zs @ l2)" by (simp add: alt_list_step)
thus ?case by (metis "3.prems"(1) alt_list_step append_Cons)
qed (simp_all add: alt_list_step)
lemma alt_list_split_1:
assumes "alt_list P1 P2 (l1 @ l2)" "even (length l1)"
shows "alt_list P1 P2 l2"
using assms
by (induction l1 rule: induct_list012)
(simp_all add: alt_list_step)
lemma alt_list_split_2:
assumes "alt_list P1 P2 (l1 @ l2)" "odd (length l1)"
shows "alt_list P2 P1 l2"
using assms
by (induction l1 rule: induct_list012)
(simp_all add: alt_list_step)
lemma alt_list_append_1':
assumes "alt_list P1 P2 (l1 @ l2)" "l1 \<noteq> []" "\<forall>x\<in>set l1. P1 x = (\<not> P2 x)"
shows "(alt_list P1 P2 l1 \<and> ((P2 (last l1) \<and> alt_list P1 P2 l2) \<or> (P1 (last l1) \<and> alt_list P2 P1 l2)))"
using assms
by (smt alt_list_append_1 alt_list_step append.assoc append_Cons append_Nil append_butlast_last_id)
lemma
assumes "alt_list P1 P2 (l1 @ a # a' # l2)" "\<forall>x\<in> {a, a'}. P1 x = (\<not> P2 x)"
shows alt_list_append_1'': "P1 a \<Longrightarrow> P2 a'"
and alt_list_append_1''': "P1 a' \<Longrightarrow> P2 a"
and alt_list_append_1'''': "P2 a' \<Longrightarrow> P1 a"
and alt_list_append_1''''': "P2 a \<Longrightarrow> P1 a'"
proof-
have "alt_list P1 P2 ((l1 @ [a, a']) @ l2)" by (simp add: assms(1))
hence list_pref: "alt_list P1 P2 (l1 @ [a, a'])" using alt_list_append_1 by blast
{ assume "P1 a" thus "P2 a'" using list_pref alt_list_append_1 alt_list_step assms(2)
by (metis insert_iff)
}
{ assume "P2 a" thus "P1 a'" using list_pref alt_list_append_1 alt_list_step assms(2)
by (metis insert_iff)
}
{ assume "P1 a'" thus "P2 a" using \<open>P1 a \<Longrightarrow> P2 a'\<close> assms(2) by blast
}
{ assume "P2 a'" thus "P1 a" using \<open>P2 a \<Longrightarrow> P1 a'\<close> assms(2) by blast
}
qed
lemma alt_list_rev_even:
assumes "alt_list P1 P2 l" "even (length l)"
shows "alt_list P2 P1 (rev l)"
using assms
proof(induction rule: induct_alt_list012)
case (sucsuc x y zs)
hence "alt_list P2 P1 (rev zs)" by simp
moreover have "alt_list P2 P1 [y, x]"
by (simp add: alt_list_empty alt_list_step sucsuc.hyps(1) sucsuc.hyps(2))