Module T.Amida
Require Import Sumbool Arith List FinFun.Require Import Eq Common Fin Pos.
Import ListNotations.
Parameter height_ : nat.
Definition Pos := Pos.t height_.
Definition Bypath := (Pos * Pos)%type.
Definition vmax_ (b: list Bypath) kuji : nat :=
let '(ps1, ps2) := List.split b in
List.length (List.filter_dec (fun pos => fst pos =? kuji) (ps1 ++ ps2)).
Inductive PosIn (pos: Pos) : list Bypath -> Prop :=
| InLeft : forall other bs, PosIn pos ((pos, other) :: bs)
| InRight : forall other bs, PosIn pos ((other, pos) :: bs)
| InCons : forall bs p1 p2, PosIn pos bs -> PosIn pos ((p1, p2) :: bs).
Lemma PosIn_In pos body:
PosIn pos body -> exists pos', In (pos, pos') body \/ In (pos', pos) body.
Proof.
induction 1; try exists other; [left|right|].
- now constructor.
- now constructor.
- destruct IHPosIn as [pos' [left | right]]; exists pos'.
+ now left; right.
+ now right; right.
Qed.
- now constructor.
- now constructor.
- destruct IHPosIn as [pos' [left | right]]; exists pos'.
+ now left; right.
+ now right; right.
Qed.
Definition AmidaP (bs: list Bypath): Prop :=
(let '(ps1, ps2) := split bs in NoDup (ps1 ++ ps2))
/\ forall kuji i, Fin.lt i (vpos_of_nat height_ (vmax_ bs kuji)) ->
PosIn (kuji, i) bs.
Definition Amida := {bs : list Bypath | AmidaP bs}.
Parameter A B C: Kuji.
Parameter f0 f1 f2 f3 : vpos height_.
Definition example : Amida.
exists [ ((A,f0), (B,f1)); ((B,f0), (B,f3)); ((B,f2), (C,f0))].
Section Amida.
Variable amida : Amida.
Notation body := (proj1_sig amida).
Definition vmax (kuji: Kuji): vpos height_ := vpos_of_nat _ (vmax_ body kuji).
Lemma in_split {A:Type} pairs (x y:A) xs ys:
In (x, y) pairs -> split pairs = (xs, ys) -> In x xs /\ In y ys.
Proof.
intros inp splitp.
pose (in_split_l pairs (x, y) inp).
pose (in_split_r pairs (x, y) inp).
rewrite splitp in *. now split.
Qed.
pose (in_split_l pairs (x, y) inp).
pose (in_split_r pairs (x, y) inp).
rewrite splitp in *. now split.
Qed.
Lemma amida_body_notIn_r p1 p2 l:
In (p1, p2) body -> ~ In (l, p1) body.
Proof.
destruct amida as [body [nodup ex]]. simpl.
case_eq (split body). intros ps1 ps2 splitb. rewrite splitb in nodup.
intros in1 in2.
destruct (in_split _ _ _ ps1 ps2 in1 splitb) as [inp1 inp2].
destruct (in_split _ _ _ ps1 ps2 in2 splitb) as [inl inp1'].
now destruct (List.NoDup_app _ _ nodup inp1 inp1') .
Qed.
case_eq (split body). intros ps1 ps2 splitb. rewrite splitb in nodup.
intros in1 in2.
destruct (in_split _ _ _ ps1 ps2 in1 splitb) as [inp1 inp2].
destruct (in_split _ _ _ ps1 ps2 in2 splitb) as [inl inp1'].
now destruct (List.NoDup_app _ _ nodup inp1 inp1') .
Qed.
Lemma amida_body_notIn_l p1 p2 r:
In (p1, p2) body -> ~ In (p2, r) body.
Proof.
destruct amida as [body [nodup ex]]. simpl.
case_eq (split body). intros ps1 ps2 splitb. rewrite splitb in nodup.
intros in1 in2.
destruct (in_split _ _ _ ps1 ps2 in1 splitb) as [inp1 inp2].
destruct (in_split _ _ _ ps1 ps2 in2 splitb) as [inp2' inr].
now destruct (List.NoDup_app _ _ nodup inp2' inp2) .
Qed.
case_eq (split body). intros ps1 ps2 splitb. rewrite splitb in nodup.
intros in1 in2.
destruct (in_split _ _ _ ps1 ps2 in1 splitb) as [inp1 inp2].
destruct (in_split _ _ _ ps1 ps2 in2 splitb) as [inp2' inr].
now destruct (List.NoDup_app _ _ nodup inp2' inp2) .
Qed.
Lemma amida_body_inj_r p1 p2 p2':
In (p1, p2) body -> In (p1, p2') body -> p2 = p2'.
Proof.
intros inp inp'.
destruct (In_nth _ _ (Pos.err _, Pos.err _) inp) as [i [lti nthi]].
destruct (In_nth _ _ (Pos.err _, Pos.err _) inp') as [j [ltj nthj]].
destruct amida as [body [nodup ex]]. simpl in *.
rewrite split_nth in nthi. injection nthi.
rewrite split_nth in nthj. injection nthj.
intros nthj_p2' nthj_p1 nthi_p2 nthi_p1.
rewrite <- split_length_l in lti.
rewrite <- split_length_l in ltj.
rewrite <- nthj_p2', <- nthi_p2. f_equal.
case_eq (split body). intros ps1 ps2 splitb. rewrite splitb in *.
destruct (in_split _ _ _ ps1 ps2 inp splitb) as [inp1 inp2].
destruct (in_split _ _ _ ps1 ps2 inp' splitb) as [_ inp2'].
apply NoDup_app_remove_r in nodup.
replace ps1 with (fst (split body)) in nodup; [|now rewrite splitb].
rewrite <- nthj_p1 in nthi_p1.
now apply (NoDup_nth (fst (split body)) (Pos.err _)).
Qed.
destruct (In_nth _ _ (Pos.err _, Pos.err _) inp) as [i [lti nthi]].
destruct (In_nth _ _ (Pos.err _, Pos.err _) inp') as [j [ltj nthj]].
destruct amida as [body [nodup ex]]. simpl in *.
rewrite split_nth in nthi. injection nthi.
rewrite split_nth in nthj. injection nthj.
intros nthj_p2' nthj_p1 nthi_p2 nthi_p1.
rewrite <- split_length_l in lti.
rewrite <- split_length_l in ltj.
rewrite <- nthj_p2', <- nthi_p2. f_equal.
case_eq (split body). intros ps1 ps2 splitb. rewrite splitb in *.
destruct (in_split _ _ _ ps1 ps2 inp splitb) as [inp1 inp2].
destruct (in_split _ _ _ ps1 ps2 inp' splitb) as [_ inp2'].
apply NoDup_app_remove_r in nodup.
replace ps1 with (fst (split body)) in nodup; [|now rewrite splitb].
rewrite <- nthj_p1 in nthi_p1.
now apply (NoDup_nth (fst (split body)) (Pos.err _)).
Qed.
Lemma amida_body_inj_l p1 p2 p1':
In (p1, p2) body -> In (p1', p2) body -> p1 = p1'.
Proof.
intros inp inp'.
destruct (In_nth _ _ (Pos.err _, Pos.err _) inp) as [i [lti nthi]].
destruct (In_nth _ _ (Pos.err _, Pos.err _) inp') as [j [ltj nthj]].
destruct amida as [body [nodup ex]]. simpl in *.
rewrite split_nth in nthi. injection nthi.
rewrite split_nth in nthj. injection nthj.
intros nthj_p2 nthj_p1' nthi_p2 nthi_p1.
rewrite <- split_length_r in lti.
rewrite <- split_length_r in ltj.
rewrite <- nthi_p1, <- nthj_p1'. f_equal.
case_eq (split body). intros ps1 ps2 splitb. rewrite splitb in *.
destruct (in_split _ _ _ ps1 ps2 inp splitb) as [inp1 inp2].
destruct (in_split _ _ _ ps1 ps2 inp' splitb) as [inp1' _].
apply NoDup_app_remove_l in nodup.
replace ps2 with (snd (split body)) in nodup; [|now rewrite splitb].
rewrite <- nthj_p2 in nthi_p2.
now apply (NoDup_nth (snd (split body)) (Pos.err _)).
Qed.
destruct (In_nth _ _ (Pos.err _, Pos.err _) inp) as [i [lti nthi]].
destruct (In_nth _ _ (Pos.err _, Pos.err _) inp') as [j [ltj nthj]].
destruct amida as [body [nodup ex]]. simpl in *.
rewrite split_nth in nthi. injection nthi.
rewrite split_nth in nthj. injection nthj.
intros nthj_p2 nthj_p1' nthi_p2 nthi_p1.
rewrite <- split_length_r in lti.
rewrite <- split_length_r in ltj.
rewrite <- nthi_p1, <- nthj_p1'. f_equal.
case_eq (split body). intros ps1 ps2 splitb. rewrite splitb in *.
destruct (in_split _ _ _ ps1 ps2 inp splitb) as [inp1 inp2].
destruct (in_split _ _ _ ps1 ps2 inp' splitb) as [inp1' _].
apply NoDup_app_remove_l in nodup.
replace ps2 with (snd (split body)) in nodup; [|now rewrite splitb].
rewrite <- nthj_p2 in nthi_p2.
now apply (NoDup_nth (snd (split body)) (Pos.err _)).
Qed.
Lemma amida_body_vmax kuji i:
Fin.lt i (vmax kuji) -> PosIn (kuji, i) body.
Definition init (kuji : Kuji) : Pos := (kuji, F1).
Definition hnext_ (pos: Pos): option Pos :=
List.find_map (fun '(l, r) =>
if l =? pos then Some r
else if r =? pos then Some l
else None) (proj1_sig amida).
Definition hnext pos := Option.value (Pos.err _) (hnext_ pos).
Lemma hnext_In_inv p p':
hnext_ p = Some p' -> In (p, p') body \/ In (p', p) body.
Proof.
intros hnextp.
destruct (List.find_map_some _ _ hnextp) as [[x y] [inx Hxy]].
destruct (x =? p).
- injection Hxy as ey. subst. now left.
- destruct (y =? p); [|discriminate].
injection Hxy as ex. subst. now right.
Qed.
destruct (List.find_map_some _ _ hnextp) as [[x y] [inx Hxy]].
destruct (x =? p).
- injection Hxy as ey. subst. now left.
- destruct (y =? p); [|discriminate].
injection Hxy as ex. subst. now right.
Qed.
Lemma hnext_PosIn (pos: Pos) :
PosIn pos body -> hnext_ pos <> None.
Proof.
intros posIn hnextp. destruct (PosIn_In _ _ posIn) as [pos' [l|r]].
-
eapply List.find_map_none in hnextp; [|apply l]. simpl in hnextp.
now destruct (prod_cmp Kuji_eqDec (vpos_eqDec height_) pos pos).
-
eapply List.find_map_none in hnextp; [|apply r]. simpl in hnextp.
destruct (prod_cmp Kuji_eqDec (vpos_eqDec height_) pos' pos); [now auto|].
now destruct (prod_cmp Kuji_eqDec (vpos_eqDec height_) pos pos).
Qed.
-
eapply List.find_map_none in hnextp; [|apply l]. simpl in hnextp.
now destruct (prod_cmp Kuji_eqDec (vpos_eqDec height_) pos pos).
-
eapply List.find_map_none in hnextp; [|apply r]. simpl in hnextp.
destruct (prod_cmp Kuji_eqDec (vpos_eqDec height_) pos' pos); [now auto|].
now destruct (prod_cmp Kuji_eqDec (vpos_eqDec height_) pos pos).
Qed.
Lemma hnext_inj_aux p' p1 p2:
hnext_ p1 = Some p' ->
hnext_ p2 = Some p' -> p1 = p2.
Proof.
intros hnext1 hnext2.
destruct (hnext_In_inv _ _ hnext1).
- (* In (p1, p') bodyのとき *)
destruct (hnext_In_inv _ _ hnext2).
+ now apply amida_body_inj_l with p'.
+ now destruct (amida_body_notIn_l p1 p' p2 H).
- (* In (p', p1) bodyのとき *)
destruct (hnext_In_inv _ _ hnext2).
+ now destruct (amida_body_notIn_r p' p1 p2 H).
+ now apply amida_body_inj_r with p'.
Qed.
destruct (hnext_In_inv _ _ hnext1).
- (* In (p1, p') bodyのとき *)
destruct (hnext_In_inv _ _ hnext2).
+ now apply amida_body_inj_l with p'.
+ now destruct (amida_body_notIn_l p1 p' p2 H).
- (* In (p', p1) bodyのとき *)
destruct (hnext_In_inv _ _ hnext2).
+ now destruct (amida_body_notIn_r p' p1 p2 H).
+ now apply amida_body_inj_r with p'.
Qed.
Lemma hnext_inj p1 p2:
PosIn p1 body -> PosIn p2 body -> hnext p1 = hnext p2 -> p1 = p2.
Proof.
unfold hnext. intros posIn1 posIn2.
apply hnext_PosIn in posIn1, posIn2.
case_eq (hnext_ p1); [|now auto]. intros p1' p1p1'. simpl.
case_eq (hnext_ p2); [|now auto]. intros p2' p2p2'. simpl.
intros e. subst p2'.
now apply hnext_inj_aux with p1'.
Qed.
apply hnext_PosIn in posIn1, posIn2.
case_eq (hnext_ p1); [|now auto]. intros p1' p1p1'. simpl.
case_eq (hnext_ p2); [|now auto]. intros p2' p2p2'. simpl.
intros e. subst p2'.
now apply hnext_inj_aux with p1'.
Qed.
Definition vnext '(kuji, n) : option Pos :=
if Fin.lt_dec n (vmax kuji) then
Option.map (fun Sn => (kuji, Sn)) (Fin.succ_opt n)
else None.
Axiom height_enough_big: forall kuji,
(Fin.to_nat (vmax kuji)) < height_.
Lemma lt_height kuji i: Fin.lt i (vmax kuji) ->
S (Fin.to_nat i) < S height_.
Proof.
intros lti.
apply Fin.lt_to_nat in lti.
rewrite <- Nat.succ_lt_mono.
now eapply Nat.lt_trans, (height_enough_big kuji).
Qed.
apply Fin.lt_to_nat in lti.
rewrite <- Nat.succ_lt_mono.
now eapply Nat.lt_trans, (height_enough_big kuji).
Qed.
Lemma vnext_inj p' p1 p2:
vnext p1 = Some p' ->
vnext p2 = Some p' -> p1 = p2.
Proof.
destruct p1 as [k1 i], p2 as [k2 j]. destruct p' as [k' x].
unfold vnext. simpl.
destruct (Fin.lt_dec i (vmax k1)) as [lti|nlti]; [|discriminate].
destruct (Fin.lt_dec j (vmax k2)) as [ltj|nltj]; [|discriminate].
destruct (Fin.succ_opt_S i) as [si [succ_i to_nat_Si]];
[ now apply lt_height with k1|].
rewrite succ_i. simpl. injection 1 as ek1 esi. subst.
destruct (Fin.succ_opt_S j) as [sj [succ_j to_nat_Sj]];
[ now apply lt_height with k2|].
rewrite succ_j. simpl. injection 1 as ek2 esj. subst. f_equal.
now apply Fin.succ_opt_inj with x.
Qed.
unfold vnext. simpl.
destruct (Fin.lt_dec i (vmax k1)) as [lti|nlti]; [|discriminate].
destruct (Fin.lt_dec j (vmax k2)) as [ltj|nltj]; [|discriminate].
destruct (Fin.succ_opt_S i) as [si [succ_i to_nat_Si]];
[ now apply lt_height with k1|].
rewrite succ_i. simpl. injection 1 as ek1 esi. subst.
destruct (Fin.succ_opt_S j) as [sj [succ_j to_nat_Sj]];
[ now apply lt_height with k2|].
rewrite succ_j. simpl. injection 1 as ek2 esj. subst. f_equal.
now apply Fin.succ_opt_inj with x.
Qed.
Lemma vnext_not_init k p :
~ vnext p = Some (init k).
Proof.
Definition next pos :=
match hnext_ pos with
| None => None
| Some pos' => vnext pos'
end.
Lemma next_not_init k p :
~ next p = Some (init k).
Proof.
Lemma next_inj pos' pos1 pos2:
next pos1 = Some pos' ->
next pos2 = Some pos' -> pos1 = pos2.
Proof.
unfold next.
case_eq (hnext_ pos1); [|now auto]. intros pos1' hnext1 vnext1.
case_eq (hnext_ pos2); [|now auto]. intros pos2' hnext2 vnext2.
apply hnext_inj_aux with pos1'; [now apply hnext1|].
rewrite hnext2. f_equal. now apply vnext_inj with pos'.
Qed.
case_eq (hnext_ pos1); [|now auto]. intros pos1' hnext1 vnext1.
case_eq (hnext_ pos2); [|now auto]. intros pos2' hnext2 vnext2.
apply hnext_inj_aux with pos1'; [now apply hnext1|].
rewrite hnext2. f_equal. now apply vnext_inj with pos'.
Qed.
Fixpoint run fuel pos : list Pos :=
match fuel with
| O => []
| S p => match next pos with
| None => [pos]
| Some pos' => pos :: run p pos'
end
end.
Lemma PosFinite : Finite Pos.
Proof.
Lemma length_run' fuel: forall pos,
length (run fuel pos) <= fuel.
Proof.
Lemma run_fuel_O pos: run 0 pos = [].
Proof.
now auto. Qed.
Lemma run_cons' fuel tl pos hd : run fuel pos = hd :: tl -> run fuel pos = pos :: tl.
Proof.
Lemma run_cons fuel tl pos hd : run fuel pos = hd :: tl -> pos = hd.
Lemma run_app xs ys fuel pos pos':
run fuel pos = (xs ++ pos' :: ys) ->
run (fuel - length xs) pos' = pos' :: ys.
Proof.
revert fuel pos. induction xs; simpl; intros fuel pos.
- rewrite Nat.sub_0_r.
intro erun.
replace pos' with pos; [now apply run_cons' with pos'|].
now apply (run_cons fuel ys).
- destruct fuel as [|fuel]; [discriminate|].
simpl. destruct (next pos).
+ injection 1 as posa erun. now apply IHxs with p.
+ injection 1 as posa.
now destruct (app_cons_not_nil _ _ _ H).
Qed.
- rewrite Nat.sub_0_r.
intro erun.
replace pos' with pos; [now apply run_cons' with pos'|].
now apply (run_cons fuel ys).
- destruct fuel as [|fuel]; [discriminate|].
simpl. destruct (next pos).
+ injection 1 as posa erun. now apply IHxs with p.
+ injection 1 as posa.
now destruct (app_cons_not_nil _ _ _ H).
Qed.
Lemma run_nth fuel pos0 i pi:
nth_error (run fuel pos0) i = Some pi ->
exists ps, run fuel pos0 = ps ++ run (fuel - length ps) pi /\ length ps = i.
Proof.
revert fuel pos0. induction i; intros fuel pos0.
- simpl. case_eq (run fuel pos0); [discriminate|]. intros p' l.
intros erun. injection 1 as epi. subst.
exists []. simpl. split; [|now auto].
rewrite Nat.sub_0_r.
rewrite <- (run_cons _ _ _ _ erun).
now apply run_cons' in erun.
- destruct fuel as[|fuel]; [discriminate|].
simpl. destruct (next pos0); [|now rewrite nth_error_nil].
intros nthi. destruct (IHi fuel p) as [ps [erun len]]; [assumption|].
exists (pos0 :: ps). simpl. rewrite len. split; [| now auto].
f_equal. now rewrite <- len, <- erun.
Qed.
- simpl. case_eq (run fuel pos0); [discriminate|]. intros p' l.
intros erun. injection 1 as epi. subst.
exists []. simpl. split; [|now auto].
rewrite Nat.sub_0_r.
rewrite <- (run_cons _ _ _ _ erun).
now apply run_cons' in erun.
- destruct fuel as[|fuel]; [discriminate|].
simpl. destruct (next pos0); [|now rewrite nth_error_nil].
intros nthi. destruct (IHi fuel p) as [ps [erun len]]; [assumption|].
exists (pos0 :: ps). simpl. rewrite len. split; [| now auto].
f_equal. now rewrite <- len, <- erun.
Qed.
Definition P kuji n pos :=
exists fuel, nth_error (run fuel (init kuji)) n = Some pos.
Lemma P0 kuji pos: P kuji 0 pos <-> pos = init kuji.
Proof.
split.
- destruct 1 as [fuel nth0]. simpl in nth0.
destruct fuel as [|fuel]; [discriminate|].
destruct (run_fuel_S fuel (init kuji)) as [tl erun].
rewrite erun in nth0. now injection nth0.
- intros ->. exists 1. simpl. now destruct (next (init kuji)).
Qed.
- destruct 1 as [fuel nth0]. simpl in nth0.
destruct fuel as [|fuel]; [discriminate|].
destruct (run_fuel_S fuel (init kuji)) as [tl erun].
rewrite erun in nth0. now injection nth0.
- intros ->. exists 1. simpl. now destruct (next (init kuji)).
Qed.
Lemma P_S_aux fuel i pos0 p_i:
nth_error (run fuel pos0) (S i) = Some p_i ->
exists prev, nth_error (run fuel pos0) i = Some prev.
Proof.
Lemma P_S kuji i pos: P kuji (S i) pos -> exists prev, P kuji i prev.
Proof.
Lemma P_S_next fuel p0 p_i p_Si i:
nth_error (run fuel p0) i = Some p_i ->
nth_error (run fuel p0) (S i) = Some p_Si ->
next p_i = Some p_Si.
Proof.
intros nthi nthSi.
destruct (nth_error_split _ _ nthi) as [left [right [erun leni]]].
rewrite erun in nthi, nthSi.
rewrite nth_error_app2 in nthi; [|now subst i].
rewrite nth_error_app2 in nthSi; [| now subst i; auto with arith].
apply run_app in erun. revert erun.
case_eq (fuel - length left); [now auto|]. intros fuel' feq.
rewrite Nat.sub_succ_l in nthSi; [|now subst i].
rewrite nth_error_cons in nthSi.
simpl. destruct (next p_i).
- (* p_i の次があるとき: *)
injection 1 as erun'. subst right. subst i.
rewrite Nat.sub_diag in *.
simpl in nthi, nthSi.
revert nthSi. case_eq (run fuel' p); [now auto|]. intros t' tl.
intros erun et. apply run_cons in erun. now subst.
- (* p_i の次がないとき: nth の S i があることに矛盾 *)
injection 1 as eright. subst right. now rewrite nth_error_nil in nthSi.
Qed.
destruct (nth_error_split _ _ nthi) as [left [right [erun leni]]].
rewrite erun in nthi, nthSi.
rewrite nth_error_app2 in nthi; [|now subst i].
rewrite nth_error_app2 in nthSi; [| now subst i; auto with arith].
apply run_app in erun. revert erun.
case_eq (fuel - length left); [now auto|]. intros fuel' feq.
rewrite Nat.sub_succ_l in nthSi; [|now subst i].
rewrite nth_error_cons in nthSi.
simpl. destruct (next p_i).
- (* p_i の次があるとき: *)
injection 1 as erun'. subst right. subst i.
rewrite Nat.sub_diag in *.
simpl in nthi, nthSi.
revert nthSi. case_eq (run fuel' p); [now auto|]. intros t' tl.
intros erun et. apply run_cons in erun. now subst.
- (* p_i の次がないとき: nth の S i があることに矛盾 *)
injection 1 as eright. subst right. now rewrite nth_error_nil in nthSi.
Qed.
Lemma P_S' kuji i pos:
P kuji (S i) pos -> exists prev, P kuji i prev /\ next prev = Some pos.
Proof.
Lemma nP_S_init kuji i: ~P kuji (S i) (init kuji).
Proof.
intros PSi. destruct (P_S' _ _ _ PSi) as [prev [Pi nextp]].
now elim (next_not_init _ _ nextp).
Qed.
now elim (next_not_init _ _ nextp).
Qed.
Lemma unique_path_aux x kuji i j : P kuji i x -> P kuji j x -> i = j.
Proof.
revert x j. induction i; intros x j Pi Pj.
- destruct j; [now auto|].
rewrite P0 in Pi. rewrite Pi in Pj.
now destruct (nP_S_init _ _ Pj).
- destruct j.
+ rewrite P0 in Pj. rewrite Pj in Pi. now destruct (nP_S_init _ _ Pi).
+ apply P_S' in Pi, Pj. destruct Pi as [previ [Pprevi nexti]].
destruct Pj as [prevj [Pprevj nextj]].
rewrite (next_inj x prevj previ) in Pprevj; try assumption.
now rewrite (IHi previ j).
Qed.
- destruct j; [now auto|].
rewrite P0 in Pi. rewrite Pi in Pj.
now destruct (nP_S_init _ _ Pj).
- destruct j.
+ rewrite P0 in Pj. rewrite Pj in Pi. now destruct (nP_S_init _ _ Pi).
+ apply P_S' in Pi, Pj. destruct Pi as [previ [Pprevi nexti]].
destruct Pj as [prevj [Pprevj nextj]].
rewrite (next_inj x prevj previ) in Pprevj; try assumption.
now rewrite (IHi previ j).
Qed.
Lemma unique_path fuel x kuji i j :
nth_error (run fuel (init kuji)) i = Some x ->
nth_error (run fuel (init kuji)) j = Some x ->
i = j.
Proof.
Lemma NoDup_run : forall fuel kuji, NoDup (run fuel (init kuji)).
Proof.
intros fuel kuji. apply NoDup_nth_error. intros i j len e.
apply nth_error_Some in len.
case_eq (nth_error (run fuel (init kuji)) i); [|now idtac].
intros p some_i. rewrite some_i in e.
now apply (unique_path fuel p kuji).
Qed.
apply nth_error_Some in len.
case_eq (nth_error (run fuel (init kuji)) i); [|now idtac].
intros p some_i. rewrite some_i in e.
now apply (unique_path fuel p kuji).
Qed.
Parameter err : Pos.
Definition Finished poss := exists pos, List.Last poss pos /\ next pos = None.
Definition Finished_dec poss: {Finished poss} + {~Finished poss}.
refine (match poss with
| [] => right _
| pos :: ps => if next (last (pos :: ps) pos) =? None then left _
else right _
end).
- destruct 1 as [p [lp]]. now inversion lp.
- set (last (pos :: ps) pos) as l.
exists l. split; [|now auto].
now erewrite (List.lastP pos l).
- intros [posn [lp nxt]].
rewrite List.lastP in lp; [|now auto].
now rewrite lp in n.
Lemma NotFinished_next fuel pos pos':
~Finished (run (1 + fuel) pos) ->
next pos = Some pos' ->
~Finished (run fuel pos').
Proof.
simpl. intros nfinS extb fin.
rewrite extb in nfinS.
destruct fin as [pos_n [lposn nextn]]. destruct nfinS.
exists pos_n. split; [|assumption].
now constructor.
Qed.
rewrite extb in nfinS.
destruct fin as [pos_n [lposn nextn]]. destruct nfinS.
exists pos_n. split; [|assumption].
now constructor.
Qed.
Lemma length_run fuel : forall pos,
~ Finished (run fuel pos) -> length (run fuel pos) = fuel.
Proof.
induction fuel; [now idtac|].
intros pos notFinished. simpl.
case_eq (next pos). intros pos' nextS.
- apply NotFinished_next with _ _ pos' in notFinished; [|now auto].
simpl. now rewrite IHfuel.
- intro nextN. elim notFinished. simpl. rewrite nextN. unfold Finished.
exists pos. now split; [constructor|].
Qed.
intros pos notFinished. simpl.
case_eq (next pos). intros pos' nextS.
- apply NotFinished_next with _ _ pos' in notFinished; [|now auto].
simpl. now rewrite IHfuel.
- intro nextN. elim notFinished. simpl. rewrite nextN. unfold Finished.
exists pos. now split; [constructor|].
Qed.
Theorem main: forall kuji,
exists fuel, Finished (run fuel (init kuji)).
Proof.
intros kuji.
destruct PosFinite as [all full].
remember (length all) as Max.
exists (1 + Max). destruct (Finished_dec (run (1 + Max) (init kuji))); [now idtac|].
apply (length_run _ (init kuji)) in n. elim (Nat.nle_succ_diag_l Max).
simpl Nat.add in n. rewrite <- n. rewrite HeqMax at 2.
apply NoDup_incl_length; [apply NoDup_run|].
now apply List.Full_incl.
Qed.
destruct PosFinite as [all full].
remember (length all) as Max.
exists (1 + Max). destruct (Finished_dec (run (1 + Max) (init kuji))); [now idtac|].
apply (length_run _ (init kuji)) in n. elim (Nat.nle_succ_diag_l Max).
simpl Nat.add in n. rewrite <- n. rewrite HeqMax at 2.
apply NoDup_incl_length; [apply NoDup_run|].
now apply List.Full_incl.
Qed.
End Amida.