initial version

cleaned-up the sources of the ITP course
- remove internal notes
- remove exercise solutions
- remove KTH logo
- add Creative Commons license
This commit is contained in:
2019-11-11 10:22:43 +01:00
commit 3c35cc25c3
71 changed files with 35906 additions and 0 deletions

View File

@ -0,0 +1,24 @@
signature dot_graphsLib =
sig
type array_graph
(* binary for running dot *)
val dot_binary : string ref;
(* a fresh, empty one *)
val new_array_graph : array_graph
(* add a node to a graph with number n and the term option content *)
val add_node : array_graph -> int -> Abbrev.term option -> array_graph
(* adds a link between two nodes in the graph *)
val add_node_link : array_graph -> int -> int -> string -> array_graph
(* Various outputs *)
val print_graph : array_graph -> unit
val graph_to_string : array_graph -> string
val show_graph : array_graph -> unit
val write_graph_to_dot_file : array_graph -> string -> unit
val write_graph_to_png_file : array_graph -> string -> unit
end

View File

@ -0,0 +1,62 @@
structure dot_graphsLib :> dot_graphsLib =
struct
open HolKernel Parse
datatype array_graph = AG of string
val new_array_graph = AG "";
(* Auxiliary functions *)
fun AG_add (AG s) s' = AG (s ^ " " ^ s' ^ "\n")
fun node_name n = ("node_"^(int_to_string n))
(* create a new node with number n and value v in graph ag *)
fun add_node ag (n:int) (v : term option) = let
val n_s = node_name n;
val v_s = case v of NONE => "-"
| SOME t => "'" ^ (term_to_string t) ^ "'"
val new_s = (n_s ^ " [label=\"" ^ (int_to_string n) ^": "^v_s^"\"]")
in
AG_add ag new_s
end
(* Add a link between nodes n1 and n2 *)
fun add_node_link ag (n1:int) (n2 : int) (label : string) = let
val new_s = (node_name n1) ^ " -> " ^ (node_name n2) ^ " [label=\""^label^"\"]";
in
AG_add ag new_s
end
fun graph_to_string (AG s) = "digraph G {\n" ^ s ^ "}\n\n"
fun print_graph ag = (TextIO.print (graph_to_string ag))
fun write_graph_to_dot_file ag file_name = let
val os = TextIO.openOut file_name;
val _ = TextIO.output (os, graph_to_string ag);
val _ = TextIO.closeOut os
in
()
end
val dot_binary = ref "/usr/bin/dot";
fun show_graph ag = let
val p = Unix.execute (!dot_binary, ["-Tx11"])
val os = Unix.textOutstreamOf p
val _ = TextIO.output (os, graph_to_string ag)
val _ = TextIO.closeOut os
in
()
end
fun write_graph_to_png_file ag filename = let
val p = Unix.execute (!dot_binary, ["-Tpng", "-o", filename])
val os = Unix.textOutstreamOf p
val _ = TextIO.output (os, graph_to_string ag)
val _ = TextIO.closeOut os
in
()
end
end

View File

@ -0,0 +1,116 @@
structure e4_arraysLib :> e4_arraysLib =
struct
open HolKernel Parse bossLib e4_arraysTheory dot_graphsLib
(* Example
val ag = let
val ag = new_array_graph
val ag = add_node ag 1 NONE
val ag = add_node ag 2 NONE
val ag = add_node ag 3 NONE
val ag = add_node ag 4 (SOME ``A /\ B``)
val ag = add_node ag 5 NONE
val ag = add_node_link ag 1 2 "a";
val ag = add_node_link ag 1 3 "b";
val ag = add_node_link ag 3 4 "c";
val ag = add_node_link ag 4 5 "d";
in
ag
end
val _ = (dot_binary := "/usr/bin/dot");
val _ = print_graph ag
val _ = show_graph ag
*)
fun simple_array n = let
val n_t = numSyntax.term_of_int n
val thm = EVAL ``FOLDL (\a n. UPDATE n a n) EMPTY_ARRAY (COUNT_LIST ^n_t)``
in
rhs (concl thm)
end
fun sparse_array n = let
val n_t = numSyntax.term_of_int n
val thm = EVAL ``FOLDL (\a n. UPDATE n a (n*3)) EMPTY_ARRAY (COUNT_LIST ^n_t)``
in
rhs (concl thm)
end
val a1 = simple_array 10;
val a2 = sparse_array 10;
val a3 = simple_array 20;
val a4 = simple_array 100;
fun is_array_leaf t = same_const t ``Leaf``
fun dest_array_node t = let
val (c, args) = strip_comb t
val _ = if (same_const c ``Node``) then () else fail()
val vo = SOME (optionSyntax.dest_some (el 2 args)) handle HOL_ERR _ => NONE
in
(el 1 args, vo, el 3 args)
end
val is_array_node = can dest_array_node
fun graph_of_array_aux ag level suff t =
if (is_array_leaf t) then (NONE, ag) else
let
val (l, vo, r) = dest_array_node t
val n = level + suff
val m = n - 1;
val ag = add_node ag m vo
val (l_n, ag) = graph_of_array_aux ag (level*2) n l
val ag = case l_n of NONE => ag
| SOME ln => add_node_link ag m ln "l"
val (r_n, ag) = graph_of_array_aux ag (level*2) suff r
val ag = case r_n of NONE => ag
| SOME rn => add_node_link ag m rn "r"
in
(SOME m, ag)
end handle HOL_ERR _ => (NONE, ag)
fun graph_of_array t =
snd (graph_of_array_aux new_array_graph 1 0 t)
show_graph (graph_of_array a1)
show_graph (graph_of_array a2)
print_graph (graph_of_array a1)
EVAL ``num2boolList 5``
a1
Node
(Node (Node Leaf (SOME 6) Leaf)
(SOME 2)
(Node Leaf (SOME 5) Leaf))
(SOME 0)
(Node
(Node Leaf (SOME 4) (Node Leaf (SOME 9) Leaf))
(SOME 1)
(Node (Node Leaf (SOME 8) Leaf) (SOME 3)
(Node Leaf (SOME 7) Leaf)))
end
print_graph (graph_of_array a2);
show_graph (graph_of_array (simple_array 15));

View File

@ -0,0 +1,235 @@
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();