Last active
December 21, 2016 14:06
-
-
Save mathink/ca496c0fc2ee60c62eceec252b81be70 to your computer and use it in GitHub Desktop.
nat を string で十進表記する(ハードモード)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (* safe translator from nat to string *) | |
| Require Import Arith List Omega Ascii String Recdef Wf_nat Program.Wf Program.Tactics. | |
| Generalizable All Variables. | |
| Fixpoint div10 (n: nat): nat * nat := | |
| match n with | |
| | S (S (S (S (S (S (S (S (S (S n'))))))))) => | |
| let (q, r) := div10 n' in (S q, r) | |
| | digit => (0, digit) | |
| end. | |
| Eval compute in div10 8. | |
| (* = (0, 8) *) | |
| (* : nat * nat *) | |
| Eval compute in div10 12. | |
| (* = (1, 2) *) | |
| (* : nat * nat *) | |
| Functional Scheme div10_ind := Induction for div10 Sort Prop. | |
| Lemma div10_lt: | |
| forall (n: nat), | |
| (fst (div10 n) < n \/ n = 0). | |
| Proof. | |
| intros n. | |
| functional induction div10 n; auto with arith. | |
| left. | |
| rewrite e9 in IHp; simpl in *. | |
| destruct IHp. | |
| - apply lt_n_S. | |
| now repeat apply lt_S. | |
| - subst; simpl in *. | |
| injection e9; intros; subst; auto with arith. | |
| Qed. | |
| Lemma div10_rem_lt_10: | |
| forall (n: nat), | |
| (snd (div10 n) < 10). | |
| Proof. | |
| intros n. | |
| functional induction div10 n; simpl; auto with arith. | |
| now rewrite e9 in IHp. | |
| Qed. | |
| Fixpoint contain (c: ascii)(s: string) := | |
| match s with | |
| | ""%string => False | |
| | String c' s' => c = c' \/ contain c s' | |
| end. | |
| Definition numeral (c: ascii) := contain c "0123456789". | |
| Inductive numerals: string -> Prop := | |
| | numerals_numeral | |
| : forall (c: ascii), numeral c -> numerals (String c ""%string) | |
| | numerals_String | |
| : forall (c: ascii)(s: string), | |
| numeral c -> numerals s -> numerals (String c s). | |
| Hint Constructors numerals. | |
| Open Scope char_scope. | |
| Obligation Tactic := try now unfold numeral, contain; tauto. | |
| Program Definition digit_to_ascii (n: { m | m < 10}): {c | numeral c} := | |
| let (n, H) := n in | |
| match n as n return n < 10 -> { c | numeral c } with | |
| | 0 => fun _ => "0" | |
| | 1 => fun _ => "1" | |
| | 2 => fun _ => "2" | |
| | 3 => fun _ => "3" | |
| | 4 => fun _ => "4" | |
| | 5 => fun _ => "5" | |
| | 6 => fun _ => "6" | |
| | 7 => fun _ => "7" | |
| | 8 => fun _ => "8" | |
| | 9 => fun _ => "9" | |
| | _ => fun (H: _ < 10) => match (_: False) with end | |
| end H. | |
| Next Obligation. | |
| intros. | |
| repeat apply lt_S_n in H. | |
| now elim (Nat.nlt_0_r _ H). | |
| Qed. | |
| Open Scope string_scope. | |
| Obligation Tactic := program_simpl. | |
| Fixpoint srev_aux (acc: string)(s: string): string := | |
| match s with | |
| | "" => acc | |
| | String c s' => srev_aux (String c acc) s' | |
| end. | |
| Definition srev := srev_aux "". | |
| Lemma srev_aux_numerals: | |
| forall (acc s: string), | |
| numerals acc -> | |
| numerals s -> | |
| numerals (srev_aux acc s). | |
| Proof. | |
| now intros acc s Ha Hs; revert acc Ha; induction Hs; simpl; auto. | |
| Qed. | |
| Lemma srev_numerals: | |
| forall s, numerals s -> numerals (srev s). | |
| Proof. | |
| intros s Hs; induction Hs; unfold srev; simpl; auto. | |
| now apply srev_aux_numerals; auto. | |
| Qed. | |
| Lemma nat_10_ind: | |
| forall (P: nat -> Prop), | |
| P 0 -> | |
| P 1 -> | |
| P 2 -> | |
| P 3 -> | |
| P 4 -> | |
| P 5 -> | |
| P 6 -> | |
| P 7 -> | |
| P 8 -> | |
| P 9 -> | |
| (forall n: nat, P n -> P (10 + n)) -> | |
| forall n: nat, P n. | |
| Proof. | |
| intros P H0 H1 H2 H3 H4 H5 H6 H7 H8 H9 Hn n. | |
| revert P H0 H1 H2 H3 H4 H5 H6 H7 H8 H9 Hn. | |
| induction n as [|[|[|[|[|[|[|[|[|[|n]]]]]]]]] IHn]; auto. | |
| intros. | |
| pattern (S n); apply (IHn (fun n => P (S n))); auto. | |
| - now apply Hn. | |
| - intros. | |
| now rewrite plus_n_Sm; apply Hn. | |
| Qed. | |
| Lemma div10_decomp_aux: | |
| forall (q r n: nat), | |
| n = r + 10 * q -> | |
| r < 10 -> | |
| (q,r) = div10 n. | |
| Proof. | |
| intros q r n; revert n q r. | |
| apply (nat_10_ind (fun n => forall q r: nat, _ -> _ -> (q,r) = div10 n)); | |
| try (intros q r Heq Hlt; assert (q = 0); [omega | subst]; | |
| simpl in *; rewrite plus_comm in Heq; | |
| simpl in Heq; subst; auto). | |
| intros n IH q r Heq Hlt. | |
| destruct q; [omega |]. | |
| rewrite <- mult_n_Sm, (plus_comm _ 10), Nat.add_shuffle3 in Heq. | |
| apply plus_reg_l in Heq. | |
| simpl. | |
| now rewrite <- (IH _ _ Heq). | |
| Qed. | |
| Lemma div10_decomp: | |
| forall (q r: nat), | |
| r < 10 -> | |
| (q,r) = div10 (r + 10 * q). | |
| Proof. | |
| now intros; apply div10_decomp_aux. | |
| Qed. | |
| Lemma n_decomp_10: | |
| forall (n: nat), | |
| exists q r, (10 * q + r = n /\ r < 10). | |
| Proof. | |
| intros; exists (fst (div10 n)), (snd (div10 n)). | |
| functional induction div10 n; | |
| try (now split; simpl; auto with arith). | |
| rewrite e9 in IHp. | |
| simpl (fst _) in *; simpl (snd _) in *. | |
| destruct IHp as [Heq Hlt]. | |
| now rewrite <- mult_n_Sm, <- plus_assoc, Nat.add_shuffle3, Heq. | |
| Qed. | |
| Function div10_l_aux (acc: list nat)(n: nat){wf lt n}: list nat := | |
| let (q,r) := div10 n in | |
| match q with | |
| | O => r :: acc | |
| | S q' => (div10_l_aux (r :: acc) q) | |
| end. | |
| Proof. | |
| - intros. | |
| generalize (div10_lt n); rewrite teq. | |
| now intros [Hlt | Heq]; [assumption | subst; simpl in teq; discriminate]. | |
| - apply lt_wf. | |
| Defined. | |
| Definition div10_l := div10_l_aux nil. | |
| Check fold_left. | |
| Lemma div10_decomp_inv: | |
| forall n q r, | |
| div10 n = (q, r) -> n = 10 * q + r. | |
| Proof. | |
| intros n; functional induction div10 n; | |
| intros q' r' Heq; try (now injection Heq; intros; subst; auto with arith). | |
| injection Heq; intros; subst. | |
| now rewrite <- mult_n_Sm, <- plus_assoc, Nat.add_shuffle3, IHp with q r'; auto with arith. | |
| Qed. | |
| Lemma div10_l_aux_valid: | |
| forall (n: nat)(acc: list nat), | |
| (10 ^ (List.length acc)) * n + fold_left `(q * 10 + r) acc 0 | |
| = fold_left `(q * 10 + r) (div10_l_aux acc n) 0. | |
| Proof. | |
| intros n acc. | |
| functional induction div10_l_aux acc n. | |
| - assert (n = r /\ n < 10). | |
| { | |
| destruct n as [|[|[|[|[|[|[|[|[|[| n]]]]]]]]]]; | |
| try now (simpl in e; injection e; intros; subst; | |
| split; auto with arith). | |
| simpl in e. | |
| now destruct (div10 n); discriminate. | |
| } | |
| simpl. | |
| destruct H as [Heq Hlt]; subst n; clear e Hlt. | |
| revert r. | |
| induction acc as [| x acc IH]. | |
| + simpl; intros; omega. | |
| + simpl (List.length _). | |
| simpl (fold_left _ _ _). | |
| intros. | |
| rewrite <- (IH (r * 10 + x)). | |
| assert (10 ^ Datatypes.length acc * (r * 10 + x) = | |
| 10 ^ S (List.length acc) * r + 10 ^ List.length acc * x). | |
| { | |
| rewrite mult_plus_distr_l. | |
| rewrite Nat.pow_succ_r'. | |
| now rewrite (mult_comm 10 _), (mult_comm r 10), mult_assoc. | |
| } | |
| rewrite H, <- plus_assoc. | |
| apply f_equal2_plus; auto. | |
| - simpl (fold_left _ _ _) in *. | |
| rewrite <- IHl. | |
| simpl (List.length _). | |
| rewrite Nat.pow_succ_r', (mult_comm 10 _), <- mult_assoc. | |
| apply div10_decomp_inv in e; subst n. | |
| rewrite mult_plus_distr_l, <- plus_assoc. | |
| apply f_equal2_plus; auto. | |
| clear IHl. | |
| revert r. | |
| induction acc as [| x acc IH]. | |
| + simpl; intros; omega. | |
| + simpl (List.length _). | |
| simpl (fold_left _ _ _). | |
| intros. | |
| rewrite <- (IH (r * 10 + x)). | |
| assert (10 ^ Datatypes.length acc * (r * 10 + x) = | |
| 10 ^ S (List.length acc) * r + 10 ^ List.length acc * x). | |
| { | |
| rewrite mult_plus_distr_l. | |
| rewrite Nat.pow_succ_r'. | |
| now rewrite (mult_comm 10 _), (mult_comm r 10), mult_assoc. | |
| } | |
| rewrite H, <- plus_assoc. | |
| apply f_equal2_plus; auto. | |
| Qed. | |
| Lemma div10_l_valid: | |
| forall (n: nat), | |
| n = fold_left `(q * 10 + r) (div10_l n) 0. | |
| Proof. | |
| intros n; unfold div10_l. | |
| generalize (div10_l_aux_valid n nil). | |
| now simpl; rewrite !plus_0_r. | |
| Qed. | |
| Lemma div10_l_aux_lt_10: | |
| forall (acc: list nat)(n: nat), | |
| Forall `(m < 10) acc -> | |
| Forall `(m < 10) (div10_l_aux acc n). | |
| Proof. | |
| intros acc n. | |
| functional induction div10_l_aux acc n. | |
| - assert (r < 10). | |
| { | |
| now generalize (div10_rem_lt_10 n); rewrite e. | |
| } | |
| intros Hacc. | |
| now apply Forall_cons. | |
| - assert (r < 10). | |
| { | |
| now generalize (div10_rem_lt_10 n); rewrite e. | |
| } | |
| intros Hacc; apply IHl. | |
| now apply Forall_cons. | |
| Qed. | |
| Definition div10_l_lt_10 (n: nat): | |
| Forall `(m < 10) (div10_l n) := | |
| div10_l_aux_lt_10 nil n (Forall_nil _). | |
| Lemma Forall_inv': | |
| forall (X: Type)(P: X -> Prop)(x: X)(l: list X), | |
| Forall P (x :: l) -> P x /\ Forall P l. | |
| Proof. | |
| now intros X P x l H; inversion H. | |
| Qed. | |
| Program Fixpoint add_prop (X: Type)(l: list X)(P: X -> Prop)(H: Forall P l) | |
| : list { x | P x } := | |
| match l as l return Forall P l -> list {x | P x }with | |
| | nil => fun _ => nil | |
| | x :: xs => fun (H: Forall P (x :: xs)) => | |
| (exist P x (proj1 (Forall_inv' _ P x xs H))) | |
| :: add_prop _ xs P (proj2 (Forall_inv' _ P x xs H)) | |
| end H. | |
| Definition nat_to_numerals_aux (n: nat): list {c | numeral c} := | |
| map (fun (n: {m | m < 10}) => digit_to_ascii n) | |
| (add_prop _ _ _ (div10_l_lt_10 n)). | |
| Program Fixpoint numeral_list_to_numerals (l: list {c | numeral c})(H: 0 < List.length l) {struct l} | |
| : {s | numerals s} := | |
| match l as l return 0 < List.length l -> {s | numerals s} with | |
| | nil => fun (H: 0 < 0) => match (lt_irrefl _ H) with end | |
| | c :: xs => | |
| fun (H: 0 < S (List.length xs)) => | |
| let (c, Hc) := c in | |
| match zerop (List.length xs) with | |
| | left _ => exist numerals (String c "") _ | |
| | right Hlt => | |
| let (s, Hs) := numeral_list_to_numerals xs Hlt in | |
| exist numerals (String c s) _ | |
| end | |
| end H. | |
| Lemma div10_l_aux_not_nil: | |
| forall (acc: list nat)(n: nat), | |
| 0 < List.length (div10_l_aux acc n). | |
| Proof. | |
| intros acc n; functional induction div10_l_aux acc n. | |
| - now simpl; auto with arith. | |
| - now apply IHl. | |
| Qed. | |
| Lemma add_prop_length: | |
| forall (X: Type)(P: X -> Prop)(l: list X)(H: Forall P l), | |
| List.length (add_prop _ _ _ H) = List.length l. | |
| Proof. | |
| now induction l; simpl; auto. | |
| Qed. | |
| Lemma nat_to_numerals_aux_not_nil: | |
| forall (n: nat), | |
| 0 < List.length (nat_to_numerals_aux n). | |
| Proof. | |
| intros; unfold nat_to_numerals_aux. | |
| rewrite map_length, add_prop_length. | |
| now apply div10_l_aux_not_nil. | |
| Qed. | |
| Definition nat_to_numerals (n: nat) := | |
| numeral_list_to_numerals _ (nat_to_numerals_aux_not_nil n). | |
| (* Proofs *) | |
| Open Scope list_scope. | |
| Lemma div10_l_aux_decomp: | |
| forall (acc: list nat)(q r: nat), | |
| r < 10 -> | |
| 0 < q -> | |
| div10_l_aux acc (q * 10 + r) = div10_l_aux (r :: acc) q. | |
| Proof. | |
| intros; simpl. | |
| generalize (div10_decomp q _ H). | |
| rewrite (plus_comm r), (mult_comm 10). | |
| set (q * 10 + r) as n. | |
| intros Heq. | |
| functional induction div10_l_aux acc n. | |
| - rewrite <- Heq in e; injection e; intros; subst; simpl. | |
| now elim (lt_irrefl _ H0). | |
| - now rewrite <- Heq in e; injection e; intros; subst; simpl. | |
| Qed. | |
| Require Import ProofIrrelevance. | |
| Lemma add_prop_cons: | |
| forall (X: Type)(P: X -> Prop)(x: X)(l: list X) | |
| (Hx: P x)(Hl: Forall P l), | |
| add_prop X (x :: l) P (Forall_cons _ Hx Hl) = | |
| exist P x Hx :: add_prop X l P Hl. | |
| Proof. | |
| intros X P x l; revert P x. | |
| induction l as [| y l IHl]. | |
| - simpl; intros. | |
| now rewrite (proof_irrelevance _ _ Hx). | |
| - intros. | |
| generalize (IHl P y (proj1 (Forall_inv' _ P _ _ Hl)) (proj2 (Forall_inv' _ P _ _ Hl))). | |
| rewrite (proof_irrelevance _ _ Hl). | |
| intros H; rewrite H. | |
| simpl. | |
| rewrite (proof_irrelevance _ _ Hx). | |
| rewrite (proof_irrelevance _ _ (proj1 (Forall_inv' _ _ _ _ Hl))). | |
| rewrite (proof_irrelevance _ _ (proj2 (Forall_inv' _ _ _ _ Hl))). | |
| reflexivity. | |
| Qed. | |
| Lemma Forall_app: | |
| forall (X: Type)(P: X -> Prop)(l1 l2: list X), | |
| Forall P l1 -> Forall P l2 -> | |
| Forall P (l1 ++ l2). | |
| Proof. | |
| induction l1 as [| x l1 IH1]; auto. | |
| simpl; intros. | |
| apply Forall_inv' in H; destruct H. | |
| now apply Forall_cons; auto. | |
| Qed. | |
| Lemma add_prop_app: | |
| forall (X: Type)(P: X -> Prop)(l1 l2: list X) | |
| (H1: Forall P l1)(H2: Forall P l2), | |
| add_prop X (l1 ++ l2) P (Forall_app _ _ _ _ H1 H2) = | |
| add_prop X l1 P H1 ++ add_prop X l2 P H2. | |
| Proof. | |
| induction l1 as [| x l1 IH]; simpl; intros. | |
| - now rewrite (proof_irrelevance _ _ H2). | |
| - generalize (IH l2 (proj2 (Forall_inv' _ _ _ _ H1)) H2). | |
| rewrite (proof_irrelevance _ (proj2 | |
| (Forall_inv' X P x (l1 ++ l2) (Forall_app X P (x :: l1) l2 H1 H2))) (Forall_app X P l1 l2 (proj2 (Forall_inv' X P x l1 H1)) H2)). | |
| intros H; rewrite H. | |
| now rewrite (proof_irrelevance _ _ (proj1 (Forall_inv' X P x l1 H1))). | |
| Qed. | |
| Lemma div10_l_aux_app_aux: | |
| forall (l acc acc': list nat)(n: nat), | |
| l = acc ++ acc' -> | |
| div10_l_aux l n = div10_l_aux acc n ++ acc'. | |
| Proof. | |
| intros l acc acc' n Heq; revert acc acc' Heq. | |
| functional induction div10_l_aux l n. | |
| - assert (n = r /\ n < 10). | |
| { | |
| destruct n as [|[|[|[|[|[|[|[|[|[| n]]]]]]]]]]; | |
| try now (simpl in e; injection e; intros; subst; | |
| split; auto with arith). | |
| simpl in e. | |
| now destruct (div10 n); discriminate. | |
| } | |
| simpl. | |
| destruct H as [Heq Hlt]; subst n; clear e. | |
| destruct r as [|[|[|[|[|[|[|[|[|[| r]]]]]]]]]]; | |
| try (now simpl; intros acc' acc'' Heq; subst acc). | |
| repeat apply lt_S_n in Hlt. | |
| now elim (Nat.nlt_0_r _ Hlt). | |
| - intros; rewrite IHl0 with (r :: acc0) acc'; try now simpl; rewrite Heq. | |
| assert (r < 10). | |
| { | |
| now generalize (div10_rem_lt_10 n); rewrite e; simpl. | |
| } | |
| apply div10_decomp_inv in e; subst n. | |
| rewrite mult_comm. | |
| now rewrite div10_l_aux_decomp; auto with arith. | |
| Qed. | |
| Lemma div10_l_aux_app: | |
| forall (acc acc': list nat)(n: nat), | |
| div10_l_aux (acc ++ acc') n = div10_l_aux acc n ++ acc'. | |
| Proof. | |
| now intros; apply div10_l_aux_app_aux. | |
| Qed. | |
| Lemma nat_to_numerals_aux_decomp: | |
| forall (q r: nat)(Hltr: r < 10), | |
| 0 < q -> | |
| map (@proj1_sig _ _) (nat_to_numerals_aux (q * 10 + r)) = | |
| map (@proj1_sig _ _) (nat_to_numerals_aux q) ++ (proj1_sig (digit_to_ascii (exist _ r Hltr)) :: nil). | |
| Proof. | |
| unfold nat_to_numerals_aux. | |
| intros q r Hltr Hltq. | |
| rewrite !map_map. | |
| assert (proj1_sig (digit_to_ascii (exist (fun m : nat => m < 10) r Hltr)) :: nil | |
| = | |
| map (fun x : {m : nat | m < 10} => proj1_sig (digit_to_ascii x)) (exist _ r Hltr :: nil)). | |
| { | |
| reflexivity. | |
| } | |
| rewrite H. | |
| rewrite <- (map_app (fun x => proj1_sig (digit_to_ascii x))). | |
| assert (H': Forall (fun m : nat => m < 10) (r :: nil)). | |
| { | |
| now apply Forall_cons; auto. | |
| } | |
| assert (exist (fun m : nat => m < 10) r Hltr :: nil = | |
| add_prop _ (r :: nil) _ H'). | |
| { | |
| simpl. | |
| now rewrite (proof_irrelevance _ (proj1 _) Hltr). | |
| } | |
| rewrite H0. | |
| rewrite <- add_prop_app. | |
| clear H0 H. | |
| generalize (div10_l_lt_10 (q * 10 + r)); intros H. | |
| unfold div10_l in *. | |
| revert H. | |
| pattern (div10_l_aux nil (q * 10 + r)). | |
| rewrite (div10_l_aux_decomp nil q r Hltr) in *; auto. | |
| generalize (Forall_app nat (fun m : nat => m < 10) (div10_l_aux nil q) | |
| (r :: nil) (div10_l_lt_10 q) H'). | |
| rewrite <- div10_l_aux_app; simpl. | |
| now intros; rewrite (proof_irrelevance _ f H). | |
| Qed. | |
| Lemma nat_to_numerals_aux_decomp': | |
| forall (q r: nat)(Hltr: r < 10), | |
| 0 < q -> | |
| nat_to_numerals_aux (q * 10 + r) = | |
| (nat_to_numerals_aux q) ++ (digit_to_ascii (exist _ r Hltr) :: nil). | |
| Proof. | |
| unfold nat_to_numerals_aux. | |
| intros q r Hltr Hltq. | |
| assert ( (digit_to_ascii (exist (fun m : nat => m < 10) r Hltr)) :: nil | |
| = | |
| map (fun x : {m : nat | m < 10} => (digit_to_ascii x)) (exist _ r Hltr :: nil)). | |
| { | |
| reflexivity. | |
| } | |
| rewrite H. | |
| rewrite <- (map_app (fun x => (digit_to_ascii x))). | |
| assert (H': Forall (fun m : nat => m < 10) (r :: nil)). | |
| { | |
| now apply Forall_cons; auto. | |
| } | |
| assert (exist (fun m : nat => m < 10) r Hltr :: nil = | |
| add_prop _ (r :: nil) _ H'). | |
| { | |
| simpl. | |
| now rewrite (proof_irrelevance _ (proj1 _) Hltr). | |
| } | |
| rewrite H0. | |
| rewrite <- add_prop_app. | |
| clear H0 H. | |
| generalize (div10_l_lt_10 (q * 10 + r)); intros H. | |
| unfold div10_l in *. | |
| revert H. | |
| pattern (div10_l_aux nil (q * 10 + r)). | |
| rewrite (div10_l_aux_decomp nil q r Hltr) in *; auto. | |
| generalize (Forall_app nat (fun m : nat => m < 10) (div10_l_aux nil q) | |
| (r :: nil) (div10_l_lt_10 q) H'). | |
| rewrite <- div10_l_aux_app; simpl. | |
| now intros; rewrite (proof_irrelevance _ f H). | |
| Qed. | |
| Lemma div10_l_decomp: | |
| forall (q r: nat), | |
| r < 10 -> | |
| 0 < q -> | |
| div10_l (q * 10 + r) = div10_l q ++ r :: nil. | |
| Proof. | |
| intros q r Hltr Hltq. | |
| unfold div10_l. | |
| rewrite div10_l_aux_decomp; auto. | |
| now rewrite <- div10_l_aux_app. | |
| Qed. | |
| Program Definition numerals_app (s1 s2: { s | numerals s}): {s | numerals s} := | |
| exist numerals (s1 ++ s2)%string _. | |
| Next Obligation. | |
| now induction H0; apply numerals_String. | |
| Qed. | |
| Lemma app_length_lt: | |
| forall (X: Type)(l1 l2: list X), | |
| 0 < List.length l1 -> 0 < List.length l2 -> | |
| 0 < List.length (l1 ++ l2). | |
| Proof. | |
| intros; rewrite app_length. | |
| rewrite <- (plus_0_r 0). | |
| now apply plus_lt_compat. | |
| Qed. | |
| Program Definition numerals_cons (c: {c | numeral c})(s: {s | numerals s}): {s | numerals s} := | |
| exist numerals (String c s) _. | |
| Lemma numeral_list_to_numerals_cons: | |
| forall (c: {c | numeral c})(l: list {c | numeral c})(H: 0 < List.length l), | |
| numeral_list_to_numerals (c :: l) (Nat.lt_lt_succ_r _ _ H) | |
| = numerals_cons c (numeral_list_to_numerals _ H). | |
| Proof. | |
| intros c l; revert c. | |
| induction l as [| c' l IH]; intros. | |
| - now elim (lt_irrefl _ H). | |
| - destruct c as [c Hc]. | |
| simpl in H. | |
| generalize H as H'. | |
| apply le_lt_or_eq in H. | |
| destruct H as [Hlt | Heq]. | |
| + intros. | |
| apply lt_S_n in Hlt. | |
| generalize (IH c' Hlt). | |
| rewrite (proof_irrelevance _ _ H'). | |
| intros Heq; rewrite Heq; clear Heq IH. | |
| generalize (Nat.lt_lt_succ_r 0 (Datatypes.length (c' :: l)) H') as H''. | |
| simpl (List.length _). | |
| unfold numerals_cons. | |
| simpl (exist numerals _ _). | |
| intros H''. | |
| simpl. | |
| assert (zerop (List.length l) = right Hlt). | |
| { | |
| destruct l; simpl. | |
| - now elim (lt_irrefl _ Hlt). | |
| - now rewrite (proof_irrelevance _ _ Hlt). | |
| } | |
| rewrite H. | |
| destruct c' as [c' Hc']. | |
| simpl. | |
| now destruct (numeral_list_to_numerals l Hlt); simpl. | |
| + apply eq_add_S in Heq. | |
| destruct l. | |
| * simpl; intros. | |
| destruct c' as [c' Hc']. | |
| simpl. | |
| now unfold numerals_cons; simpl. | |
| * discriminate. | |
| Qed. | |
| Lemma numerals_app_valid: | |
| forall (l1 l2: list {c | numeral c}) | |
| (H1: 0 < List.length l1) | |
| (H2: 0 < List.length l2), | |
| numeral_list_to_numerals (l1 ++ l2) (app_length_lt _ _ _ H1 H2) = | |
| numerals_app (numeral_list_to_numerals l1 H1) | |
| (numeral_list_to_numerals l2 H2). | |
| Proof. | |
| induction l1 as [| c l1 IH]; intros. | |
| - now elim (lt_irrefl _ H1). | |
| - simpl ((_ :: _) ++ l2). | |
| assert (0 < List.length (l1 ++ l2)). | |
| { | |
| rewrite app_length. | |
| now apply Nat.add_pos_r. | |
| } | |
| generalize (numeral_list_to_numerals_cons c (l1 ++ l2) H); intros Heq. | |
| rewrite (proof_irrelevance _ (Nat.lt_lt_succ_r 0 (Datatypes.length (l1 ++ l2)) H) (app_length_lt {c0 : ascii | numeral c0} (c :: l1) l2 H1 H2)) in Heq. | |
| rewrite Heq; clear Heq. | |
| revert c H1. | |
| case_eq (zerop (List.length l1)). | |
| + intros e Heq c Hlt; simpl. | |
| rewrite Heq; simpl. | |
| destruct c as [c Hc]; simpl. | |
| unfold numerals_cons, numerals_app. | |
| simpl. | |
| destruct l1; [| discriminate]; simpl in *. | |
| rewrite (proof_irrelevance _ H2 H). | |
| now rewrite (proof_irrelevance _ (numerals_cons_obligation_1 (exist (fun c0 : ascii => numeral c0) c Hc) (numeral_list_to_numerals l2 H)) (numerals_app_obligation_1 (exist numerals (String c "") (numerals_numeral c Hc)) (numeral_list_to_numerals l2 H))). | |
| + intros H1 Heq c Hlt. | |
| simpl. | |
| rewrite Heq; clear Heq. | |
| destruct c as [c Hc]; simpl. | |
| generalize (IH l2 H1 H2). | |
| rewrite (proof_irrelevance _ (app_length_lt {c0 : ascii | numeral c0} l1 l2 H1 H2) H). | |
| intros Heq; rewrite Heq. | |
| unfold numerals_cons, numerals_app. | |
| destruct (numeral_list_to_numerals l1 H1); simpl. | |
| now rewrite (proof_irrelevance _ (numerals_String c (x ++ proj1_sig (numeral_list_to_numerals l2 H2)) Hc (numerals_app_obligation_1 (exist (fun s : string => numerals s) x n) (numeral_list_to_numerals l2 H2))) (numerals_app_obligation_1 (exist numerals (String c x) (numerals_String c x Hc n)) (numeral_list_to_numerals l2 H2))). | |
| Qed. | |
| Program Definition numeral_numerals (c: {c | numeral c}): {s | numerals s} := | |
| exist numerals (String c ""%string) _. | |
| Lemma nat_to_numerals_decomp: | |
| forall (q r: nat)(Hltr: r < 10), | |
| 0 < q -> | |
| (nat_to_numerals (q * 10 + r)) = | |
| numerals_app (nat_to_numerals q) (numeral_numerals (digit_to_ascii (exist _ r Hltr))). | |
| Proof. | |
| unfold nat_to_numerals; intros. | |
| generalize (nat_to_numerals_aux_not_nil (q * 10 + r)) as Hlt. | |
| rewrite (nat_to_numerals_aux_decomp' _ _ Hltr); auto. | |
| intros Hlt. | |
| assert (0 < List.length (nat_to_numerals_aux q)). | |
| { | |
| unfold nat_to_numerals_aux. | |
| rewrite map_length, add_prop_length. | |
| unfold div10_l. | |
| now apply div10_l_aux_not_nil. | |
| } | |
| generalize (numerals_app_valid (nat_to_numerals_aux q) (digit_to_ascii (exist (fun m : nat => m < 10) r Hltr) :: nil) H0 (Nat.lt_0_succ _)); intros Heq. | |
| rewrite (proof_irrelevance _ (app_length_lt {c : ascii | numeral c} (nat_to_numerals_aux q) | |
| (digit_to_ascii (exist (fun m : nat => m < 10) r Hltr) :: nil) H0 | |
| (Nat.lt_0_succ 0)) Hlt) in Heq. | |
| rewrite Heq; clear Heq. | |
| rewrite (proof_irrelevance _ (nat_to_numerals_aux_not_nil q) H0). | |
| destruct r as [|[|[|[|[|[|[|[|[|[|r]]]]]]]]]]; | |
| try now simpl; auto. | |
| clear Hlt. | |
| generalize Hltr; intros. | |
| repeat apply lt_S_n in Hltr. | |
| now elim (Nat.nlt_0_r _ Hltr). | |
| Qed. | |
| (* *) | |
| Open Scope char_scope. | |
| Definition numeral_to_digit (c: { c | numeral c }): { m | m < 10 }. | |
| refine (let (c, Hc) := c in | |
| match c as c return numeral c -> { m | m < 10 } with | |
| | "0" => fun Hc => exist `(m < 10) 0 _ | |
| | "1" => fun Hc => exist `(m < 10) 1 _ | |
| | "2" => fun Hc => exist `(m < 10) 2 _ | |
| | "3" => fun Hc => exist `(m < 10) 3 _ | |
| | "4" => fun Hc => exist `(m < 10) 4 _ | |
| | "5" => fun Hc => exist `(m < 10) 5 _ | |
| | "6" => fun Hc => exist `(m < 10) 6 _ | |
| | "7" => fun Hc => exist `(m < 10) 7 _ | |
| | "8" => fun Hc => exist `(m < 10) 8 _ | |
| | "9" => fun Hc => exist `(m < 10) 9 _ | |
| | Ascii b0 b1 b2 b3 b4 b5 b6 b7 => | |
| fun H => match (_:False) with end | |
| end Hc); auto with arith; | |
| unfold numeral, contain in H; | |
| destruct H as [H0 |[H1 |[H2 |[H3 |[H4 |[H5 |[H6 |[H7 |[H8 |[H9 | F]]]]]]]]]]; try discriminate; contradiction. | |
| Defined. | |
| Lemma numerals_inv: | |
| forall (c: ascii)(s: string), | |
| numerals (String c s) -> numeral c. | |
| Proof. | |
| now intros c s H; inversion H. | |
| Qed. | |
| Lemma numerals_inv': | |
| forall (c c': ascii)(s: string), | |
| numerals (String c (String c' s)) -> | |
| numerals (String c' s). | |
| Proof. | |
| now intros c s s' H; inversion H. | |
| Qed. | |
| Fixpoint string_to_ascii_list (s: string): list ascii := | |
| match s with | |
| | ""%string => nil | |
| | String c s' => c :: string_to_ascii_list s' | |
| end. | |
| Lemma numerals_all_numeral: | |
| forall s, numerals s -> | |
| Forall numeral (string_to_ascii_list s). | |
| Proof. | |
| now intros s Hs; induction Hs; simpl; apply Forall_cons; auto. | |
| Qed. | |
| Definition numerals_to_numeral_list (s: {s | numerals s}): list {c | numeral c} := | |
| let (s, Hs) := s in | |
| add_prop _ (string_to_ascii_list s) | |
| numeral (numerals_all_numeral s Hs). | |
| Definition numerals_to_nat (s : {s | numerals s}): nat := | |
| fold_left (fun n m => n * 10 + proj1_sig m) | |
| (map numeral_to_digit (numerals_to_numeral_list s)) 0. | |
| Lemma test: numerals "2361". | |
| Proof. | |
| do 3 (apply numerals_String; [unfold numeral; simpl; tauto |]). | |
| apply numerals_numeral; unfold numeral; simpl; tauto. | |
| Qed. | |
| Eval compute in numerals_to_nat (exist numerals _ test). | |
| (* = 2361 *) | |
| (* : nat *) | |
| Lemma string_to_ascii_list_app: | |
| forall (s1 s2: string), | |
| string_to_ascii_list (append s1 s2) = | |
| string_to_ascii_list s1 ++ string_to_ascii_list s2. | |
| Proof. | |
| induction s1 as [| c s1 IH]; simpl; auto. | |
| now intros s2; rewrite IH. | |
| Qed. | |
| Lemma Forall_app_inv: | |
| forall (X: Type)(P: X -> Prop)(l1 l2: list X), | |
| Forall P (l1 ++ l2) -> Forall P l1 /\ Forall P l2. | |
| Proof. | |
| induction l1; auto. | |
| simpl; intros l2 Hf. | |
| inversion Hf; subst. | |
| now split; [apply Forall_cons; auto; apply IHl1 with l2 | apply IHl1]. | |
| Qed. | |
| Lemma fold_left_cons: | |
| forall (A B: Type)(f: A -> B -> A)(l: list B)(e: A)(x: B), | |
| fold_left f (x :: l) e = fold_left f l (f e x). | |
| Proof. | |
| reflexivity. | |
| Qed. | |
| Lemma numerals_to_nat_app: | |
| forall (s1 s2: {s | numerals s}), | |
| numerals_to_nat (numerals_app s1 s2) = | |
| (10 ^ length (proj1_sig s2)) * numerals_to_nat s1 + | |
| numerals_to_nat s2. | |
| Proof. | |
| intros [s1 Hs1] [s2 Hs2]. | |
| simpl. | |
| unfold numerals_to_nat. | |
| set (fun (n: nat)(m: {m : nat | m < 10}) => n * 10 + proj1_sig m) as f in *. | |
| unfold numerals_to_numeral_list, numerals_app. | |
| simpl (proj1_sig (exist _ _ _)). | |
| generalize (numerals_all_numeral (s1 ++ s2) | |
| (numerals_app_obligation_1 | |
| (exist (fun s : string => numerals s) s1 Hs1) | |
| (exist (fun s : string => numerals s) s2 Hs2))) as Hf. | |
| rewrite string_to_ascii_list_app; intros Hf. | |
| generalize Hf as Hf'; intros. | |
| apply Forall_app_inv in Hf. | |
| destruct Hf as [Hf1 Hf2]. | |
| generalize (add_prop_app _ numeral (string_to_ascii_list s1) (string_to_ascii_list s2) Hf1 Hf2) as Heq; intros. | |
| rewrite (proof_irrelevance _ _ Hf') in Heq. | |
| rewrite Heq. | |
| rewrite map_app. | |
| clear Heq Hf'. | |
| rewrite (proof_irrelevance _ Hf1 (numerals_all_numeral _ Hs1)). | |
| rewrite (proof_irrelevance _ Hf2 (numerals_all_numeral _ Hs2)). | |
| clear Hf1 Hf2. | |
| revert s1 Hs1. | |
| induction s2 as [| c2 s2 IH2]. | |
| - now inversion Hs2. | |
| - inversion Hs2; subst. | |
| + simpl (length _). | |
| simpl (_ ^ _). | |
| assert (map numeral_to_digit | |
| (add_prop ascii (string_to_ascii_list (String c2 "")) numeral | |
| (numerals_all_numeral (String c2 "") Hs2)) = numeral_to_digit (exist _ c2 H0) :: nil). | |
| { | |
| unfold numeral in H0. | |
| repeat destruct H0 as [H | H0]; subst; try reflexivity. | |
| now elim H0. | |
| } | |
| rewrite H in *. | |
| intros s1 Hs1. | |
| rewrite fold_left_app. | |
| rewrite fold_left_cons. | |
| unfold numeral in H0. | |
| repeat destruct H0 as [H' | H0]; subst; | |
| now rewrite (mult_comm 10); subst f; simpl. | |
| + simpl (length _). | |
| rewrite Nat.pow_succ_r'. | |
| intros s1 Hs1. | |
| rewrite <- mult_assoc, (mult_comm 10). | |
| simpl (string_to_ascii_list _) in *. | |
| simpl (add_prop _ (_ :: _) _ _). | |
| rewrite map_cons. | |
| rewrite (proof_irrelevance _ _ H1). | |
| assert (H: numerals (append s1 (String c2 ""))). | |
| { | |
| clear IH2. | |
| induction Hs1; auto. | |
| - simpl. | |
| now apply numerals_String; auto. | |
| - simpl. | |
| now apply numerals_String. | |
| } | |
| generalize (IH2 H2 _ H); clear IH2. | |
| generalize (numerals_all_numeral (s1 ++ String c2 "") H) as H1'. | |
| rewrite string_to_ascii_list_app. | |
| intros H1'; generalize H1' as H1''. | |
| apply Forall_app_inv in H1'. | |
| destruct H1'; intros H1''. | |
| generalize (add_prop_app ascii numeral _ _ H0 H3); intros H4. | |
| rewrite (proof_irrelevance _ _ H1'') in H4. | |
| rewrite H4; clear H4. | |
| rewrite map_app. | |
| rewrite (proof_irrelevance _ H0 (numerals_all_numeral s1 Hs1)); clear H0. | |
| assert (map numeral_to_digit | |
| (add_prop ascii (string_to_ascii_list (String c2 "")) numeral | |
| H3) = numeral_to_digit (exist _ c2 H1) :: nil). | |
| { | |
| unfold numeral in H1. | |
| repeat destruct H1 as [H' | H1]; subst; try reflexivity. | |
| now elim H1. | |
| } | |
| rewrite H0. | |
| intros. | |
| set (map numeral_to_digit | |
| (add_prop ascii (string_to_ascii_list s1) numeral | |
| (numerals_all_numeral s1 Hs1))) as x in *. | |
| rewrite (proof_irrelevance _ (proj2 _) (numerals_all_numeral s2 H2)). | |
| set (map numeral_to_digit | |
| (add_prop ascii (string_to_ascii_list s2) numeral | |
| (numerals_all_numeral s2 H2))) as y in *. | |
| rewrite <- app_assoc in H4. | |
| set (numeral_to_digit (exist numeral c2 H1)) as n in *. | |
| simpl (_ ++ (_ :: nil) ++ _) in H4. | |
| rewrite H4; clear H4. | |
| rewrite fold_left_app, fold_left_cons. | |
| simpl. | |
| subst f; simpl. | |
| set (fun (n: nat)(m: {m | m < 10}) => n * 10 + proj1_sig m) as f. | |
| rewrite mult_plus_distr_l, mult_assoc. | |
| rewrite <- plus_assoc. | |
| apply f_equal2_plus; auto. | |
| clear x. | |
| assert (length s2 = List.length y). | |
| { | |
| subst y. | |
| rewrite map_length, add_prop_length. | |
| clear c2 Hs2 H1 H2 s1 Hs1 H H3 H1'' n H0 f. | |
| induction s2; auto. | |
| now simpl; rewrite IHs2. | |
| } | |
| rewrite H4; clear H4. | |
| assert (proj1_sig n = f 0 n). | |
| { | |
| now subst f; simpl. | |
| } | |
| rewrite H4; clear H4. | |
| assert (forall y x n, | |
| 10 ^ Datatypes.length y * f x n + fold_left f y 0 = | |
| fold_left f y (f x n) | |
| ). | |
| { | |
| induction y0 as [| m y0 IHy]. | |
| - intros; simpl; omega. | |
| - intros. | |
| simpl (List.length _). | |
| rewrite Nat.pow_succ_r', !(mult_comm 10). | |
| simpl. | |
| rewrite <- IHy. | |
| rewrite <- IHy. | |
| subst f. | |
| simpl. | |
| set (fold_left | |
| (fun (n1 : nat) (m0 : {m0 : nat | m0 < 10}) => n1 * 10 + proj1_sig m0) | |
| y0 0) as p. | |
| set (10 ^ List.length y0) as e. | |
| rewrite !mult_plus_distr_l. | |
| rewrite mult_plus_distr_r. | |
| rewrite !mult_plus_distr_l. | |
| rewrite <- !plus_assoc. | |
| ring. | |
| } | |
| apply H4. | |
| Qed. | |
| Lemma lt_ind: | |
| forall (P: nat -> Prop), | |
| (forall m, (forall n, n < m -> P n) -> P m) -> | |
| forall n, P n. | |
| Proof. | |
| intros P IH n. | |
| revert P IH; induction n as [| n IHn]. | |
| - intros; apply IH. | |
| now intros n Hlt; inversion Hlt. | |
| - intros. | |
| apply (IHn (fun n => P (S n))). | |
| intros. | |
| apply IH. | |
| intros n' Hlt. | |
| destruct n' as [| n']. | |
| + apply IH. | |
| intros. | |
| now inversion H0. | |
| + apply lt_S_n in Hlt. | |
| now apply H. | |
| Qed. | |
| (* *) | |
| Theorem nat_to_numerals_to_nat: | |
| forall (n: nat), | |
| numerals_to_nat (nat_to_numerals n) = n. | |
| Proof. | |
| apply lt_ind. | |
| intros n IH. | |
| destruct (n_decomp_10 n) as [q [r [Heq Hlt]]]. | |
| rewrite <- Heq, mult_comm. | |
| destruct q as [| q]. | |
| - | |
| destruct r as [|[|[|[|[|[|[|[|[|[| r]]]]]]]]]]; | |
| try (repeat apply lt_S_n in Hlt; elim (Nat.nlt_0_r _ Hlt)); | |
| now compute. | |
| - rewrite (nat_to_numerals_decomp _ _ Hlt); auto with arith. | |
| rewrite numerals_to_nat_app. | |
| simpl (length _). | |
| simpl (_ ^ _). | |
| assert (numerals_to_nat | |
| (numeral_numerals | |
| (digit_to_ascii (exist (fun m : nat => m < 10) r Hlt))) = r). | |
| { | |
| destruct r as [|[|[|[|[|[|[|[|[|[| r]]]]]]]]]]; | |
| try (generalize Hlt; repeat apply lt_S_n in Hlt; elim (Nat.nlt_0_r _ Hlt)); now compute. | |
| } | |
| rewrite H; clear H. | |
| rewrite (mult_comm 10). | |
| apply f_equal2_plus; auto. | |
| apply f_equal2_mult; auto. | |
| apply IH. | |
| rewrite <- Heq. | |
| omega. | |
| Qed. | |
| (* *) | |
| Fixpoint normalize_numerals_aux (s: string): string := | |
| match s with | |
| | String "0" "" => s | |
| | String "0" s' => normalize_numerals_aux s' | |
| | _ => s | |
| end. | |
| Lemma normalize_numerals_aux_valid: | |
| forall s, numerals s -> numerals (normalize_numerals_aux s). | |
| Proof. | |
| intros s Hs; induction Hs. | |
| - destruct H as [H0 | H]. | |
| + subst c; simpl; auto. | |
| now apply numerals_numeral; unfold numeral; left. | |
| + repeat destruct H as [Heq | H]; subst; try (now elim H); | |
| apply numerals_numeral; unfold numeral; simpl; tauto. | |
| - repeat destruct H as [Heq | H]; subst; try (now elim H); | |
| try (now simpl;inversion Hs; subst; auto); (* for 0 *) | |
| try (now simpl; apply numerals_String; unfold numeral; simpl; tauto). | |
| Qed. | |
| Definition normalize_numerals (s: {s | numerals s}): {s | numerals s} := | |
| let (s, Hs) := s in | |
| exist numerals _ (normalize_numerals_aux_valid _ Hs). | |
| Theorem numerals_to_nat_numerals: | |
| forall (s: string)(Hs: numerals s), | |
| (nat_to_numerals (numerals_to_nat (exist numerals s Hs))) = | |
| (normalize_numerals (exist numerals s Hs)). | |
| Proof. | |
| Admitted. | |
| Lemma irrelevance_exist_eq: | |
| forall (X: Type)(P: X -> Prop)(x y: X)(Hx: P x)(Hy: P y), | |
| x = y -> exist P x Hx = exist P y Hy. | |
| Proof. | |
| intros; subst. | |
| now rewrite (proof_irrelevance _ Hx Hy). | |
| Qed. | |
| Lemma normalize_nothing: | |
| forall (c: ascii)(s: string), | |
| numeral c -> numerals s -> | |
| c <> "0" -> | |
| normalize_numerals_aux (String c s) = String c s. | |
| Proof. | |
| intros c s Hc Hs Hneq. | |
| repeat destruct Hc as [Heq | Hc]; subst; try (now elim Hc); | |
| simpl; auto. | |
| now elim (Hneq (eq_refl _)). | |
| Qed. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment