(* ========================================================================== *)
(* FLYSPECK - BOOK FORMALIZATION                                              *)
(*                                                                            *)
(* Lemma: PPHEUFG                                                             *)
(* Chapter: Tame Hypermap                                                     *)
(* Authors: Trieu Thi Diep, Alexey Solovyev                                   *)
(* Date: 2010-02-26                                                           *)
(* ========================================================================== *)



module type Tame_opposite_type = sig

end;;

flyspeck_needs "hypermap/hypermap.hl";;
flyspeck_needs "tame/tame_defs.hl";;

module Tame_opposite  = struct


open Hypermap;;
open Tame_defs;;


(* LEMMA: general *)
let tuple_opposite_hypermap = 
prove (`!(H:(A)hypermap). tuple_hypermap (opposite_hypermap H) = ((dart H),face_map H o node_map H , inverse(node_map H),inverse(face_map H))`,
GEN_TAC THEN REWRITE_TAC[opposite_hypermap] THEN REWRITE_TAC[GSYM hypermap_tybij] THEN MP_TAC (SPEC `H:(A)hypermap` hypermap_lemma) THEN STRIP_TAC THEN ASM_SIMP_TAC[PERMUTES_INVERSE; PERMUTES_COMPOSE] THEN REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN MP_TAC (ISPECL [`(node_map H):A->A`; `(dart H):A->bool`] PERMUTES_INVERSES_o) THEN MP_TAC (ISPECL [`(face_map H):A->A`; `(dart H):A->bool`] PERMUTES_INVERSES_o) THEN ASM_SIMP_TAC[FUN_EQ_THM; o_THM; I_THM]);;
(* LEMMA: plain (tame_1a) *)
let opposite_hypermap_plain = 
prove ( `!(H:(A)hypermap). plain_hypermap H ==> plain_hypermap (opposite_hypermap H)`,
GEN_TAC THEN REWRITE_TAC[plain_hypermap] THEN DISCH_TAC THEN REWRITE_TAC[edge_map; tuple_opposite_hypermap] THEN SUBGOAL_THEN `(face_map (H:(A)hypermap) o node_map H) o face_map H o node_map H = (face_map H) o ((node_map H) o (face_map H) o (edge_map H)) o (edge_map H) o (node_map H)` MP_TAC THENL [ POP_ASSUM MP_TAC THEN SIMP_TAC[FUN_EQ_THM; o_THM; I_THM]; ALL_TAC ] THEN DISCH_THEN (fun th -> REWRITE_TAC[th]) THEN REWRITE_TAC[hypermap_cyclic; I_O_ID]);;
(* LEMMA: general *)
let opposite_components = 
prove(`!(H:(A)hypermap) x. dart (opposite_hypermap H) = dart H /\ node (opposite_hypermap H) x = node H x /\ face (opposite_hypermap H) x = face H x`,
REPEAT GEN_TAC THEN REWRITE_TAC[dart; tuple_opposite_hypermap] THEN CONJ_TAC THENL [ REWRITE_TAC[node; node_map; tuple_opposite_hypermap] THEN REWRITE_TAC[GSYM node_map]; REWRITE_TAC[face; face_map; tuple_opposite_hypermap] THEN REWRITE_TAC[GSYM face_map] ] THEN MATCH_MP_TAC lemma_card_inverse_map_eq THEN EXISTS_TAC `(dart H):A->bool` THEN REWRITE_TAC[hypermap_lemma]);;
(* LEMMA: simple (tame_2b) *)
let opposite_hypermap_simple = 
prove ( `!(H:(A)hypermap). simple_hypermap H ==> simple_hypermap (opposite_hypermap H)`,
GEN_TAC THEN REWRITE_TAC[simple_hypermap; opposite_components] THEN REWRITE_TAC[dart; tuple_opposite_hypermap]);;
(* LEMMA: general *)
let hypermap_eq_lemma = 
prove(`!(H:(A)hypermap). tuple_hypermap H = dart H,edge_map H,node_map H,face_map H`,
GEN_TAC THEN MP_TAC (ISPEC `tuple_hypermap (H:(A)hypermap)` PAIR_SURJECTIVE) THEN STRIP_TAC THEN MP_TAC (ISPEC `y:(A->A)#(A->A)#(A->A)` PAIR_SURJECTIVE) THEN STRIP_TAC THEN MP_TAC (ISPEC `y':(A->A)#(A->A)` PAIR_SURJECTIVE) THEN STRIP_TAC THEN ASM_REWRITE_TAC[PAIR_EQ] THEN ASM_REWRITE_TAC[dart; edge_map; node_map; face_map]);;
(* LEMMA: general *)
let opposite_opposite_hypermap_eq_hypermap = 
prove(`!(H:(A)hypermap). opposite_hypermap (opposite_hypermap H) = H`,
ONCE_REWRITE_TAC[GSYM hypermap_tybij] THEN GEN_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[tuple_opposite_hypermap; hypermap_eq_lemma; PAIR_EQ] THEN REWRITE_TAC[dart; face_map; node_map; tuple_opposite_hypermap] THEN REWRITE_TAC[GSYM dart; GSYM face_map; GSYM node_map] THEN REWRITE_TAC[GSYM inverse2_hypermap_maps] THEN CONJ_TAC THEN MATCH_MP_TAC (GEN_ALL PERMUTES_INVERSE_INVERSE) THEN EXISTS_TAC `dart (H:(A)hypermap)` THEN REWRITE_TAC[hypermap_lemma]);;
(* LEMMA: aux *)
let truncated_path_lemma = 
prove(`!(H:(A)hypermap) p q n. is_path H p n /\ (!i. i <= n ==> q i = p i) ==> is_path H q n`,
REPLICATE_TAC 3 GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[is_path] THEN STRIP_TAC THEN FIRST_X_ASSUM (MP_TAC o check (is_imp o concl)) THEN ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ GEN_TAC THEN ASM_SIMP_TAC[ARITH_RULE `i <= n ==> i <= SUC n`]; ALL_TAC ] THEN FIRST_ASSUM (MP_TAC o SPEC `n:num`) THEN FIRST_ASSUM (MP_TAC o SPEC `SUC n`) THEN REWRITE_TAC[LE_REFL; ARITH_RULE `n <= SUC n`] THEN ASM_SIMP_TAC[]);;
(* LEMMA: general *)
let opposite_path = 
prove(`!(H:(A)hypermap) p n. is_path H p n ==> ?q m. is_path (opposite_hypermap H) q m /\ q 0 = p 0 /\ q m = p n`,
GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[is_path] THENL [ MAP_EVERY EXISTS_TAC [`p:num->A`; `0`] THEN REWRITE_TAC[is_path]; ALL_TAC ] THEN STRIP_TAC THEN FIRST_X_ASSUM (MP_TAC o check (is_imp o concl)) THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THEN FIRST_X_ASSUM (MP_TAC o check (fun th -> rator (rator (concl th)) = `go_one_step (H:(A)hypermap)`)) THEN REWRITE_TAC[go_one_step] THEN STRIP_TAC THENL [ EXISTS_TAC `(\i:num. if i <= m then (q:num->A) i else (if i = m + 1 then inverse (node_map H) (q m) else edge_map H ((p:num->A) n)))` THEN EXISTS_TAC `SUC(SUC m)` THEN BETA_TAC THEN ASM_SIMP_TAC[LE_0; ARITH_RULE `~(SUC (SUC m) <= m)`; ARITH_RULE `~(SUC(SUC m) = m + 1)`] THEN REWRITE_TAC[is_path] THEN REPEAT STRIP_TAC THENL [ MATCH_MP_TAC truncated_path_lemma THEN EXISTS_TAC `q:num->A` THEN ASM_SIMP_TAC[]; ASM_REWRITE_TAC[LE_REFL; ARITH_RULE `~(m = m + 1)`; ARITH_RULE `~(SUC m <= m)`; ARITH_RULE `SUC m = m + 1`] THEN REWRITE_TAC[go_one_step] THEN DISJ2_TAC THEN DISJ1_TAC THEN GEN_REWRITE_TAC (RAND_CONV o DEPTH_CONV) [node_map] THEN REWRITE_TAC[tuple_opposite_hypermap]; ASM_REWRITE_TAC[ARITH_RULE `~(SUC m <= m) /\ ~(SUC (SUC m) <= m) /\ ~(SUC (SUC m) = m + 1) /\ SUC m = m + 1`] THEN REWRITE_TAC[go_one_step] THEN DISJ2_TAC THEN DISJ2_TAC THEN REWRITE_TAC[face_map] THEN REWRITE_TAC[tuple_opposite_hypermap] THEN MP_TAC (SPEC `H:(A)hypermap` inverse2_hypermap_maps) THEN SIMP_TAC[o_THM; FUN_EQ_THM]; ]; EXISTS_TAC `(\i:num. if i <= m then (q:num->A) i else (if i = m + 1 then ((face_map H) o (node_map H)) (q m) else node_map H ((p:num->A) n)))` THEN EXISTS_TAC `SUC(SUC m)` THEN BETA_TAC THEN ASM_SIMP_TAC[LE_0; ARITH_RULE `~(SUC (SUC m) <= m)`; ARITH_RULE `~(SUC(SUC m) = m + 1)`] THEN REWRITE_TAC[is_path] THEN REPEAT STRIP_TAC THENL [ MATCH_MP_TAC truncated_path_lemma THEN EXISTS_TAC `q:num->A` THEN ASM_SIMP_TAC[]; ASM_REWRITE_TAC[LE_REFL; ARITH_RULE `~(m = m + 1)`; ARITH_RULE `~(SUC m <= m)`; ARITH_RULE `SUC m = m + 1`] THEN REWRITE_TAC[go_one_step] THEN DISJ1_TAC THEN GEN_REWRITE_TAC (RAND_CONV o DEPTH_CONV) [edge_map] THEN REWRITE_TAC[tuple_opposite_hypermap]; ASM_REWRITE_TAC[ARITH_RULE `~(SUC m <= m) /\ ~(SUC (SUC m) <= m) /\ ~(SUC (SUC m) = m + 1) /\ SUC m = m + 1`] THEN REWRITE_TAC[go_one_step] THEN DISJ2_TAC THEN DISJ2_TAC THEN REWRITE_TAC[face_map] THEN REWRITE_TAC[tuple_opposite_hypermap] THEN REWRITE_TAC[GSYM face_map] THEN REWRITE_TAC[o_THM] THEN MP_TAC (ISPECL [`face_map (H:(A)hypermap)`; `dart (H:(A)hypermap)`] PERMUTES_INVERSES_o) THEN REWRITE_TAC[hypermap_lemma; FUN_EQ_THM; o_THM; I_THM] THEN SIMP_TAC[]; ]; EXISTS_TAC `(\i:num. if i <= m then (q:num->A) i else (if i = m + 1 then inverse (node_map H) (q m) else face_map H ((p:num->A) n)))` THEN EXISTS_TAC `SUC(SUC m)` THEN BETA_TAC THEN ASM_SIMP_TAC[LE_0; ARITH_RULE `~(SUC (SUC m) <= m)`; ARITH_RULE `~(SUC(SUC m) = m + 1)`] THEN REWRITE_TAC[is_path] THEN REPEAT STRIP_TAC THENL [ MATCH_MP_TAC truncated_path_lemma THEN EXISTS_TAC `q:num->A` THEN ASM_SIMP_TAC[]; ASM_REWRITE_TAC[LE_REFL; ARITH_RULE `~(m = m + 1)`; ARITH_RULE `~(SUC m <= m)`; ARITH_RULE `SUC m = m + 1`] THEN REWRITE_TAC[go_one_step] THEN DISJ2_TAC THEN DISJ1_TAC THEN GEN_REWRITE_TAC (RAND_CONV o DEPTH_CONV) [node_map] THEN REWRITE_TAC[tuple_opposite_hypermap]; ASM_REWRITE_TAC[ARITH_RULE `~(SUC m <= m) /\ ~(SUC (SUC m) <= m) /\ ~(SUC (SUC m) = m + 1) /\ SUC m = m + 1`] THEN REWRITE_TAC[go_one_step] THEN DISJ1_TAC THEN REWRITE_TAC[edge_map] THEN REWRITE_TAC[tuple_opposite_hypermap] THEN MP_TAC (ISPECL [`node_map (H:(A)hypermap)`; `dart (H:(A)hypermap)`] PERMUTES_INVERSES_o) THEN REWRITE_TAC[hypermap_lemma; FUN_EQ_THM; o_THM; I_THM] THEN SIMP_TAC[] ] ]);;
(* LEMMA: general *)
let opposite_path_alt = 
prove(`!(H:(A)hypermap) q m. is_path (opposite_hypermap H) q m ==> (?p n. is_path H p n /\ p 0 = q 0 /\ p n = q m)`,
REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM opposite_opposite_hypermap_eq_hypermap] THEN MATCH_MP_TAC opposite_path THEN ASM_REWRITE_TAC[]);;
(* LEMMA: general *)
let opposite_sets_of_components = 
prove(`!H:(A)hypermap. node_set (opposite_hypermap H) = node_set H /\ face_set (opposite_hypermap H) = face_set H /\ set_of_components (opposite_hypermap H) = set_of_components H`,
REPEAT GEN_TAC THEN REWRITE_TAC[node_set; face_set; set_of_orbits] THEN REWRITE_TAC[GSYM node; GSYM face; opposite_components] THEN REWRITE_TAC[dart; tuple_opposite_hypermap] THEN SUBGOAL_THEN `!x y:A. (?(p:num->A) n. p 0 = x /\ p n = y /\ is_path H p n) <=> (?(q:num->A) m. q 0 = x /\ q m = y /\ is_path (opposite_hypermap H) q m)` ASSUME_TAC THENL [ REPEAT GEN_TAC THEN EQ_TAC THEN STRIP_TAC THENL [ ONCE_REWRITE_TAC[TAUT `A /\ B /\ C <=> C /\ A /\ B`] THEN REPLICATE_TAC 2 (FIRST_X_ASSUM ((fun th -> REWRITE_TAC[SYM th]) o check (is_eq o concl))) THEN MATCH_MP_TAC opposite_path THEN ASM_REWRITE_TAC[]; ONCE_REWRITE_TAC[TAUT `A /\ B /\ C <=> C /\ A /\ B`] THEN REPLICATE_TAC 2 (FIRST_X_ASSUM ((fun th -> REWRITE_TAC[SYM th]) o check (is_eq o concl))) THEN MATCH_MP_TAC opposite_path_alt THEN ASM_REWRITE_TAC[] ]; ALL_TAC ] THEN REWRITE_TAC[set_of_components; set_part_components; dart; tuple_opposite_hypermap] THEN ASM_REWRITE_TAC[GSYM dart; comb_component; is_in_component]);;
(* LEMMA: connected (tame_2a) *)
let opposite_hypermap_connected = 
prove ( `!(H:(A)hypermap).connected_hypermap H ==> connected_hypermap (opposite_hypermap H)`,
(* LEMMA: is_edge_nondegenerate (tame_3) *)
let opposite_nondegenerate = 
prove (`!(H:(A)hypermap). plain_hypermap H /\ is_edge_nondegenerate H ==> is_edge_nondegenerate (opposite_hypermap H)`,
GEN_TAC THEN REWRITE_TAC[plain_hypermap; is_edge_nondegenerate] THEN REPEAT STRIP_TAC THEN POP_ASSUM MP_TAC THEN POP_ASSUM MP_TAC THEN REWRITE_TAC[dart; edge_map; tuple_opposite_hypermap] THEN REWRITE_TAC[GSYM dart] THEN DISCH_TAC THEN FIRST_X_ASSUM (MP_TAC o check (is_forall o concl)) THEN ONCE_REWRITE_TAC[TAUT `(A ==> ~B) <=> (B ==> ~A)`] THEN REWRITE_TAC[NOT_FORALL_THM; TAUT `~(A ==> ~B) <=> A /\ B`] THEN REWRITE_TAC[o_THM] THEN DISCH_TAC THEN EXISTS_TAC `node_map H (x:A)` THEN ASM_SIMP_TAC[lemma_dart_invariant] THEN POP_ASSUM (fun th -> GEN_REWRITE_TAC (LAND_CONV o DEPTH_CONV) [SYM th]) THEN MP_TAC (REWRITE_RULE[FUN_EQ_THM; o_THM; I_THM] hypermap_lemma) THEN SIMP_TAC[]);;
(* LEMMA: is_no_double_joints (tame_5a) *)
let opposite_no_double_joints = 
prove(`!H:(A)hypermap. is_no_double_joints H /\ plain_hypermap H ==> is_no_double_joints (opposite_hypermap H)`,
GEN_TAC THEN REWRITE_TAC[is_no_double_joints; edge_map_convolution] THEN STRIP_TAC THEN REWRITE_TAC[tuple_opposite_hypermap; opposite_components; edge_map] THEN REPEAT STRIP_TAC THEN ABBREV_TAC `z:A = node_map H y` THEN ABBREV_TAC `u:A = node_map H x` THEN SUBGOAL_THEN `z:A = u:A ==> x:A = y` MATCH_MP_TAC THENL [ EXPAND_TAC "z" THEN EXPAND_TAC "u" THEN SIMP_TAC[node_map_injective; EQ_SYM]; ALL_TAC ] THEN MATCH_MP_TAC EQ_SYM THEN FIRST_X_ASSUM MATCH_MP_TAC THEN SUBGOAL_THEN `node H (y:A) = node H x` ASSUME_TAC THENL [ MATCH_MP_TAC EQ_SYM THEN MATCH_MP_TAC lemma_node_identity THEN ASM_REWRITE_TAC[]; ALL_TAC ] THEN REPEAT CONJ_TAC THENL [ EXPAND_TAC "u" THEN ASM_SIMP_TAC[lemma_dart_invariant]; SUBGOAL_THEN `node H (u:A) = node H y` ASSUME_TAC THENL [ MATCH_MP_TAC EQ_SYM THEN MATCH_MP_TAC lemma_node_identity THEN ASM_REWRITE_TAC[] THEN EXPAND_TAC "u" THEN MATCH_MP_TAC lemma_in_node1 THEN REWRITE_TAC[node_refl]; ALL_TAC ] THEN POP_ASSUM (fun th -> REWRITE_TAC[th]) THEN EXPAND_TAC "z" THEN MATCH_MP_TAC lemma_in_node1 THEN REWRITE_TAC[node_refl]; ALL_TAC ] THEN ASM_REWRITE_TAC[o_THM] THEN SUBGOAL_THEN `!v w:A. v IN node H w ==> node_map H v IN node H (node_map H w)` MATCH_MP_TAC THENL [ REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma_in_node1 THEN SUBGOAL_THEN `node H (node_map H (w:A)) = node H w` (fun th -> REWRITE_TAC[th]) THENL [ MATCH_MP_TAC EQ_SYM THEN MATCH_MP_TAC lemma_node_identity THEN MATCH_MP_TAC lemma_in_node1 THEN REWRITE_TAC[node_refl]; ALL_TAC ] THEN ASM_REWRITE_TAC[]; ALL_TAC ] THEN FIRST_X_ASSUM (MP_TAC o check (is_binary "IN" o concl)) THEN REWRITE_TAC[o_THM] THEN EXPAND_TAC "z" THEN EXPAND_TAC "u" THEN SIMP_TAC[]);;
(* LEMMA: general *)
let plain_hypermap_edge = 
prove(`!(H:(A)hypermap) x. plain_hypermap H ==> edge H x = {x, edge_map H x}`,
REPEAT GEN_TAC THEN REWRITE_TAC[plain_hypermap] THEN DISCH_TAC THEN REWRITE_TAC[edge] THEN SPEC_TAC (`x:A`, `x:A`) THEN MATCH_MP_TAC lemma_orbit_convolution_map THEN ASM_REWRITE_TAC[]);;
(* LEMMA: no_loops (tame_4) *)
let opposite_no_loops = 
prove(`!H:(A)hypermap. no_loops H /\ plain_hypermap H ==> no_loops (opposite_hypermap H)`,
GEN_TAC THEN REWRITE_TAC[no_loops] THEN STRIP_TAC THEN FIRST_ASSUM (MP_TAC o (fun th -> MATCH_MP plain_hypermap_edge th)) THEN FIRST_ASSUM (MP_TAC o (fun th -> MATCH_MP opposite_hypermap_plain th)) THEN DISCH_THEN (MP_TAC o (fun th -> MATCH_MP plain_hypermap_edge th)) THEN POP_ASSUM MP_TAC THEN REWRITE_TAC[edge_map_convolution] THEN DISCH_TAC THEN DISCH_THEN (fun th -> REWRITE_TAC[th]) THEN DISCH_TAC THEN REWRITE_TAC[opposite_components; edge_map; tuple_opposite_hypermap; o_THM] THEN REWRITE_TAC[Collect_geom.IN_SET2] THEN REPEAT STRIP_TAC THEN SUBGOAL_THEN `node_map H (x:A) = node_map H y ==> x = y` MATCH_MP_TAC THENL [ REWRITE_TAC[node_map_injective]; ALL_TAC ] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL [ ASM_REWRITE_TAC[o_THM; Collect_geom.IN_SET2]; MATCH_MP_TAC lemma_in_node1 THEN SUBGOAL_THEN `node H (node_map H (y:A)) = node H y` (fun th -> REWRITE_TAC[th]) THENL [ MATCH_MP_TAC EQ_SYM THEN MATCH_MP_TAC lemma_node_identity THEN MATCH_MP_TAC lemma_in_node1 THEN REWRITE_TAC[node_refl]; ALL_TAC ] THEN ASM_REWRITE_TAC[] ]);;
(* LEMMA: aux *)
let edge_CARD_dart = 
prove(`!H:(A)hypermap. plain_hypermap H /\ is_edge_nondegenerate H ==> CARD (dart H) = 2 * number_of_edges H`,
GEN_TAC THEN REWRITE_TAC[plain_hypermap; is_edge_nondegenerate] THEN STRIP_TAC THEN REWRITE_TAC[number_of_edges; edge_set] THEN MATCH_MP_TAC (REWRITE_RULE[number_of_orbits] lemma_card_eq) THEN REWRITE_TAC[hypermap_lemma] THEN REPEAT STRIP_TAC THEN MP_TAC (SPECL [`(dart H):A->bool`; `(edge_map H):A->A`] lemma_orbit_of_size_2) THEN REWRITE_TAC[hypermap_lemma] THEN DISCH_THEN (fun th -> REWRITE_TAC[th]) THEN FIRST_X_ASSUM (MP_TAC o SPEC `x:A`) THEN FIRST_X_ASSUM (MP_TAC o check (is_eq o concl)) THEN ASM_SIMP_TAC[FUN_EQ_THM; o_THM; I_THM]);;
(* LEMMA: aux *)
let edge_CARD = 
prove(`!H:(A)hypermap. plain_hypermap H /\ is_edge_nondegenerate H ==> number_of_edges H = CARD (dart H) DIV 2`,
GEN_TAC THEN DISCH_THEN (ASSUME_TAC o (fun th -> MATCH_MP edge_CARD_dart th)) THEN MATCH_MP_TAC EQ_SYM THEN MATCH_MP_TAC DIV_UNIQ THEN EXISTS_TAC `0` THEN ASM_REWRITE_TAC[] THEN ARITH_TAC);;
(* LEMMA: planar (tame_1b) *)
let opposite_planar = 
prove ( `!(H:(A)hypermap). planar_hypermap H /\ is_edge_nondegenerate H /\ plain_hypermap H ==> planar_hypermap (opposite_hypermap H)`,
GEN_TAC THEN REWRITE_TAC[planar_hypermap] THEN REWRITE_TAC[number_of_nodes; number_of_faces; number_of_components] THEN REWRITE_TAC[opposite_sets_of_components] THEN DISCH_THEN (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN MP_TAC (SPEC `opposite_hypermap (H:(A)hypermap)` edge_CARD) THEN ASM_SIMP_TAC[opposite_hypermap_plain; opposite_nondegenerate] THEN MP_TAC (SPEC `H:(A)hypermap` edge_CARD) THEN ASM_SIMP_TAC[dart; tuple_opposite_hypermap]);;
(* LEMMA: tame_8 *)
let CARD_faces1 = 
prove (`! (H:(A)hypermap). tame_8 H ==> tame_8 (opposite_hypermap H) `,
(* LEMMA: tame_9a *)
let CARD_in_face = 
prove ( `!(H:(A)hypermap). tame_9a H ==> tame_9a (opposite_hypermap H) `,
REWRITE_TAC[tame_9a; opposite_components] THEN SIMP_TAC[dart; tuple_opposite_hypermap]);;
(* LEMMA: tame_10 *)
let CARD_nodes = 
prove (`!H:(A)hypermap. tame_10 H ==> tame_10 (opposite_hypermap H)`,
(* LEMMA: tame_11a /\ tame_11b *)
let CARD_in_node = 
prove ( `!(H:(A)hypermap). tame_11a H /\ tame_11b H ==> tame_11a (opposite_hypermap H) /\ tame_11b (opposite_hypermap H)`,
REWRITE_TAC[tame_11a; tame_11b; opposite_components] THEN SIMP_TAC[dart; tuple_opposite_hypermap]);;
(* LEMMA: general *)
let the_SAME_orbit_triangles = 
prove (`!(H:(A)hypermap) x. set_of_triangles_meeting_node H x = set_of_triangles_meeting_node (opposite_hypermap H) x`,
REPEAT GEN_TAC THEN REWRITE_TAC[set_of_triangles_meeting_node] THEN REWRITE_TAC[opposite_components] THEN REWRITE_TAC[dart; tuple_opposite_hypermap]);;
(* LEMMA: general *)
let the_SAME_orbit_quadrilaterals = 
prove (`!(H:(A)hypermap) x. set_of_quadrilaterals_meeting_node H x = set_of_quadrilaterals_meeting_node (opposite_hypermap H) x`,
REPEAT GEN_TAC THEN REWRITE_TAC[set_of_quadrilaterals_meeting_node] THEN REWRITE_TAC[opposite_components; dart; tuple_opposite_hypermap]);;
(* LEMMA: general *)
let the_SAME_orbit_exceptional = 
prove (`!(H:(A)hypermap) x. set_of_exceptional_meeting_node H x = set_of_exceptional_meeting_node (opposite_hypermap H) x`,
REPEAT GEN_TAC THEN REWRITE_TAC[set_of_exceptional_meeting_node] THEN REWRITE_TAC[opposite_components; dart; tuple_opposite_hypermap]);;
(* LEMMA: general *)
let the_SAME_orbit_face = 
prove (`!(H:(A)hypermap) x. set_of_face_meeting_node H x = set_of_face_meeting_node (opposite_hypermap H) x`,
REPEAT GEN_TAC THEN REWRITE_TAC[set_of_face_meeting_node] THEN REWRITE_TAC[opposite_components; dart; tuple_opposite_hypermap]);;
(* LEMMA: general *)
let the_SAME_type = 
prove(`!H (x:A). type_of_node H x = type_of_node (opposite_hypermap H) x`,
REWRITE_TAC[type_of_node; PAIR_EQ] THEN REWRITE_TAC[GSYM the_SAME_orbit_triangles] THEN REWRITE_TAC[GSYM the_SAME_orbit_quadrilaterals] THEN REWRITE_TAC[GSYM the_SAME_orbit_exceptional]);;
(* LEMMA: tame_12o *)
let opposite_tame_12o = 
prove(`!H:(A)hypermap. tame_12o H ==> tame_12o (opposite_hypermap H)`,
REWRITE_TAC[tame_12o] THEN REWRITE_TAC[node_type_exceptional_face; exceptional_face] THEN REWRITE_TAC[node_exceptional_face] THEN SIMP_TAC[opposite_components; GSYM the_SAME_type] THEN SIMP_TAC[exceptional_face; opposite_components]);;
(* LEMMA: tame_13a *)
let opposite_tame_13a = 
prove(`!H:(A)hypermap. tame_13a H ==> tame_13a (opposite_hypermap H)`,
GEN_TAC THEN REWRITE_TAC[tame_13a] THEN REWRITE_TAC[admissible_weight; adm_1; adm_2; adm_3] THEN REWRITE_TAC[GSYM the_SAME_type] THEN REWRITE_TAC[GSYM the_SAME_orbit_exceptional] THEN REWRITE_TAC[GSYM the_SAME_orbit_quadrilaterals] THEN REWRITE_TAC[GSYM the_SAME_orbit_triangles] THEN REWRITE_TAC[GSYM the_SAME_orbit_face] THEN REWRITE_TAC[opposite_components] THEN STRIP_TAC THEN EXISTS_TAC `w:(A->bool)->real` THEN ASM_REWRITE_TAC[] THEN POP_ASSUM MP_TAC THEN REWRITE_TAC[total_weight] THEN REWRITE_TAC[opposite_sets_of_components]);;
(* LEMMA: tame H ==> tame (opposite H) *)
let tame_opposite_hypermap = 
prove ( `!(H:(A)hypermap). tame_hypermap H ==> tame_hypermap (opposite_hypermap H)`,
(* LEMMA: the main result *)
let PPHEUFG = 
prove (`!(H:(A)hypermap). tame_hypermap H <=> tame_hypermap (opposite_hypermap H)`,
GEN_TAC THEN EQ_TAC THENL [ REWRITE_TAC[tame_opposite_hypermap]; DISCH_TAC THEN ONCE_REWRITE_TAC[GSYM opposite_opposite_hypermap_eq_hypermap] THEN MATCH_MP_TAC tame_opposite_hypermap THEN ASM_REWRITE_TAC[] ]);;
end;;