Thomas Tuerk
3c35cc25c3
cleaned-up the sources of the ITP course - remove internal notes - remove exercise solutions - remove KTH logo - add Creative Commons license
236 lines
7.9 KiB
Standard ML
236 lines
7.9 KiB
Standard ML
open HolKernel Parse boolLib bossLib;
|
|
|
|
val _ = new_theory "e4_arrays";
|
|
|
|
|
|
(**************************************************)
|
|
(* Provided part *)
|
|
(**************************************************)
|
|
|
|
val num2boolList_def = Define `
|
|
(num2boolList 0 = []) /\
|
|
(num2boolList 1 = []) /\
|
|
(num2boolList n = (EVEN n) :: num2boolList (n DIV 2))`
|
|
|
|
(* The resulting definition is hard to apply and
|
|
rewriting with it loops easily. So let's provide
|
|
a decent lemma capturing the semantics *)
|
|
|
|
val num2boolList_REWRS = store_thm ("num2boolList_REWRS",
|
|
``(num2boolList 0 = []) /\
|
|
(num2boolList 1 = []) /\
|
|
(!n. 2 <= n ==> ((num2boolList n = (EVEN n) :: num2boolList (n DIV 2))))``,
|
|
REPEAT STRIP_TAC >| [
|
|
METIS_TAC[num2boolList_def],
|
|
METIS_TAC[num2boolList_def],
|
|
|
|
`n <> 0 /\ n <> 1` by DECIDE_TAC >>
|
|
METIS_TAC[num2boolList_def]
|
|
]);
|
|
|
|
|
|
(* It is aslo useful to show when the list is empty *)
|
|
val num2boolList_EQ_NIL = store_thm ("num2boolList_EQ_NIL",
|
|
``!n. (num2boolList n = []) <=> ((n = 0) \/ (n = 1))``,
|
|
GEN_TAC >> EQ_TAC >| [
|
|
REPEAT STRIP_TAC >>
|
|
CCONTR_TAC >>
|
|
FULL_SIMP_TAC list_ss [num2boolList_REWRS],
|
|
|
|
REPEAT STRIP_TAC >> (
|
|
ASM_SIMP_TAC std_ss [num2boolList_REWRS]
|
|
)
|
|
]);
|
|
|
|
|
|
(* Now the awkward arithmetic part. Let's show that num2boolList is injective *)
|
|
|
|
(* For demonstration, let's define our own induction theorem *)
|
|
val MY_NUM_INDUCT = store_thm ("MY_NUM_INDUCT",
|
|
``!P. P 1 /\ (!n. (2 <= n /\ (!m. (m < n /\ m <> 0) ==> P m)) ==> P n) ==> (!n. n <> 0 ==> P n)``,
|
|
REPEAT STRIP_TAC >>
|
|
completeInduct_on `n` >>
|
|
Cases_on `n` >> FULL_SIMP_TAC arith_ss [] >>
|
|
Cases_on `n'` >> ASM_SIMP_TAC arith_ss [])
|
|
|
|
val num2boolList_INJ = store_thm ("num2boolList_INJ",
|
|
``!n. n <> 0 ==> !m. m <> 0 ==> (num2boolList n = num2boolList m) ==> (n = m)``,
|
|
|
|
HO_MATCH_MP_TAC MY_NUM_INDUCT >>
|
|
CONJ_TAC >- (
|
|
SIMP_TAC list_ss [num2boolList_REWRS, num2boolList_EQ_NIL]
|
|
) >>
|
|
GEN_TAC >> STRIP_TAC >> GEN_TAC >> STRIP_TAC >>
|
|
Cases_on `m = 1` >- (
|
|
ASM_SIMP_TAC list_ss [num2boolList_REWRS]
|
|
) >>
|
|
ASM_SIMP_TAC list_ss [num2boolList_REWRS] >>
|
|
REPEAT STRIP_TAC >>
|
|
`n DIV 2 = m DIV 2` by (
|
|
`(m DIV 2 <> 0) /\ (n DIV 2 <> 0) /\ (n DIV 2 < n)` suffices_by METIS_TAC[] >>
|
|
|
|
ASM_SIMP_TAC arith_ss [arithmeticTheory.NOT_ZERO_LT_ZERO,
|
|
arithmeticTheory.X_LT_DIV]
|
|
) >>
|
|
`n MOD 2 = m MOD 2` by (
|
|
ASM_SIMP_TAC std_ss [arithmeticTheory.MOD_2]
|
|
) >>
|
|
`0 < 2` by DECIDE_TAC >>
|
|
METIS_TAC[arithmeticTheory.DIVISION]);
|
|
|
|
|
|
|
|
|
|
(* Shifting the keys by one is trivial and by this we get rid of the
|
|
preconditions of the injectivity theorem *)
|
|
val num2arrayIndex_def = Define `num2arrayIndex n = (num2boolList (SUC n))`
|
|
val num2arrayIndex_INJ = store_thm ("num2arrayIndex_INJ",
|
|
``!n m. (num2arrayIndex n = num2arrayIndex m) <=> (n = m)``,
|
|
|
|
SIMP_TAC list_ss [num2arrayIndex_def] >>
|
|
METIS_TAC [numTheory.NOT_SUC, num2boolList_INJ, numTheory.INV_SUC]);
|
|
|
|
|
|
(* Now let's define the inverse operation *)
|
|
val boolList2num_def = Define `
|
|
(boolList2num [] = 1) /\
|
|
(boolList2num (F::idx) = 2 * boolList2num idx + 1) /\
|
|
(boolList2num (T::idx) = 2 * boolList2num idx)`
|
|
|
|
(* We can show that the inverse is never 0 ... *)
|
|
val boolList2num_GT_0 = prove (``!idx. 0 < boolList2num idx``,
|
|
Induct >- SIMP_TAC arith_ss [boolList2num_def] >>
|
|
Cases >> ASM_SIMP_TAC arith_ss [boolList2num_def]);
|
|
|
|
(* ... so we can subtract 1 for the index shift *)
|
|
val arrayIndex2num_def = Define `arrayIndex2num idx = PRE (boolList2num idx)`
|
|
|
|
|
|
|
|
(* Now a fiddly prove that we indeed defined the inverse *)
|
|
val boolList2num_inv = prove (``!idx. num2boolList (boolList2num idx) = idx``,
|
|
Induct >- (
|
|
SIMP_TAC arith_ss [boolList2num_def, num2boolList_REWRS]
|
|
) >>
|
|
`0 < boolList2num idx` by METIS_TAC[boolList2num_GT_0] >>
|
|
`0 < 2` by DECIDE_TAC >>
|
|
Cases >| [
|
|
`!x. (2 * x) MOD 2 = 0` by
|
|
METIS_TAC[arithmeticTheory.MOD_EQ_0, arithmeticTheory.MULT_COMM] >>
|
|
`!x. (2 * x) DIV 2 = x` by
|
|
METIS_TAC[arithmeticTheory.MULT_DIV, arithmeticTheory.MULT_COMM] >>
|
|
ASM_SIMP_TAC list_ss [boolList2num_def, num2boolList_REWRS,
|
|
arithmeticTheory.EVEN_MOD2],
|
|
|
|
`!x y. (2 * x + y) MOD 2 = (y MOD 2)` by
|
|
METIS_TAC[arithmeticTheory.MOD_TIMES, arithmeticTheory.MULT_COMM] >>
|
|
`!x y. (2 * x + y) DIV 2 = x + y DIV 2` by
|
|
METIS_TAC[arithmeticTheory.ADD_DIV_ADD_DIV, arithmeticTheory.MULT_COMM] >>
|
|
ASM_SIMP_TAC list_ss [boolList2num_def, num2boolList_REWRS,
|
|
arithmeticTheory.EVEN_MOD2]
|
|
]);
|
|
|
|
(* Shifting is easy then *)
|
|
val arrayIndex2num_inv = store_thm ("arrayIndex2num_inv",
|
|
``!idx. num2arrayIndex (arrayIndex2num idx) = idx``,
|
|
GEN_TAC >>
|
|
REWRITE_TAC[num2arrayIndex_def, arrayIndex2num_def] >>
|
|
`0 < boolList2num idx` by METIS_TAC[boolList2num_GT_0] >>
|
|
FULL_SIMP_TAC arith_ss [arithmeticTheory.SUC_PRE] >>
|
|
ASM_SIMP_TAC std_ss [boolList2num_inv]);
|
|
|
|
|
|
(* It is also very easy to derive other useful properties. *)
|
|
val num2arrayIndex_inv = store_thm ("num2arrayIndex_inv",
|
|
``!n. arrayIndex2num (num2arrayIndex n) = n``,
|
|
METIS_TAC[ num2arrayIndex_INJ, arrayIndex2num_inv]);
|
|
|
|
val arrayIndex2num_INJ = store_thm ("arrayIndex2num_INJ",
|
|
``!idx1 idx2. (arrayIndex2num idx1 = arrayIndex2num idx2) <=> (idx1 = idx2)``,
|
|
METIS_TAC[ num2arrayIndex_INJ, arrayIndex2num_inv]);
|
|
|
|
|
|
(* A rewrite for the top-level inverse might be handy *)
|
|
val num2arrayIndex_REWRS = store_thm ("num2arrayIndex_REWRS", ``
|
|
!n. num2arrayIndex n =
|
|
if (n = 0) then [] else
|
|
ODD n :: num2arrayIndex ((n - 1) DIV 2)``,
|
|
|
|
REWRITE_TAC[num2arrayIndex_def] >>
|
|
Cases >> SIMP_TAC arith_ss [num2boolList_REWRS] >>
|
|
SIMP_TAC arith_ss [arithmeticTheory.ODD, arithmeticTheory.EVEN,
|
|
arithmeticTheory.ODD_EVEN] >>
|
|
`(!x r. (2 * x + r) DIV 2 = x + r DIV 2) /\ (!x. (2*x) DIV 2 = x)` by (
|
|
`0 < 2` by DECIDE_TAC >>
|
|
METIS_TAC[arithmeticTheory.ADD_DIV_ADD_DIV, arithmeticTheory.MULT_COMM,
|
|
arithmeticTheory.MULT_DIV]
|
|
) >>
|
|
Cases_on `EVEN n'` >> ASM_REWRITE_TAC[] >| [
|
|
`?m. n' = 2* m` by METIS_TAC[arithmeticTheory.EVEN_ODD_EXISTS] >>
|
|
ASM_SIMP_TAC arith_ss [arithmeticTheory.ADD1],
|
|
|
|
`?m. n' = SUC (2* m)` by METIS_TAC[arithmeticTheory.EVEN_ODD_EXISTS,
|
|
arithmeticTheory.ODD_EVEN] >>
|
|
ASM_SIMP_TAC arith_ss [arithmeticTheory.ADD1]
|
|
]);
|
|
|
|
|
|
(**************************************************)
|
|
(* YOU SHOULD WORK FROM HERE ON *)
|
|
(**************************************************)
|
|
|
|
(* TODO: Define a datatype for arrays storing values of type 'a. *)
|
|
val _ = Datatype `array = DUMMY 'a`
|
|
|
|
|
|
(* TODO: Define a new, empty array *)
|
|
val EMPTY_ARRAY_def = Define `EMPTY_ARRAY : 'a array = ARB`
|
|
|
|
(* TODO: define ILOOKUP, IUPDATE and IREMOVE *)
|
|
val IUPDATE_def = Define `IUPDATE (v : 'a) (a : 'a array) (k : bool list) = a:'a array`
|
|
val ILOOKUP_def = Define `ILOOKUP (a : 'a array) (k : bool list) = NONE:'a option`
|
|
val IREMOVE_def = Define `IREMOVE (a : 'a array) (k : bool list) = a:'a array`
|
|
|
|
|
|
(* With these, we can define the lifted operations *)
|
|
val LOOKUP_def = Define `LOOKUP a n = ILOOKUP a (num2arrayIndex n)`
|
|
val UPDATE_def = Define `UPDATE v a n = IUPDATE v a (num2arrayIndex n)`
|
|
val REMOVE_def = Define `REMOVE a n = IREMOVE a (num2arrayIndex n)`
|
|
|
|
|
|
(* TODO: show a few properties *)
|
|
val LOOKUP_EMPTY = store_thm ("LOOKUP_EMPTY",
|
|
``!k. LOOKUP EMPTY_ARRAY k = NONE``,
|
|
cheat);
|
|
|
|
val LOOKUP_UPDATE = store_thm ("LOOKUP_UPDATE",
|
|
``!v n n' a. LOOKUP (UPDATE v a n) n' =
|
|
(if (n = n') then SOME v else LOOKUP a n')``,
|
|
cheat);
|
|
|
|
val LOOKUP_REMOVE = store_thm ("LOOKUP_REMOVE",
|
|
``!n n' a. LOOKUP (REMOVE a n) n' =
|
|
(if (n = n') then NONE else LOOKUP a n')``,
|
|
cheat);
|
|
|
|
|
|
val UPDATE_REMOVE_EQ = store_thm ("UPDATE_REMOVE_EQ", ``
|
|
(!v1 v2 n a. UPDATE v1 (UPDATE v2 a n) n = UPDATE v1 a n) /\
|
|
(!v n a. UPDATE v (REMOVE a n) n = UPDATE v a n) /\
|
|
(!v n a. REMOVE (UPDATE v a n) n = REMOVE a n)
|
|
``,
|
|
cheat);
|
|
|
|
|
|
val UPDATE_REMOVE_NEQ = store_thm ("UPDATE_REMOVE_NEQ", ``
|
|
(!v1 v2 a n1 n2. n1 <> n2 ==>
|
|
((UPDATE v1 (UPDATE v2 a n2) n1) = (UPDATE v2 (UPDATE v1 a n1) n2))) /\
|
|
(!v a n1 n2. n1 <> n2 ==>
|
|
((UPDATE v (REMOVE a n2) n1) = (REMOVE (UPDATE v a n1) n2))) /\
|
|
(!a n1 n2. n1 <> n2 ==>
|
|
((REMOVE (REMOVE a n2) n1) = (REMOVE (REMOVE a n1) n2)))``,
|
|
cheat);
|
|
|
|
|
|
val _ = export_theory();
|