(** Some properties of [is_mill] and [dests_disjoint]. *)

Definition dests_disjoint (m1 m2: moves) : Prop :=
  list_disjoint (dests m1) (dests m2).

(* Specifications: *)
Lemma dests_disjoint_sym: forall m1 m2, dests_disjoint m1 m2 <-> dests_disjoint m2 m1.
Lemma dests_disjoint_cons_left: forall m1 s d m2, dests_disjoint ((s, d) :: m1) m2 <-> dests_disjoint m1 m2 /\ ~In d (dests m2).
Lemma dests_disjoint_cons_right: forall m1 s d m2, dests_disjoint m1 ((s, d) :: m2) <-> dests_disjoint m1 m2 /\ ~In d (dests m1).
Lemma dests_disjoint_append_left: forall m1 m2 m3, dests_disjoint (m1 ++ m2) m3 <-> dests_disjoint m1 m3 /\ dests_disjoint m2 m3.
Lemma dests_disjoint_append_right: forall m1 m2 m3, dests_disjoint m1 (m2 ++ m3) <-> dests_disjoint m1 m2 /\ dests_disjoint m1 m3.
Lemma is_mill_cons: forall s d m, is_mill ((s, d) :: m) <-> is_mill m /\ ~In d (dests m).
Lemma is_mill_append: forall m1 m2, is_mill (m1 ++ m2) <-> is_mill m1 /\ is_mill m2 /\ dests_disjoint m1 m2.
Lemma move_no_temp_append: forall m1 m2, move_no_temp m1 -> move_no_temp m2 -> move_no_temp (m1 ++ m2).
Lemma move_no_temp_rev: forall m, move_no_temp (List.rev m) -> move_no_temp m.
Lemma temp_last_change_last_source: forall s d s' sigma, temp_last (sigma ++ (s, d) :: nil) -> temp_last (sigma ++ (s', d) :: nil).
Lemma temp_last_push: forall s1 d1 s2 d2 sigma, temp_last ((s2, d2) :: sigma) -> is_not_temp s1 -> is_not_temp d1 -> temp_last ((s1, d1) :: (s2, d2) :: sigma).
Lemma temp_last_pop: forall s1 d1 sigma s2 d2, temp_last ((s1, d1) :: sigma ++ (s2, d2) :: nil) -> temp_last (sigma ++ (s2, d2) :: nil).
Lemma is_path_pop: forall s d m, is_path ((s, d) :: m) -> is_path m.
Lemma is_path_change_last_source: forall s s' d sigma, is_path (sigma ++ (s, d) :: nil) -> is_path (sigma ++ (s', d) :: nil).
Lemma path_sources_dests: forall s0 d0 sigma, is_path (sigma ++ (s0, d0) :: nil) -> List.incl (srcs (sigma ++ (s0, d0) :: nil)) (s0 :: dests (sigma ++ (s0, d0) :: nil)).
Lemma no_read_path: forall d1 sigma s0 d0, d1 <> s0 -> is_path (sigma ++ (s0, d0) :: nil) -> ~In d1 (dests (sigma ++ (s0, d0) :: nil)) -> no_read (sigma ++ (s0, d0) :: nil) d1.
Lemma notin_dests_cons: forall x s d m, ~In x (dests ((s, d) :: m)) <-> x <> d /\ ~In x (dests m).
Lemma notin_dests_append: forall d m1 m2, ~In d (dests (m1 ++ m2)) <-> ~In d (dests m1) /\ ~In d (dests m2).
Lemma transition_preserves_wf: forall st st', transition st st' -> state_wf st -> state_wf st'.
Lemma transitions_preserve_wf: forall st st', transitions st st' -> state_wf st -> state_wf st'.
Lemma dests_disjoint_sym: forall m1 m2, dests_disjoint m1 m2 <-> dests_disjoint m2 m1.
Lemma dests_disjoint_cons_left: forall m1 s d m2, dests_disjoint ((s, d) :: m1) m2 <-> dests_disjoint m1 m2 /\ ~In d (dests m2).
Lemma dests_disjoint_cons_right: forall m1 s d m2, dests_disjoint m1 ((s, d) :: m2) <-> dests_disjoint m1 m2 /\ ~In d (dests m1).
Lemma dests_disjoint_append_left: forall m1 m2 m3, dests_disjoint (m1 ++ m2) m3 <-> dests_disjoint m1 m3 /\ dests_disjoint m2 m3.
Lemma dests_disjoint_append_right: forall m1 m2 m3, dests_disjoint m1 (m2 ++ m3) <-> dests_disjoint m1 m2 /\ dests_disjoint m1 m3.
Lemma is_mill_cons: forall s d m, is_mill ((s, d) :: m) <-> is_mill m /\ ~In d (dests m).
Lemma is_mill_append: forall m1 m2, is_mill (m1 ++ m2) <-> is_mill m1 /\ is_mill m2 /\ dests_disjoint m1 m2.
Lemma move_no_temp_append: forall m1 m2, move_no_temp m1 -> move_no_temp m2 -> move_no_temp (m1 ++ m2).
Lemma move_no_temp_rev: forall m, move_no_temp (List.rev m) -> move_no_temp m.
Lemma temp_last_change_last_source: forall s d s' sigma, temp_last (sigma ++ (s, d) :: nil) -> temp_last (sigma ++ (s', d) :: nil).
Lemma temp_last_push: forall s1 d1 s2 d2 sigma, temp_last ((s2, d2) :: sigma) -> is_not_temp s1 -> is_not_temp d1 -> temp_last ((s1, d1) :: (s2, d2) :: sigma).
Lemma temp_last_pop: forall s1 d1 sigma s2 d2, temp_last ((s1, d1) :: sigma ++ (s2, d2) :: nil) -> temp_last (sigma ++ (s2, d2) :: nil).
Lemma is_path_pop: forall s d m, is_path ((s, d) :: m) -> is_path m.
Lemma is_path_change_last_source: forall s s' d sigma, is_path (sigma ++ (s, d) :: nil) -> is_path (sigma ++ (s', d) :: nil).
Lemma path_sources_dests: forall s0 d0 sigma, is_path (sigma ++ (s0, d0) :: nil) -> List.incl (srcs (sigma ++ (s0, d0) :: nil)) (s0 :: dests (sigma ++ (s0, d0) :: nil)).
Lemma no_read_path: forall d1 sigma s0 d0, d1 <> s0 -> is_path (sigma ++ (s0, d0) :: nil) -> ~In d1 (dests (sigma ++ (s0, d0) :: nil)) -> no_read (sigma ++ (s0, d0) :: nil) d1.
Lemma notin_dests_cons: forall x s d m, ~In x (dests ((s, d) :: m)) <-> x <> d /\ ~In x (dests m).
Lemma notin_dests_append: forall d m1 m2, ~In d (dests (m1 ++ m2)) <-> ~In d (dests m1) /\ ~In d (dests m2).
Lemma transition_preserves_wf: forall st st', transition st st' -> state_wf st -> state_wf st'.
Lemma transitions_preserve_wf: forall st st', transitions st st' -> state_wf st -> state_wf st'.