From 8ab6291e717a1ad0fe77dcabca928491134708e3 Mon Sep 17 00:00:00 2001 From: Son Ho Date: Tue, 24 Jan 2023 00:06:37 +0100 Subject: Add a Holmakefile --- backends/hol4/Holmakefile | 9 + backends/hol4/Primitives.sml | 1358 ---------------------------- backends/hol4/PrimitivesScript.sml | 1356 ++++++++++++++++++++++++++++ backends/hol4/PrimitivesTheory.sig | 1667 ++++++++++++++++++++++++++++++++++ backends/hol4/Test.sml | 1749 ------------------------------------ backends/hol4/TestScript.sml | 1746 +++++++++++++++++++++++++++++++++++ backends/hol4/TestTheory.sig | 839 +++++++++++++++++ 7 files changed, 5617 insertions(+), 3107 deletions(-) create mode 100644 backends/hol4/Holmakefile delete mode 100644 backends/hol4/Primitives.sml create mode 100644 backends/hol4/PrimitivesScript.sml create mode 100644 backends/hol4/PrimitivesTheory.sig delete mode 100644 backends/hol4/Test.sml create mode 100644 backends/hol4/TestScript.sml create mode 100644 backends/hol4/TestTheory.sig (limited to 'backends/hol4') diff --git a/backends/hol4/Holmakefile b/backends/hol4/Holmakefile new file mode 100644 index 00000000..49cc6da7 --- /dev/null +++ b/backends/hol4/Holmakefile @@ -0,0 +1,9 @@ +INCLUDES = + +all: $(DEFAULT_TARGETS) +.PHONY: all + +README_SOURCES = $(wildcard *Script.sml) $(wildcard *Lib.sml) $(wildcard *Syntax.sml) +DIRS = $(wildcard */) +README.md: $(README_SOURCES) + $(README_SOURCES) diff --git a/backends/hol4/Primitives.sml b/backends/hol4/Primitives.sml deleted file mode 100644 index be384012..00000000 --- a/backends/hol4/Primitives.sml +++ /dev/null @@ -1,1358 +0,0 @@ -open HolKernel boolLib bossLib Parse -open boolTheory arithmeticTheory integerTheory intLib listTheory stringTheory - -val primitives_theory_name = "Primitives" -val _ = new_theory primitives_theory_name - -(* TODO: val _ = export_theory(); *) - -(*** Result *) -Datatype: - error = Failure -End - -Datatype: - result = Return 'a | Fail error | Loop -End - -Type M = ``: 'a result`` - -val bind_def = Define ` - (bind : 'a M -> ('a -> 'b M) -> 'b M) x f = - case x of - Return y => f y - | Fail e => Fail e - | Loop => Loop`; - -val bind_name = fst (dest_const “bind”) - -val return_def = Define ` - (return : 'a -> 'a M) x = - Return x`; - -val massert_def = Define ‘massert b = if b then Return () else Fail Failure’ - -Overload monad_bind = ``bind`` -Overload monad_unitbind = ``\x y. bind x (\z. y)`` -Overload monad_ignore_bind = ``\x y. bind x (\z. y)`` - -(* Allow the use of monadic syntax *) -val _ = monadsyntax.enable_monadsyntax () - -(*** Misc *) -Type char = “:char” -Type string = “:string” - -val mem_replace_fwd_def = Define ‘mem_replace_fwd (x : 'a) (y :'a) : 'a = x’ -val mem_replace_back_def = Define ‘mem_replace_back (x : 'a) (y :'a) : 'a = y’ - -(*** Scalars *) -(* Remark: most of the following code was partially generated *) - -(* The bounds for the isize/usize types are opaque, because they vary with - the architecture *) -val _ = new_constant ("isize_min", “:int”) -val _ = new_constant ("isize_max", “:int”) -val _ = new_constant ("usize_max", “:int”) - -val _ = new_type ("usize", 0) -val _ = new_type ("u8", 0) -val _ = new_type ("u16", 0) -val _ = new_type ("u32", 0) -val _ = new_type ("u64", 0) -val _ = new_type ("u128", 0) -val _ = new_type ("isize", 0) -val _ = new_type ("i8", 0) -val _ = new_type ("i16", 0) -val _ = new_type ("i32", 0) -val _ = new_type ("i64", 0) -val _ = new_type ("i128", 0) - -val _ = new_constant ("isize_to_int", “:isize -> int”) -val _ = new_constant ("i8_to_int", “:i8 -> int”) -val _ = new_constant ("i16_to_int", “:i16 -> int”) -val _ = new_constant ("i32_to_int", “:i32 -> int”) -val _ = new_constant ("i64_to_int", “:i64 -> int”) -val _ = new_constant ("i128_to_int", “:i128 -> int”) -val _ = new_constant ("usize_to_int", “:usize -> int”) -val _ = new_constant ("u8_to_int", “:u8 -> int”) -val _ = new_constant ("u16_to_int", “:u16 -> int”) -val _ = new_constant ("u32_to_int", “:u32 -> int”) -val _ = new_constant ("u64_to_int", “:u64 -> int”) -val _ = new_constant ("u128_to_int", “:u128 -> int”) - -val _ = new_constant ("int_to_isize", “:int -> isize”) -val _ = new_constant ("int_to_i8", “:int -> i8”) -val _ = new_constant ("int_to_i16", “:int -> i16”) -val _ = new_constant ("int_to_i32", “:int -> i32”) -val _ = new_constant ("int_to_i64", “:int -> i64”) -val _ = new_constant ("int_to_i128", “:int -> i128”) -val _ = new_constant ("int_to_usize", “:int -> usize”) -val _ = new_constant ("int_to_u8", “:int -> u8”) -val _ = new_constant ("int_to_u16", “:int -> u16”) -val _ = new_constant ("int_to_u32", “:int -> u32”) -val _ = new_constant ("int_to_u64", “:int -> u64”) -val _ = new_constant ("int_to_u128", “:int -> u128”) - -(* The bounds *) -val i8_min_def = Define ‘i8_min = (-128:int)’ -val i8_max_def = Define ‘i8_max = (127:int)’ -val i16_min_def = Define ‘i16_min = (-32768:int)’ -val i16_max_def = Define ‘i16_max = (32767:int)’ -val i32_min_def = Define ‘i32_min = (-2147483648:int)’ -val i32_max_def = Define ‘i32_max = (2147483647:int)’ -val i64_min_def = Define ‘i64_min = (-9223372036854775808:int)’ -val i64_max_def = Define ‘i64_max = (9223372036854775807:int)’ -val i128_min_def = Define ‘i128_min = (-170141183460469231731687303715884105728:int)’ -val i128_max_def = Define ‘i128_max = (170141183460469231731687303715884105727:int)’ -val u8_max_def = Define ‘u8_max = (255:int)’ -val u16_max_def = Define ‘u16_max = (65535:int)’ -val u32_max_def = Define ‘u32_max = (4294967295:int)’ -val u64_max_def = Define ‘u64_max = (18446744073709551615:int)’ -val u128_max_def = Define ‘u128_max = (340282366920938463463374607431768211455:int)’ - -val all_bound_defs = [ - i8_min_def, i8_max_def, - i16_min_def, i16_max_def, - i32_min_def, i32_max_def, - i64_min_def, i64_max_def, - i128_min_def, i128_max_def, - u8_max_def, - u16_max_def, - u32_max_def, - u64_max_def, - u128_max_def -] - -(* The following bounds are valid for all architectures *) -val isize_bounds = new_axiom ("isize_bounds", “isize_min <= i16_min /\ isize_max >= i16_max”) -val usize_bounds = new_axiom ("usize_bounds", “usize_max >= u16_max”) - -(* Conversion bounds *) -val isize_to_int_bounds = new_axiom ("isize_to_int_bounds", - “!n. isize_min <= isize_to_int n /\ isize_to_int n <= isize_max”) - -val i8_to_int_bounds = new_axiom ("i8_to_int_bounds", - “!n. i8_min <= i8_to_int n /\ i8_to_int n <= i8_max”) - -val i16_to_int_bounds = new_axiom ("i16_to_int_bounds", - “!n. i16_min <= i16_to_int n /\ i16_to_int n <= i16_max”) - -val i32_to_int_bounds = new_axiom ("i32_to_int_bounds", - “!n. i32_min <= i32_to_int n /\ i32_to_int n <= i32_max”) - -val i64_to_int_bounds = new_axiom ("i64_to_int_bounds", - “!n. i64_min <= i64_to_int n /\ i64_to_int n <= i64_max”) - -val i128_to_int_bounds = new_axiom ("i128_to_int_bounds", - “!n. i128_min <= i128_to_int n /\ i128_to_int n <= i128_max”) - -val usize_to_int_bounds = new_axiom ("usize_to_int_bounds", - “!n. 0 <= usize_to_int n /\ usize_to_int n <= usize_max”) - -val u8_to_int_bounds = new_axiom ("u8_to_int_bounds", - “!n. 0 <= u8_to_int n /\ u8_to_int n <= u8_max”) - -val u16_to_int_bounds = new_axiom ("u16_to_int_bounds", - “!n. 0 <= u16_to_int n /\ u16_to_int n <= u16_max”) - -val u32_to_int_bounds = new_axiom ("u32_to_int_bounds", - “!n. 0 <= u32_to_int n /\ u32_to_int n <= u32_max”) - -val u64_to_int_bounds = new_axiom ("u64_to_int_bounds", - “!n. 0 <= u64_to_int n /\ u64_to_int n <= u64_max”) - -val u128_to_int_bounds = new_axiom ("u128_to_int_bounds", - “!n. 0 <= u128_to_int n /\ u128_to_int n <= u128_max”) - -val all_to_int_bounds_lemmas = [ - isize_to_int_bounds, - i8_to_int_bounds, - i16_to_int_bounds, - i32_to_int_bounds, - i64_to_int_bounds, - i128_to_int_bounds, - usize_to_int_bounds, - u8_to_int_bounds, - u16_to_int_bounds, - u32_to_int_bounds, - u64_to_int_bounds, - u128_to_int_bounds -] - -(* Conversion to and from int. - - Note that for isize and usize, we write the lemmas in such a way that the - proofs are easily automatable for constants. - *) -val int_to_isize_id = - new_axiom ("int_to_isize_id", - “!n. (i16_min <= n \/ isize_min <= n) /\ (n <= i16_max \/ n <= isize_max) ==> - isize_to_int (int_to_isize n) = n”) - -val int_to_usize_id = - new_axiom ("int_to_usize_id", - “!n. 0 <= n /\ (n <= u16_max \/ n <= usize_max) ==> usize_to_int (int_to_usize n) = n”) - -val int_to_i8_id = - new_axiom ("int_to_i8_id", - “!n. i8_min <= n /\ n <= i8_max ==> i8_to_int (int_to_i8 n) = n”) - -val int_to_i16_id = - new_axiom ("int_to_i16_id", - “!n. i16_min <= n /\ n <= i16_max ==> i16_to_int (int_to_i16 n) = n”) - -val int_to_i32_id = - new_axiom ("int_to_i32_id", - “!n. i32_min <= n /\ n <= i32_max ==> i32_to_int (int_to_i32 n) = n”) - -val int_to_i64_id = - new_axiom ("int_to_i64_id", - “!n. i64_min <= n /\ n <= i64_max ==> i64_to_int (int_to_i64 n) = n”) - -val int_to_i128_id = - new_axiom ("int_to_i128_id", - “!n. i128_min <= n /\ n <= i128_max ==> i128_to_int (int_to_i128 n) = n”) - -val int_to_u8_id = - new_axiom ("int_to_u8_id", - “!n. 0 <= n /\ n <= u8_max ==> u8_to_int (int_to_u8 n) = n”) - -val int_to_u16_id = - new_axiom ("int_to_u16_id", - “!n. 0 <= n /\ n <= u16_max ==> u16_to_int (int_to_u16 n) = n”) - -val int_to_u32_id = - new_axiom ("int_to_u32_id", - “!n. 0 <= n /\ n <= u32_max ==> u32_to_int (int_to_u32 n) = n”) - -val int_to_u64_id = - new_axiom ("int_to_u64_id", - “!n. 0 <= n /\ n <= u64_max ==> u64_to_int (int_to_u64 n) = n”) - -val int_to_u128_id = - new_axiom ("int_to_u128_id", - “!n. 0 <= n /\ n <= u128_max ==> u128_to_int (int_to_u128 n) = n”) - -val all_conversion_id_lemmas = [ - int_to_isize_id, - int_to_i8_id, - int_to_i16_id, - int_to_i32_id, - int_to_i64_id, - int_to_i128_id, - int_to_usize_id, - int_to_u8_id, - int_to_u16_id, - int_to_u32_id, - int_to_u64_id, - int_to_u128_id -] - -(** Utilities to define the arithmetic operations *) -val mk_isize_def = Define - ‘mk_isize n = - if isize_min <= n /\ n <= isize_max then Return (int_to_isize n) - else Fail Failure’ - -val mk_i8_def = Define - ‘mk_i8 n = - if i8_min <= n /\ n <= i8_max then Return (int_to_i8 n) - else Fail Failure’ - -val mk_i16_def = Define - ‘mk_i16 n = - if i16_min <= n /\ n <= i16_max then Return (int_to_i16 n) - else Fail Failure’ - -val mk_i32_def = Define - ‘mk_i32 n = - if i32_min <= n /\ n <= i32_max then Return (int_to_i32 n) - else Fail Failure’ - -val mk_i64_def = Define - ‘mk_i64 n = - if i64_min <= n /\ n <= i64_max then Return (int_to_i64 n) - else Fail Failure’ - -val mk_i128_def = Define - ‘mk_i128 n = - if i128_min <= n /\ n <= i128_max then Return (int_to_i128 n) - else Fail Failure’ - -val mk_usize_def = Define - ‘mk_usize n = - if 0 <= n /\ n <= usize_max then Return (int_to_usize n) - else Fail Failure’ - -val mk_u8_def = Define - ‘mk_u8 n = - if 0 <= n /\ n <= u8_max then Return (int_to_u8 n) - else Fail Failure’ - -val mk_u16_def = Define - ‘mk_u16 n = - if 0 <= n /\ n <= u16_max then Return (int_to_u16 n) - else Fail Failure’ - -val mk_u32_def = Define - ‘mk_u32 n = - if 0 <= n /\ n <= u32_max then Return (int_to_u32 n) - else Fail Failure’ - -val mk_u64_def = Define - ‘mk_u64 n = - if 0 <= n /\ n <= u64_max then Return (int_to_u64 n) - else Fail Failure’ - -val mk_u128_def = Define - ‘mk_u128 n = - if 0 <= n /\ n <= u128_max then Return (int_to_u128 n) - else Fail Failure’ - -val all_mk_int_defs = [ - mk_isize_def, - mk_i8_def, - mk_i16_def, - mk_i32_def, - mk_i64_def, - mk_i128_def, - mk_usize_def, - mk_u8_def, - mk_u16_def, - mk_u32_def, - mk_u64_def, - mk_u128_def -] - - -val isize_add_def = Define ‘isize_add x y = mk_isize ((isize_to_int x) + (isize_to_int y))’ -val i8_add_def = Define ‘i8_add x y = mk_i8 ((i8_to_int x) + (i8_to_int y))’ -val i16_add_def = Define ‘i16_add x y = mk_i16 ((i16_to_int x) + (i16_to_int y))’ -val i32_add_def = Define ‘i32_add x y = mk_i32 ((i32_to_int x) + (i32_to_int y))’ -val i64_add_def = Define ‘i64_add x y = mk_i64 ((i64_to_int x) + (i64_to_int y))’ -val i128_add_def = Define ‘i128_add x y = mk_i128 ((i128_to_int x) + (i128_to_int y))’ -val usize_add_def = Define ‘usize_add x y = mk_usize ((usize_to_int x) + (usize_to_int y))’ -val u8_add_def = Define ‘u8_add x y = mk_u8 ((u8_to_int x) + (u8_to_int y))’ -val u16_add_def = Define ‘u16_add x y = mk_u16 ((u16_to_int x) + (u16_to_int y))’ -val u32_add_def = Define ‘u32_add x y = mk_u32 ((u32_to_int x) + (u32_to_int y))’ -val u64_add_def = Define ‘u64_add x y = mk_u64 ((u64_to_int x) + (u64_to_int y))’ -val u128_add_def = Define ‘u128_add x y = mk_u128 ((u128_to_int x) + (u128_to_int y))’ - -val all_add_defs = [ - isize_add_def, - i8_add_def, - i16_add_def, - i32_add_def, - i64_add_def, - i128_add_def, - usize_add_def, - u8_add_def, - u16_add_def, - u32_add_def, - u64_add_def, - u128_add_def -] - -val isize_sub_def = Define ‘isize_sub x y = mk_isize ((isize_to_int x) - (isize_to_int y))’ -val i8_sub_def = Define ‘i8_sub x y = mk_i8 ((i8_to_int x) - (i8_to_int y))’ -val i16_sub_def = Define ‘i16_sub x y = mk_i16 ((i16_to_int x) - (i16_to_int y))’ -val i32_sub_def = Define ‘i32_sub x y = mk_i32 ((i32_to_int x) - (i32_to_int y))’ -val i64_sub_def = Define ‘i64_sub x y = mk_i64 ((i64_to_int x) - (i64_to_int y))’ -val i128_sub_def = Define ‘i128_sub x y = mk_i128 ((i128_to_int x) - (i128_to_int y))’ -val usize_sub_def = Define ‘usize_sub x y = mk_usize ((usize_to_int x) - (usize_to_int y))’ -val u8_sub_def = Define ‘u8_sub x y = mk_u8 ((u8_to_int x) - (u8_to_int y))’ -val u16_sub_def = Define ‘u16_sub x y = mk_u16 ((u16_to_int x) - (u16_to_int y))’ -val u32_sub_def = Define ‘u32_sub x y = mk_u32 ((u32_to_int x) - (u32_to_int y))’ -val u64_sub_def = Define ‘u64_sub x y = mk_u64 ((u64_to_int x) - (u64_to_int y))’ -val u128_sub_def = Define ‘u128_sub x y = mk_u128 ((u128_to_int x) - (u128_to_int y))’ - -val all_sub_defs = [ - isize_sub_def, - i8_sub_def, - i16_sub_def, - i32_sub_def, - i64_sub_def, - i128_sub_def, - usize_sub_def, - u8_sub_def, - u16_sub_def, - u32_sub_def, - u64_sub_def, - u128_sub_def -] - -val isize_mul_def = Define ‘isize_mul x y = mk_isize ((isize_to_int x) * (isize_to_int y))’ -val i8_mul_def = Define ‘i8_mul x y = mk_i8 ((i8_to_int x) * (i8_to_int y))’ -val i16_mul_def = Define ‘i16_mul x y = mk_i16 ((i16_to_int x) * (i16_to_int y))’ -val i32_mul_def = Define ‘i32_mul x y = mk_i32 ((i32_to_int x) * (i32_to_int y))’ -val i64_mul_def = Define ‘i64_mul x y = mk_i64 ((i64_to_int x) * (i64_to_int y))’ -val i128_mul_def = Define ‘i128_mul x y = mk_i128 ((i128_to_int x) * (i128_to_int y))’ -val usize_mul_def = Define ‘usize_mul x y = mk_usize ((usize_to_int x) * (usize_to_int y))’ -val u8_mul_def = Define ‘u8_mul x y = mk_u8 ((u8_to_int x) * (u8_to_int y))’ -val u16_mul_def = Define ‘u16_mul x y = mk_u16 ((u16_to_int x) * (u16_to_int y))’ -val u32_mul_def = Define ‘u32_mul x y = mk_u32 ((u32_to_int x) * (u32_to_int y))’ -val u64_mul_def = Define ‘u64_mul x y = mk_u64 ((u64_to_int x) * (u64_to_int y))’ -val u128_mul_def = Define ‘u128_mul x y = mk_u128 ((u128_to_int x) * (u128_to_int y))’ - -val all_mul_defs = [ - isize_mul_def, - i8_mul_def, - i16_mul_def, - i32_mul_def, - i64_mul_def, - i128_mul_def, - usize_mul_def, - u8_mul_def, - u16_mul_def, - u32_mul_def, - u64_mul_def, - u128_mul_def -] - -val isize_div_def = Define ‘isize_div x y = - if isize_to_int y = 0 then Fail Failure else mk_isize ((isize_to_int x) / (isize_to_int y))’ -val i8_div_def = Define ‘i8_div x y = - if i8_to_int y = 0 then Fail Failure else mk_i8 ((i8_to_int x) / (i8_to_int y))’ -val i16_div_def = Define ‘i16_div x y = - if i16_to_int y = 0 then Fail Failure else mk_i16 ((i16_to_int x) / (i16_to_int y))’ -val i32_div_def = Define ‘i32_div x y = - if i32_to_int y = 0 then Fail Failure else mk_i32 ((i32_to_int x) / (i32_to_int y))’ -val i64_div_def = Define ‘i64_div x y = - if i64_to_int y = 0 then Fail Failure else mk_i64 ((i64_to_int x) / (i64_to_int y))’ -val i128_div_def = Define ‘i128_div x y = - if i128_to_int y = 0 then Fail Failure else mk_i128 ((i128_to_int x) / (i128_to_int y))’ -val usize_div_def = Define ‘usize_div x y = - if usize_to_int y = 0 then Fail Failure else mk_usize ((usize_to_int x) / (usize_to_int y))’ -val u8_div_def = Define ‘u8_div x y = - if u8_to_int y = 0 then Fail Failure else mk_u8 ((u8_to_int x) / (u8_to_int y))’ -val u16_div_def = Define ‘u16_div x y = - if u16_to_int y = 0 then Fail Failure else mk_u16 ((u16_to_int x) / (u16_to_int y))’ -val u32_div_def = Define ‘u32_div x y = - if u32_to_int y = 0 then Fail Failure else mk_u32 ((u32_to_int x) / (u32_to_int y))’ -val u64_div_def = Define ‘u64_div x y = - if u64_to_int y = 0 then Fail Failure else mk_u64 ((u64_to_int x) / (u64_to_int y))’ -val u128_div_def = Define ‘u128_div x y = - if u128_to_int y = 0 then Fail Failure else mk_u128 ((u128_to_int x) / (u128_to_int y))’ - -val all_div_defs = [ - isize_div_def, - i8_div_def, - i16_div_def, - i32_div_def, - i64_div_def, - i128_div_def, - usize_div_def, - u8_div_def, - u16_div_def, - u32_div_def, - u64_div_def, - u128_div_def -] - -(* The remainder operation is not a modulo. - - In Rust, the remainder has the sign of the dividend. - In HOL4, it has the sign of the divisor. - *) -val int_rem_def = Define ‘int_rem (x : int) (y : int) : int = - if (x >= 0 /\ y >= 0) \/ (x < 0 /\ y < 0) then x % y else -(x % y)’ - -(* Checking consistency with Rust *) -val _ = prove(“int_rem 1 2 = 1”, EVAL_TAC) -val _ = prove(“int_rem (-1) 2 = -1”, EVAL_TAC) -val _ = prove(“int_rem 1 (-2) = 1”, EVAL_TAC) -val _ = prove(“int_rem (-1) (-2) = -1”, EVAL_TAC) - -val isize_rem_def = Define ‘isize_rem x y = - if isize_to_int y = 0 then Fail Failure else mk_isize (int_rem (isize_to_int x) (isize_to_int y))’ -val i8_rem_def = Define ‘i8_rem x y = - if i8_to_int y = 0 then Fail Failure else mk_i8 (int_rem (i8_to_int x) (i8_to_int y))’ -val i16_rem_def = Define ‘i16_rem x y = - if i16_to_int y = 0 then Fail Failure else mk_i16 (int_rem (i16_to_int x) (i16_to_int y))’ -val i32_rem_def = Define ‘i32_rem x y = - if i32_to_int y = 0 then Fail Failure else mk_i32 (int_rem (i32_to_int x) (i32_to_int y))’ -val i64_rem_def = Define ‘i64_rem x y = - if i64_to_int y = 0 then Fail Failure else mk_i64 (int_rem (i64_to_int x) (i64_to_int y))’ -val i128_rem_def = Define ‘i128_rem x y = - if i128_to_int y = 0 then Fail Failure else mk_i128 (int_rem (i128_to_int x) (i128_to_int y))’ -val usize_rem_def = Define ‘usize_rem x y = - if usize_to_int y = 0 then Fail Failure else mk_usize (int_rem (usize_to_int x) (usize_to_int y))’ -val u8_rem_def = Define ‘u8_rem x y = - if u8_to_int y = 0 then Fail Failure else mk_u8 (int_rem (u8_to_int x) (u8_to_int y))’ -val u16_rem_def = Define ‘u16_rem x y = - if u16_to_int y = 0 then Fail Failure else mk_u16 (int_rem (u16_to_int x) (u16_to_int y))’ -val u32_rem_def = Define ‘u32_rem x y = - if u32_to_int y = 0 then Fail Failure else mk_u32 (int_rem (u32_to_int x) (u32_to_int y))’ -val u64_rem_def = Define ‘u64_rem x y = - if u64_to_int y = 0 then Fail Failure else mk_u64 (int_rem (u64_to_int x) (u64_to_int y))’ -val u128_rem_def = Define ‘u128_rem x y = - if u128_to_int y = 0 then Fail Failure else mk_u128 (int_rem (u128_to_int x) (u128_to_int y))’ - -val all_rem_defs = [ - isize_rem_def, - i8_rem_def, - i16_rem_def, - i32_rem_def, - i64_rem_def, - i128_rem_def, - usize_rem_def, - u8_rem_def, - u16_rem_def, - u32_rem_def, - u64_rem_def, - u128_rem_def -] - -(* Ignore a theorem. - - To be used in conjunction with {!pop_assum} for instance. - *) -fun IGNORE_TAC (_ : thm) : tactic = ALL_TAC - -val POP_IGNORE_TAC = POP_ASSUM IGNORE_TAC - -(* TODO: we need a better library of lemmas about arithmetic *) - -(* TODO: add those as rewriting tactics by default *) -val NOT_LE_EQ_GT = store_thm("NOT_LE_EQ_GT", “!(x y: int). ~(x <= y) <=> x > y”, COOPER_TAC) -val NOT_LT_EQ_GE = store_thm("NOT_LT_EQ_GE", “!(x y: int). ~(x < y) <=> x >= y”, COOPER_TAC) -val NOT_GE_EQ_LT = store_thm("NOT_GE_EQ_LT", “!(x y: int). ~(x >= y) <=> x < y”, COOPER_TAC) -val NOT_GT_EQ_LE = store_thm("NOT_GT_EQ_LE", “!(x y: int). ~(x > y) <=> x <= y”, COOPER_TAC) - -Theorem POS_MUL_POS_IS_POS: - !(x y : int). 0 <= x ==> 0 <= y ==> 0 <= x * y -Proof - rpt strip_tac >> - sg ‘0 <= &(Num x) * &(Num y)’ >- (rw [INT_MUL_CALCULATE] >> COOPER_TAC) >> - sg ‘&(Num x) = x’ >- (irule EQ_SYM >> rw [INT_OF_NUM] >> COOPER_TAC) >> - sg ‘&(Num y) = y’ >- (irule EQ_SYM >> rw [INT_OF_NUM] >> COOPER_TAC) >> - metis_tac[] -QED - -val GE_EQ_LE = store_thm("GE_EQ_LE", “!(x y : int). x >= y <=> y <= x”, COOPER_TAC) -val LE_EQ_GE = store_thm("LE_EQ_GE", “!(x y : int). x <= y <=> y >= x”, COOPER_TAC) -val GT_EQ_LT = store_thm("GT_EQ_LT", “!(x y : int). x > y <=> y < x”, COOPER_TAC) -val LT_EQ_GT = store_thm("LT_EQ_GT", “!(x y : int). x < y <=> y > x”, COOPER_TAC) - -Theorem POS_DIV_POS_IS_POS: - !(x y : int). 0 <= x ==> 0 < y ==> 0 <= x / y -Proof - rpt strip_tac >> - rw [LE_EQ_GE] >> - sg ‘y <> 0’ >- COOPER_TAC >> - qspecl_then [‘\x. x >= 0’, ‘x’, ‘y’] ASSUME_TAC INT_DIV_FORALL_P >> - fs [] >> POP_IGNORE_TAC >> rw [] >- COOPER_TAC >> - fs [NOT_LT_EQ_GE] >> - (* Proof by contradiction: assume k < 0 *) - spose_not_then ASSUME_TAC >> - fs [NOT_GE_EQ_LT] >> - sg ‘k * y = (k + 1) * y + - y’ >- (fs [INT_RDISTRIB] >> COOPER_TAC) >> - sg ‘0 <= (-(k + 1)) * y’ >- (irule POS_MUL_POS_IS_POS >> COOPER_TAC) >> - COOPER_TAC -QED - -Theorem POS_DIV_POS_LE: - !(x y d : int). 0 <= x ==> 0 <= y ==> 0 < d ==> x <= y ==> x / d <= y / d -Proof - rpt strip_tac >> - sg ‘d <> 0’ >- COOPER_TAC >> - qspecl_then [‘\k. k = x / d’, ‘x’, ‘d’] ASSUME_TAC INT_DIV_P >> - qspecl_then [‘\k. k = y / d’, ‘y’, ‘d’] ASSUME_TAC INT_DIV_P >> - rfs [NOT_LT_EQ_GE] >> TRY COOPER_TAC >> - sg ‘y = (x / d) * d + (r' + y - x)’ >- COOPER_TAC >> - qspecl_then [‘(x / d) * d’, ‘r' + y - x’, ‘d’] ASSUME_TAC INT_ADD_DIV >> - rfs [] >> - Cases_on ‘x = y’ >- fs [] >> - sg ‘r' + y ≠ x’ >- COOPER_TAC >> fs [] >> - sg ‘((x / d) * d) / d = x / d’ >- (irule INT_DIV_RMUL >> COOPER_TAC) >> - fs [] >> - sg ‘0 <= (r' + y − x) / d’ >- (irule POS_DIV_POS_IS_POS >> COOPER_TAC) >> - metis_tac [INT_LE_ADDR] -QED - -Theorem POS_DIV_POS_LE_INIT: - !(x y : int). 0 <= x ==> 0 < y ==> x / y <= x -Proof - rpt strip_tac >> - sg ‘y <> 0’ >- COOPER_TAC >> - qspecl_then [‘\k. k = x / y’, ‘x’, ‘y’] ASSUME_TAC INT_DIV_P >> - rfs [NOT_LT_EQ_GE] >- COOPER_TAC >> - sg ‘y = (y - 1) + 1’ >- rw [] >> - sg ‘x = x / y + ((x / y) * (y - 1) + r)’ >-( - qspecl_then [‘1’, ‘y-1’, ‘x / y’] ASSUME_TAC INT_LDISTRIB >> - rfs [] >> - COOPER_TAC - ) >> - sg ‘!a b c. 0 <= c ==> a = b + c ==> b <= a’ >- (COOPER_TAC) >> - pop_assum irule >> - exists_tac “x / y * (y − 1) + r” >> - sg ‘0 <= x / y’ >- (irule POS_DIV_POS_IS_POS >> COOPER_TAC) >> - sg ‘0 <= (x / y) * (y - 1)’ >- (irule POS_MUL_POS_IS_POS >> COOPER_TAC) >> - COOPER_TAC -QED - -Theorem POS_MOD_POS_IS_POS: - !(x y : int). 0 <= x ==> 0 < y ==> 0 <= x % y -Proof - rpt strip_tac >> - sg ‘y <> 0’ >- COOPER_TAC >> - imp_res_tac INT_DIVISION >> - first_x_assum (qspec_then ‘x’ assume_tac) >> - first_x_assum (qspec_then ‘x’ assume_tac) >> - sg ‘~(y < 0)’ >- COOPER_TAC >> fs [] -QED - -Theorem POS_MOD_POS_LE_INIT: - !(x y : int). 0 <= x ==> 0 < y ==> x % y <= x -Proof - rpt strip_tac >> - sg ‘y <> 0’ >- COOPER_TAC >> - imp_res_tac INT_DIVISION >> - first_x_assum (qspec_then ‘x’ assume_tac) >> - first_x_assum (qspec_then ‘x’ assume_tac) >> - sg ‘~(y < 0)’ >- COOPER_TAC >> fs [] >> - sg ‘0 <= x % y’ >- (irule POS_MOD_POS_IS_POS >> COOPER_TAC) >> - sg ‘0 <= x / y’ >- (irule POS_DIV_POS_IS_POS >> COOPER_TAC) >> - sg ‘0 <= (x / y) * y’ >- (irule POS_MUL_POS_IS_POS >> COOPER_TAC) >> - COOPER_TAC -QED - -(* -val (asms,g) = top_goal () -*) - -fun prove_arith_op_eq (asms, g) = - let - val (_, t) = (dest_exists o snd o strip_imp o snd o strip_forall) g; - val (x_to_int, y_to_int) = - case (snd o strip_comb o rhs o snd o dest_conj) t of - [x, y] => (x,y) - | _ => failwith "Unexpected" - val x = (snd o dest_comb) x_to_int; - val y = (snd o dest_comb) y_to_int; - fun inst_first_lem arg lems = - MAP_FIRST (fn th => (ASSUME_TAC (SPEC arg th) handle HOL_ERR _ => FAIL_TAC "")) lems; - in - (rpt gen_tac >> - rpt DISCH_TAC >> - ASSUME_TAC usize_bounds >> (* Only useful for usize of course *) - ASSUME_TAC isize_bounds >> (* Only useful for isize of course *) - rw (int_rem_def :: List.concat [all_rem_defs, all_add_defs, all_sub_defs, all_mul_defs, all_div_defs, all_mk_int_defs, all_to_int_bounds_lemmas, all_conversion_id_lemmas]) >> - fs (int_rem_def :: List.concat [all_rem_defs, all_add_defs, all_sub_defs, all_mul_defs, all_div_defs, all_mk_int_defs, all_to_int_bounds_lemmas, all_conversion_id_lemmas]) >> - inst_first_lem x all_to_int_bounds_lemmas >> - inst_first_lem y all_to_int_bounds_lemmas >> - gs [NOT_LE_EQ_GT, NOT_LT_EQ_GE, NOT_GE_EQ_LT, NOT_GT_EQ_LE, GE_EQ_LE, GT_EQ_LT] >> - TRY COOPER_TAC >> - FIRST [ - (* For division *) - qspecl_then [‘^x_to_int’, ‘^y_to_int’] ASSUME_TAC POS_DIV_POS_IS_POS >> - qspecl_then [‘^x_to_int’, ‘^y_to_int’] ASSUME_TAC POS_DIV_POS_LE_INIT >> - COOPER_TAC, - (* For remainder *) - dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC all_conversion_id_lemmas >> fs [] >> - qspecl_then [‘^x_to_int’, ‘^y_to_int’] ASSUME_TAC POS_MOD_POS_IS_POS >> - qspecl_then [‘^x_to_int’, ‘^y_to_int’] ASSUME_TAC POS_MOD_POS_LE_INIT >> - COOPER_TAC, - dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC all_conversion_id_lemmas >> fs [] - ]) (asms, g) - end - -Theorem U8_ADD_EQ: - !x y. - u8_to_int x + u8_to_int y <= u8_max ==> - ?z. u8_add x y = Return z /\ u8_to_int z = u8_to_int x + u8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U16_ADD_EQ: - !x y. - u16_to_int x + u16_to_int y <= u16_max ==> - ?z. u16_add x y = Return z /\ u16_to_int z = u16_to_int x + u16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U32_ADD_EQ: - !x y. - u32_to_int x + u32_to_int y <= u32_max ==> - ?z. u32_add x y = Return z /\ u32_to_int z = u32_to_int x + u32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U64_ADD_EQ: - !x y. - u64_to_int x + u64_to_int y <= u64_max ==> - ?z. u64_add x y = Return z /\ u64_to_int z = u64_to_int x + u64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U128_ADD_EQ: - !x y. - u128_to_int x + u128_to_int y <= u128_max ==> - ?z. u128_add x y = Return z /\ u128_to_int z = u128_to_int x + u128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem USIZE_ADD_EQ: - !x y. - (usize_to_int x + usize_to_int y <= u16_max) \/ (usize_to_int x + usize_to_int y <= usize_max) ==> - ?z. usize_add x y = Return z /\ usize_to_int z = usize_to_int x + usize_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I8_ADD_EQ: - !x y. - i8_min <= i8_to_int x + i8_to_int y ==> - i8_to_int x + i8_to_int y <= i8_max ==> - ?z. i8_add x y = Return z /\ i8_to_int z = i8_to_int x + i8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I16_ADD_EQ: - !x y. - i16_min <= i16_to_int x + i16_to_int y ==> - i16_to_int x + i16_to_int y <= i16_max ==> - ?z. i16_add x y = Return z /\ i16_to_int z = i16_to_int x + i16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I32_ADD_EQ: - !x y. - i32_min <= i32_to_int x + i32_to_int y ==> - i32_to_int x + i32_to_int y <= i32_max ==> - ?z. i32_add x y = Return z /\ i32_to_int z = i32_to_int x + i32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I64_ADD_EQ: - !x y. - i64_min <= i64_to_int x + i64_to_int y ==> - i64_to_int x + i64_to_int y <= i64_max ==> - ?z. i64_add x y = Return z /\ i64_to_int z = i64_to_int x + i64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I128_ADD_EQ: - !x y. - i128_min <= i128_to_int x + i128_to_int y ==> - i128_to_int x + i128_to_int y <= i128_max ==> - ?z. i128_add x y = Return z /\ i128_to_int z = i128_to_int x + i128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem ISIZE_ADD_EQ: - !x y. - (i16_min <= isize_to_int x + isize_to_int y \/ isize_min <= isize_to_int x + isize_to_int y) ==> - (isize_to_int x + isize_to_int y <= i16_max \/ isize_to_int x + isize_to_int y <= isize_max) ==> - ?z. isize_add x y = Return z /\ isize_to_int z = isize_to_int x + isize_to_int y -Proof - prove_arith_op_eq -QED - -val all_add_eqs = [ - ISIZE_ADD_EQ, - I8_ADD_EQ, - I16_ADD_EQ, - I32_ADD_EQ, - I64_ADD_EQ, - I128_ADD_EQ, - USIZE_ADD_EQ, - U8_ADD_EQ, - U16_ADD_EQ, - U32_ADD_EQ, - U64_ADD_EQ, - U128_ADD_EQ -] - -Theorem U8_SUB_EQ: - !x y. - 0 <= u8_to_int x - u8_to_int y ==> - ?z. u8_sub x y = Return z /\ u8_to_int z = u8_to_int x - u8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U16_SUB_EQ: - !x y. - 0 <= u16_to_int x - u16_to_int y ==> - ?z. u16_sub x y = Return z /\ u16_to_int z = u16_to_int x - u16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U32_SUB_EQ: - !x y. - 0 <= u32_to_int x - u32_to_int y ==> - ?z. u32_sub x y = Return z /\ u32_to_int z = u32_to_int x - u32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U64_SUB_EQ: - !x y. - 0 <= u64_to_int x - u64_to_int y ==> - ?z. u64_sub x y = Return z /\ u64_to_int z = u64_to_int x - u64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U128_SUB_EQ: - !x y. - 0 <= u128_to_int x - u128_to_int y ==> - ?z. u128_sub x y = Return z /\ u128_to_int z = u128_to_int x - u128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem USIZE_SUB_EQ: - !x y. - 0 <= usize_to_int x - usize_to_int y ==> - ?z. usize_sub x y = Return z /\ usize_to_int z = usize_to_int x - usize_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I8_SUB_EQ: - !x y. - i8_min <= i8_to_int x - i8_to_int y ==> - i8_to_int x - i8_to_int y <= i8_max ==> - ?z. i8_sub x y = Return z /\ i8_to_int z = i8_to_int x - i8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I16_SUB_EQ: - !x y. - i16_min <= i16_to_int x - i16_to_int y ==> - i16_to_int x - i16_to_int y <= i16_max ==> - ?z. i16_sub x y = Return z /\ i16_to_int z = i16_to_int x - i16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I32_SUB_EQ: - !x y. - i32_min <= i32_to_int x - i32_to_int y ==> - i32_to_int x - i32_to_int y <= i32_max ==> - ?z. i32_sub x y = Return z /\ i32_to_int z = i32_to_int x - i32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I64_SUB_EQ: - !x y. - i64_min <= i64_to_int x - i64_to_int y ==> - i64_to_int x - i64_to_int y <= i64_max ==> - ?z. i64_sub x y = Return z /\ i64_to_int z = i64_to_int x - i64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I128_SUB_EQ: - !x y. - i128_min <= i128_to_int x - i128_to_int y ==> - i128_to_int x - i128_to_int y <= i128_max ==> - ?z. i128_sub x y = Return z /\ i128_to_int z = i128_to_int x - i128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem ISIZE_SUB_EQ: - !x y. - (i16_min <= isize_to_int x - isize_to_int y \/ isize_min <= isize_to_int x - isize_to_int y) ==> - (isize_to_int x - isize_to_int y <= i16_max \/ isize_to_int x - isize_to_int y <= isize_max) ==> - ?z. isize_sub x y = Return z /\ isize_to_int z = isize_to_int x - isize_to_int y -Proof - prove_arith_op_eq -QED - -val all_sub_eqs = [ - ISIZE_SUB_EQ, - I8_SUB_EQ, - I16_SUB_EQ, - I32_SUB_EQ, - I64_SUB_EQ, - I128_SUB_EQ, - USIZE_SUB_EQ, - U8_SUB_EQ, - U16_SUB_EQ, - U32_SUB_EQ, - U64_SUB_EQ, - U128_SUB_EQ -] - -Theorem U8_MUL_EQ: - !x y. - u8_to_int x * u8_to_int y <= u8_max ==> - ?z. u8_mul x y = Return z /\ u8_to_int z = u8_to_int x * u8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U16_MUL_EQ: - !x y. - u16_to_int x * u16_to_int y <= u16_max ==> - ?z. u16_mul x y = Return z /\ u16_to_int z = u16_to_int x * u16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U32_MUL_EQ: - !x y. - u32_to_int x * u32_to_int y <= u32_max ==> - ?z. u32_mul x y = Return z /\ u32_to_int z = u32_to_int x * u32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U64_MUL_EQ: - !x y. - u64_to_int x * u64_to_int y <= u64_max ==> - ?z. u64_mul x y = Return z /\ u64_to_int z = u64_to_int x * u64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U128_MUL_EQ: - !x y. - u128_to_int x * u128_to_int y <= u128_max ==> - ?z. u128_mul x y = Return z /\ u128_to_int z = u128_to_int x * u128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem USIZE_MUL_EQ: - !x y. - (usize_to_int x * usize_to_int y <= u16_max) \/ (usize_to_int x * usize_to_int y <= usize_max) ==> - ?z. usize_mul x y = Return z /\ usize_to_int z = usize_to_int x * usize_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I8_MUL_EQ: - !x y. - i8_min <= i8_to_int x * i8_to_int y ==> - i8_to_int x * i8_to_int y <= i8_max ==> - ?z. i8_mul x y = Return z /\ i8_to_int z = i8_to_int x * i8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I16_MUL_EQ: - !x y. - i16_min <= i16_to_int x * i16_to_int y ==> - i16_to_int x * i16_to_int y <= i16_max ==> - ?z. i16_mul x y = Return z /\ i16_to_int z = i16_to_int x * i16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I32_MUL_EQ: - !x y. - i32_min <= i32_to_int x * i32_to_int y ==> - i32_to_int x * i32_to_int y <= i32_max ==> - ?z. i32_mul x y = Return z /\ i32_to_int z = i32_to_int x * i32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I64_MUL_EQ: - !x y. - i64_min <= i64_to_int x * i64_to_int y ==> - i64_to_int x * i64_to_int y <= i64_max ==> - ?z. i64_mul x y = Return z /\ i64_to_int z = i64_to_int x * i64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I128_MUL_EQ: - !x y. - i128_min <= i128_to_int x * i128_to_int y ==> - i128_to_int x * i128_to_int y <= i128_max ==> - ?z. i128_mul x y = Return z /\ i128_to_int z = i128_to_int x * i128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem ISIZE_MUL_EQ: - !x y. - (i16_min <= isize_to_int x * isize_to_int y \/ isize_min <= isize_to_int x * isize_to_int y) ==> - (isize_to_int x * isize_to_int y <= i16_max \/ isize_to_int x * isize_to_int y <= isize_max) ==> - ?z. isize_mul x y = Return z /\ isize_to_int z = isize_to_int x * isize_to_int y -Proof - prove_arith_op_eq -QED - -val all_mul_eqs = [ - ISIZE_MUL_EQ, - I8_MUL_EQ, - I16_MUL_EQ, - I32_MUL_EQ, - I64_MUL_EQ, - I128_MUL_EQ, - USIZE_MUL_EQ, - U8_MUL_EQ, - U16_MUL_EQ, - U32_MUL_EQ, - U64_MUL_EQ, - U128_MUL_EQ -] - -Theorem U8_DIV_EQ: - !x y. - u8_to_int y <> 0 ==> - ?z. u8_div x y = Return z /\ u8_to_int z = u8_to_int x / u8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U16_DIV_EQ: - !x y. - u16_to_int y <> 0 ==> - ?z. u16_div x y = Return z /\ u16_to_int z = u16_to_int x / u16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U32_DIV_EQ: - !x y. - u32_to_int y <> 0 ==> - ?z. u32_div x y = Return z /\ u32_to_int z = u32_to_int x / u32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U64_DIV_EQ: - !x y. - u64_to_int y <> 0 ==> - ?z. u64_div x y = Return z /\ u64_to_int z = u64_to_int x / u64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U128_DIV_EQ: - !x y. - u128_to_int y <> 0 ==> - ?z. u128_div x y = Return z /\ u128_to_int z = u128_to_int x / u128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem USIZE_DIV_EQ: - !x y. - usize_to_int y <> 0 ==> - ?z. usize_div x y = Return z /\ usize_to_int z = usize_to_int x / usize_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I8_DIV_EQ: - !x y. - i8_to_int y <> 0 ==> - i8_min <= i8_to_int x / i8_to_int y ==> - i8_to_int x / i8_to_int y <= i8_max ==> - ?z. i8_div x y = Return z /\ i8_to_int z = i8_to_int x / i8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I16_DIV_EQ: - !x y. - i16_to_int y <> 0 ==> - i16_min <= i16_to_int x / i16_to_int y ==> - i16_to_int x / i16_to_int y <= i16_max ==> - ?z. i16_div x y = Return z /\ i16_to_int z = i16_to_int x / i16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I32_DIV_EQ: - !x y. - i32_to_int y <> 0 ==> - i32_min <= i32_to_int x / i32_to_int y ==> - i32_to_int x / i32_to_int y <= i32_max ==> - ?z. i32_div x y = Return z /\ i32_to_int z = i32_to_int x / i32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I64_DIV_EQ: - !x y. - i64_to_int y <> 0 ==> - i64_min <= i64_to_int x / i64_to_int y ==> - i64_to_int x / i64_to_int y <= i64_max ==> - ?z. i64_div x y = Return z /\ i64_to_int z = i64_to_int x / i64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I128_DIV_EQ: - !x y. - i128_to_int y <> 0 ==> - i128_min <= i128_to_int x / i128_to_int y ==> - i128_to_int x / i128_to_int y <= i128_max ==> - ?z. i128_div x y = Return z /\ i128_to_int z = i128_to_int x / i128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem ISIZE_DIV_EQ: - !x y. - isize_to_int y <> 0 ==> - (i16_min <= isize_to_int x / isize_to_int y \/ isize_min <= isize_to_int x / isize_to_int y) ==> - (isize_to_int x / isize_to_int y <= i16_max \/ isize_to_int x / isize_to_int y <= isize_max) ==> - ?z. isize_div x y = Return z /\ isize_to_int z = isize_to_int x / isize_to_int y -Proof - prove_arith_op_eq -QED - -val all_div_eqs = [ - ISIZE_DIV_EQ, - I8_DIV_EQ, - I16_DIV_EQ, - I32_DIV_EQ, - I64_DIV_EQ, - I128_DIV_EQ, - USIZE_DIV_EQ, - U8_DIV_EQ, - U16_DIV_EQ, - U32_DIV_EQ, - U64_DIV_EQ, - U128_DIV_EQ -] - -Theorem U8_REM_EQ: - !x y. - u8_to_int y <> 0 ==> - ?z. u8_rem x y = Return z /\ u8_to_int z = int_rem (u8_to_int x) (u8_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem U16_REM_EQ: - !x y. - u16_to_int y <> 0 ==> - ?z. u16_rem x y = Return z /\ u16_to_int z = int_rem (u16_to_int x) (u16_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem U32_REM_EQ: - !x y. - u32_to_int y <> 0 ==> - ?z. u32_rem x y = Return z /\ u32_to_int z = int_rem (u32_to_int x) (u32_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem U64_REM_EQ: - !x y. - u64_to_int y <> 0 ==> - ?z. u64_rem x y = Return z /\ u64_to_int z = int_rem (u64_to_int x) (u64_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem U128_REM_EQ: - !x y. - u128_to_int y <> 0 ==> - ?z. u128_rem x y = Return z /\ u128_to_int z = int_rem (u128_to_int x) (u128_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem USIZE_REM_EQ: - !x y. - usize_to_int y <> 0 ==> - ?z. usize_rem x y = Return z /\ usize_to_int z = int_rem (usize_to_int x) (usize_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem I8_REM_EQ: - !x y. - i8_to_int y <> 0 ==> - i8_min <= int_rem (i8_to_int x) (i8_to_int y) ==> - int_rem (i8_to_int x) (i8_to_int y) <= i8_max ==> - ?z. i8_rem x y = Return z /\ i8_to_int z = int_rem (i8_to_int x) (i8_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem I16_REM_EQ: - !x y. - i16_to_int y <> 0 ==> - i16_min <= int_rem (i16_to_int x) (i16_to_int y) ==> - int_rem (i16_to_int x) (i16_to_int y) <= i16_max ==> - ?z. i16_rem x y = Return z /\ i16_to_int z = int_rem (i16_to_int x) (i16_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem I32_REM_EQ: - !x y. - i32_to_int y <> 0 ==> - i32_min <= int_rem (i32_to_int x) (i32_to_int y) ==> - int_rem (i32_to_int x) (i32_to_int y) <= i32_max ==> - ?z. i32_rem x y = Return z /\ i32_to_int z = int_rem (i32_to_int x) (i32_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem I64_REM_EQ: - !x y. - i64_to_int y <> 0 ==> - i64_min <= int_rem (i64_to_int x) (i64_to_int y) ==> - int_rem (i64_to_int x) (i64_to_int y) <= i64_max ==> - ?z. i64_rem x y = Return z /\ i64_to_int z = int_rem (i64_to_int x) (i64_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem I8_REM_EQ: - !x y. - i8_to_int y <> 0 ==> - i8_min <= int_rem (i8_to_int x) (i8_to_int y) ==> - int_rem (i8_to_int x) (i8_to_int y) <= i8_max ==> - ?z. i8_rem x y = Return z /\ i8_to_int z = int_rem (i8_to_int x) (i8_to_int y) -Proof - prove_arith_op_eq -QED - -Theorem I8_REM_EQ: - !x y. - i8_to_int y <> 0 ==> - i8_min <= int_rem (i8_to_int x) (i8_to_int y) ==> - int_rem (i8_to_int x) (i8_to_int y) <= i8_max ==> - ?z. i8_rem x y = Return z /\ i8_to_int z = int_rem (i8_to_int x) (i8_to_int y) -Proof - prove_arith_op_eq -QED - - -(* -Theorem U16_DIV_EQ: - !x y. - u16_to_int y <> 0 ==> - ?z. u16_div x y = Return z /\ u16_to_int z = u16_to_int x / u16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U32_DIV_EQ: - !x y. - u32_to_int y <> 0 ==> - ?z. u32_div x y = Return z /\ u32_to_int z = u32_to_int x / u32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U64_DIV_EQ: - !x y. - u64_to_int y <> 0 ==> - ?z. u64_div x y = Return z /\ u64_to_int z = u64_to_int x / u64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem U128_DIV_EQ: - !x y. - u128_to_int y <> 0 ==> - ?z. u128_div x y = Return z /\ u128_to_int z = u128_to_int x / u128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem USIZE_DIV_EQ: - !x y. - usize_to_int y <> 0 ==> - ?z. usize_div x y = Return z /\ usize_to_int z = usize_to_int x / usize_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I8_DIV_EQ: - !x y. - i8_to_int y <> 0 ==> - i8_min <= i8_to_int x / i8_to_int y ==> - i8_to_int x / i8_to_int y <= i8_max ==> - ?z. i8_div x y = Return z /\ i8_to_int z = i8_to_int x / i8_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I16_DIV_EQ: - !x y. - i16_to_int y <> 0 ==> - i16_min <= i16_to_int x / i16_to_int y ==> - i16_to_int x / i16_to_int y <= i16_max ==> - ?z. i16_div x y = Return z /\ i16_to_int z = i16_to_int x / i16_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I32_DIV_EQ: - !x y. - i32_to_int y <> 0 ==> - i32_min <= i32_to_int x / i32_to_int y ==> - i32_to_int x / i32_to_int y <= i32_max ==> - ?z. i32_div x y = Return z /\ i32_to_int z = i32_to_int x / i32_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I64_DIV_EQ: - !x y. - i64_to_int y <> 0 ==> - i64_min <= i64_to_int x / i64_to_int y ==> - i64_to_int x / i64_to_int y <= i64_max ==> - ?z. i64_div x y = Return z /\ i64_to_int z = i64_to_int x / i64_to_int y -Proof - prove_arith_op_eq -QED - -Theorem I128_DIV_EQ: - !x y. - i128_to_int y <> 0 ==> - i128_min <= i128_to_int x / i128_to_int y ==> - i128_to_int x / i128_to_int y <= i128_max ==> - ?z. i128_div x y = Return z /\ i128_to_int z = i128_to_int x / i128_to_int y -Proof - prove_arith_op_eq -QED - -Theorem ISIZE_DIV_EQ: - !x y. - isize_to_int y <> 0 ==> - (i16_min <= isize_to_int x / isize_to_int y \/ isize_min <= isize_to_int x / isize_to_int y) ==> - (isize_to_int x / isize_to_int y <= i16_max \/ isize_to_int x / isize_to_int y <= isize_max) ==> - ?z. isize_div x y = Return z /\ isize_to_int z = isize_to_int x / isize_to_int y -Proof - prove_arith_op_eq -QED - -val all_div_eqs = [ - ISIZE_DIV_EQ, - I8_DIV_EQ, - I16_DIV_EQ, - I32_DIV_EQ, - I64_DIV_EQ, - I128_DIV_EQ, - USIZE_DIV_EQ, - U8_DIV_EQ, - U16_DIV_EQ, - U32_DIV_EQ, - U64_DIV_EQ, - U128_DIV_EQ -] diff --git a/backends/hol4/PrimitivesScript.sml b/backends/hol4/PrimitivesScript.sml new file mode 100644 index 00000000..1f8bb1a5 --- /dev/null +++ b/backends/hol4/PrimitivesScript.sml @@ -0,0 +1,1356 @@ +open HolKernel boolLib bossLib Parse +open boolTheory arithmeticTheory integerTheory intLib listTheory stringTheory + +val primitives_theory_name = "Primitives" +val _ = new_theory primitives_theory_name + +(*** Result *) +Datatype: + error = Failure +End + +Datatype: + result = Return 'a | Fail error | Loop +End + +Type M = ``: 'a result`` + +val bind_def = Define ` + (bind : 'a M -> ('a -> 'b M) -> 'b M) x f = + case x of + Return y => f y + | Fail e => Fail e + | Loop => Loop`; + +val bind_name = fst (dest_const “bind”) + +val return_def = Define ` + (return : 'a -> 'a M) x = + Return x`; + +val massert_def = Define ‘massert b = if b then Return () else Fail Failure’ + +Overload monad_bind = ``bind`` +Overload monad_unitbind = ``\x y. bind x (\z. y)`` +Overload monad_ignore_bind = ``\x y. bind x (\z. y)`` + +(* Allow the use of monadic syntax *) +val _ = monadsyntax.enable_monadsyntax () + +(*** Misc *) +Type char = “:char” +Type string = “:string” + +val mem_replace_fwd_def = Define ‘mem_replace_fwd (x : 'a) (y :'a) : 'a = x’ +val mem_replace_back_def = Define ‘mem_replace_back (x : 'a) (y :'a) : 'a = y’ + +(*** Scalars *) +(* Remark: most of the following code was partially generated *) + +(* The bounds for the isize/usize types are opaque, because they vary with + the architecture *) +val _ = new_constant ("isize_min", “:int”) +val _ = new_constant ("isize_max", “:int”) +val _ = new_constant ("usize_max", “:int”) + +val _ = new_type ("usize", 0) +val _ = new_type ("u8", 0) +val _ = new_type ("u16", 0) +val _ = new_type ("u32", 0) +val _ = new_type ("u64", 0) +val _ = new_type ("u128", 0) +val _ = new_type ("isize", 0) +val _ = new_type ("i8", 0) +val _ = new_type ("i16", 0) +val _ = new_type ("i32", 0) +val _ = new_type ("i64", 0) +val _ = new_type ("i128", 0) + +val _ = new_constant ("isize_to_int", “:isize -> int”) +val _ = new_constant ("i8_to_int", “:i8 -> int”) +val _ = new_constant ("i16_to_int", “:i16 -> int”) +val _ = new_constant ("i32_to_int", “:i32 -> int”) +val _ = new_constant ("i64_to_int", “:i64 -> int”) +val _ = new_constant ("i128_to_int", “:i128 -> int”) +val _ = new_constant ("usize_to_int", “:usize -> int”) +val _ = new_constant ("u8_to_int", “:u8 -> int”) +val _ = new_constant ("u16_to_int", “:u16 -> int”) +val _ = new_constant ("u32_to_int", “:u32 -> int”) +val _ = new_constant ("u64_to_int", “:u64 -> int”) +val _ = new_constant ("u128_to_int", “:u128 -> int”) + +val _ = new_constant ("int_to_isize", “:int -> isize”) +val _ = new_constant ("int_to_i8", “:int -> i8”) +val _ = new_constant ("int_to_i16", “:int -> i16”) +val _ = new_constant ("int_to_i32", “:int -> i32”) +val _ = new_constant ("int_to_i64", “:int -> i64”) +val _ = new_constant ("int_to_i128", “:int -> i128”) +val _ = new_constant ("int_to_usize", “:int -> usize”) +val _ = new_constant ("int_to_u8", “:int -> u8”) +val _ = new_constant ("int_to_u16", “:int -> u16”) +val _ = new_constant ("int_to_u32", “:int -> u32”) +val _ = new_constant ("int_to_u64", “:int -> u64”) +val _ = new_constant ("int_to_u128", “:int -> u128”) + +(* The bounds *) +val i8_min_def = Define ‘i8_min = (-128:int)’ +val i8_max_def = Define ‘i8_max = (127:int)’ +val i16_min_def = Define ‘i16_min = (-32768:int)’ +val i16_max_def = Define ‘i16_max = (32767:int)’ +val i32_min_def = Define ‘i32_min = (-2147483648:int)’ +val i32_max_def = Define ‘i32_max = (2147483647:int)’ +val i64_min_def = Define ‘i64_min = (-9223372036854775808:int)’ +val i64_max_def = Define ‘i64_max = (9223372036854775807:int)’ +val i128_min_def = Define ‘i128_min = (-170141183460469231731687303715884105728:int)’ +val i128_max_def = Define ‘i128_max = (170141183460469231731687303715884105727:int)’ +val u8_max_def = Define ‘u8_max = (255:int)’ +val u16_max_def = Define ‘u16_max = (65535:int)’ +val u32_max_def = Define ‘u32_max = (4294967295:int)’ +val u64_max_def = Define ‘u64_max = (18446744073709551615:int)’ +val u128_max_def = Define ‘u128_max = (340282366920938463463374607431768211455:int)’ + +val all_bound_defs = [ + i8_min_def, i8_max_def, + i16_min_def, i16_max_def, + i32_min_def, i32_max_def, + i64_min_def, i64_max_def, + i128_min_def, i128_max_def, + u8_max_def, + u16_max_def, + u32_max_def, + u64_max_def, + u128_max_def +] + +(* The following bounds are valid for all architectures *) +val isize_bounds = new_axiom ("isize_bounds", “isize_min <= i16_min /\ isize_max >= i16_max”) +val usize_bounds = new_axiom ("usize_bounds", “usize_max >= u16_max”) + +(* Conversion bounds *) +val isize_to_int_bounds = new_axiom ("isize_to_int_bounds", + “!n. isize_min <= isize_to_int n /\ isize_to_int n <= isize_max”) + +val i8_to_int_bounds = new_axiom ("i8_to_int_bounds", + “!n. i8_min <= i8_to_int n /\ i8_to_int n <= i8_max”) + +val i16_to_int_bounds = new_axiom ("i16_to_int_bounds", + “!n. i16_min <= i16_to_int n /\ i16_to_int n <= i16_max”) + +val i32_to_int_bounds = new_axiom ("i32_to_int_bounds", + “!n. i32_min <= i32_to_int n /\ i32_to_int n <= i32_max”) + +val i64_to_int_bounds = new_axiom ("i64_to_int_bounds", + “!n. i64_min <= i64_to_int n /\ i64_to_int n <= i64_max”) + +val i128_to_int_bounds = new_axiom ("i128_to_int_bounds", + “!n. i128_min <= i128_to_int n /\ i128_to_int n <= i128_max”) + +val usize_to_int_bounds = new_axiom ("usize_to_int_bounds", + “!n. 0 <= usize_to_int n /\ usize_to_int n <= usize_max”) + +val u8_to_int_bounds = new_axiom ("u8_to_int_bounds", + “!n. 0 <= u8_to_int n /\ u8_to_int n <= u8_max”) + +val u16_to_int_bounds = new_axiom ("u16_to_int_bounds", + “!n. 0 <= u16_to_int n /\ u16_to_int n <= u16_max”) + +val u32_to_int_bounds = new_axiom ("u32_to_int_bounds", + “!n. 0 <= u32_to_int n /\ u32_to_int n <= u32_max”) + +val u64_to_int_bounds = new_axiom ("u64_to_int_bounds", + “!n. 0 <= u64_to_int n /\ u64_to_int n <= u64_max”) + +val u128_to_int_bounds = new_axiom ("u128_to_int_bounds", + “!n. 0 <= u128_to_int n /\ u128_to_int n <= u128_max”) + +val all_to_int_bounds_lemmas = [ + isize_to_int_bounds, + i8_to_int_bounds, + i16_to_int_bounds, + i32_to_int_bounds, + i64_to_int_bounds, + i128_to_int_bounds, + usize_to_int_bounds, + u8_to_int_bounds, + u16_to_int_bounds, + u32_to_int_bounds, + u64_to_int_bounds, + u128_to_int_bounds +] + +(* Conversion to and from int. + + Note that for isize and usize, we write the lemmas in such a way that the + proofs are easily automatable for constants. + *) +val int_to_isize_id = + new_axiom ("int_to_isize_id", + “!n. (i16_min <= n \/ isize_min <= n) /\ (n <= i16_max \/ n <= isize_max) ==> + isize_to_int (int_to_isize n) = n”) + +val int_to_usize_id = + new_axiom ("int_to_usize_id", + “!n. 0 <= n /\ (n <= u16_max \/ n <= usize_max) ==> usize_to_int (int_to_usize n) = n”) + +val int_to_i8_id = + new_axiom ("int_to_i8_id", + “!n. i8_min <= n /\ n <= i8_max ==> i8_to_int (int_to_i8 n) = n”) + +val int_to_i16_id = + new_axiom ("int_to_i16_id", + “!n. i16_min <= n /\ n <= i16_max ==> i16_to_int (int_to_i16 n) = n”) + +val int_to_i32_id = + new_axiom ("int_to_i32_id", + “!n. i32_min <= n /\ n <= i32_max ==> i32_to_int (int_to_i32 n) = n”) + +val int_to_i64_id = + new_axiom ("int_to_i64_id", + “!n. i64_min <= n /\ n <= i64_max ==> i64_to_int (int_to_i64 n) = n”) + +val int_to_i128_id = + new_axiom ("int_to_i128_id", + “!n. i128_min <= n /\ n <= i128_max ==> i128_to_int (int_to_i128 n) = n”) + +val int_to_u8_id = + new_axiom ("int_to_u8_id", + “!n. 0 <= n /\ n <= u8_max ==> u8_to_int (int_to_u8 n) = n”) + +val int_to_u16_id = + new_axiom ("int_to_u16_id", + “!n. 0 <= n /\ n <= u16_max ==> u16_to_int (int_to_u16 n) = n”) + +val int_to_u32_id = + new_axiom ("int_to_u32_id", + “!n. 0 <= n /\ n <= u32_max ==> u32_to_int (int_to_u32 n) = n”) + +val int_to_u64_id = + new_axiom ("int_to_u64_id", + “!n. 0 <= n /\ n <= u64_max ==> u64_to_int (int_to_u64 n) = n”) + +val int_to_u128_id = + new_axiom ("int_to_u128_id", + “!n. 0 <= n /\ n <= u128_max ==> u128_to_int (int_to_u128 n) = n”) + +val all_conversion_id_lemmas = [ + int_to_isize_id, + int_to_i8_id, + int_to_i16_id, + int_to_i32_id, + int_to_i64_id, + int_to_i128_id, + int_to_usize_id, + int_to_u8_id, + int_to_u16_id, + int_to_u32_id, + int_to_u64_id, + int_to_u128_id +] + +(** Utilities to define the arithmetic operations *) +val mk_isize_def = Define + ‘mk_isize n = + if isize_min <= n /\ n <= isize_max then Return (int_to_isize n) + else Fail Failure’ + +val mk_i8_def = Define + ‘mk_i8 n = + if i8_min <= n /\ n <= i8_max then Return (int_to_i8 n) + else Fail Failure’ + +val mk_i16_def = Define + ‘mk_i16 n = + if i16_min <= n /\ n <= i16_max then Return (int_to_i16 n) + else Fail Failure’ + +val mk_i32_def = Define + ‘mk_i32 n = + if i32_min <= n /\ n <= i32_max then Return (int_to_i32 n) + else Fail Failure’ + +val mk_i64_def = Define + ‘mk_i64 n = + if i64_min <= n /\ n <= i64_max then Return (int_to_i64 n) + else Fail Failure’ + +val mk_i128_def = Define + ‘mk_i128 n = + if i128_min <= n /\ n <= i128_max then Return (int_to_i128 n) + else Fail Failure’ + +val mk_usize_def = Define + ‘mk_usize n = + if 0 <= n /\ n <= usize_max then Return (int_to_usize n) + else Fail Failure’ + +val mk_u8_def = Define + ‘mk_u8 n = + if 0 <= n /\ n <= u8_max then Return (int_to_u8 n) + else Fail Failure’ + +val mk_u16_def = Define + ‘mk_u16 n = + if 0 <= n /\ n <= u16_max then Return (int_to_u16 n) + else Fail Failure’ + +val mk_u32_def = Define + ‘mk_u32 n = + if 0 <= n /\ n <= u32_max then Return (int_to_u32 n) + else Fail Failure’ + +val mk_u64_def = Define + ‘mk_u64 n = + if 0 <= n /\ n <= u64_max then Return (int_to_u64 n) + else Fail Failure’ + +val mk_u128_def = Define + ‘mk_u128 n = + if 0 <= n /\ n <= u128_max then Return (int_to_u128 n) + else Fail Failure’ + +val all_mk_int_defs = [ + mk_isize_def, + mk_i8_def, + mk_i16_def, + mk_i32_def, + mk_i64_def, + mk_i128_def, + mk_usize_def, + mk_u8_def, + mk_u16_def, + mk_u32_def, + mk_u64_def, + mk_u128_def +] + + +val isize_add_def = Define ‘isize_add x y = mk_isize ((isize_to_int x) + (isize_to_int y))’ +val i8_add_def = Define ‘i8_add x y = mk_i8 ((i8_to_int x) + (i8_to_int y))’ +val i16_add_def = Define ‘i16_add x y = mk_i16 ((i16_to_int x) + (i16_to_int y))’ +val i32_add_def = Define ‘i32_add x y = mk_i32 ((i32_to_int x) + (i32_to_int y))’ +val i64_add_def = Define ‘i64_add x y = mk_i64 ((i64_to_int x) + (i64_to_int y))’ +val i128_add_def = Define ‘i128_add x y = mk_i128 ((i128_to_int x) + (i128_to_int y))’ +val usize_add_def = Define ‘usize_add x y = mk_usize ((usize_to_int x) + (usize_to_int y))’ +val u8_add_def = Define ‘u8_add x y = mk_u8 ((u8_to_int x) + (u8_to_int y))’ +val u16_add_def = Define ‘u16_add x y = mk_u16 ((u16_to_int x) + (u16_to_int y))’ +val u32_add_def = Define ‘u32_add x y = mk_u32 ((u32_to_int x) + (u32_to_int y))’ +val u64_add_def = Define ‘u64_add x y = mk_u64 ((u64_to_int x) + (u64_to_int y))’ +val u128_add_def = Define ‘u128_add x y = mk_u128 ((u128_to_int x) + (u128_to_int y))’ + +val all_add_defs = [ + isize_add_def, + i8_add_def, + i16_add_def, + i32_add_def, + i64_add_def, + i128_add_def, + usize_add_def, + u8_add_def, + u16_add_def, + u32_add_def, + u64_add_def, + u128_add_def +] + +val isize_sub_def = Define ‘isize_sub x y = mk_isize ((isize_to_int x) - (isize_to_int y))’ +val i8_sub_def = Define ‘i8_sub x y = mk_i8 ((i8_to_int x) - (i8_to_int y))’ +val i16_sub_def = Define ‘i16_sub x y = mk_i16 ((i16_to_int x) - (i16_to_int y))’ +val i32_sub_def = Define ‘i32_sub x y = mk_i32 ((i32_to_int x) - (i32_to_int y))’ +val i64_sub_def = Define ‘i64_sub x y = mk_i64 ((i64_to_int x) - (i64_to_int y))’ +val i128_sub_def = Define ‘i128_sub x y = mk_i128 ((i128_to_int x) - (i128_to_int y))’ +val usize_sub_def = Define ‘usize_sub x y = mk_usize ((usize_to_int x) - (usize_to_int y))’ +val u8_sub_def = Define ‘u8_sub x y = mk_u8 ((u8_to_int x) - (u8_to_int y))’ +val u16_sub_def = Define ‘u16_sub x y = mk_u16 ((u16_to_int x) - (u16_to_int y))’ +val u32_sub_def = Define ‘u32_sub x y = mk_u32 ((u32_to_int x) - (u32_to_int y))’ +val u64_sub_def = Define ‘u64_sub x y = mk_u64 ((u64_to_int x) - (u64_to_int y))’ +val u128_sub_def = Define ‘u128_sub x y = mk_u128 ((u128_to_int x) - (u128_to_int y))’ + +val all_sub_defs = [ + isize_sub_def, + i8_sub_def, + i16_sub_def, + i32_sub_def, + i64_sub_def, + i128_sub_def, + usize_sub_def, + u8_sub_def, + u16_sub_def, + u32_sub_def, + u64_sub_def, + u128_sub_def +] + +val isize_mul_def = Define ‘isize_mul x y = mk_isize ((isize_to_int x) * (isize_to_int y))’ +val i8_mul_def = Define ‘i8_mul x y = mk_i8 ((i8_to_int x) * (i8_to_int y))’ +val i16_mul_def = Define ‘i16_mul x y = mk_i16 ((i16_to_int x) * (i16_to_int y))’ +val i32_mul_def = Define ‘i32_mul x y = mk_i32 ((i32_to_int x) * (i32_to_int y))’ +val i64_mul_def = Define ‘i64_mul x y = mk_i64 ((i64_to_int x) * (i64_to_int y))’ +val i128_mul_def = Define ‘i128_mul x y = mk_i128 ((i128_to_int x) * (i128_to_int y))’ +val usize_mul_def = Define ‘usize_mul x y = mk_usize ((usize_to_int x) * (usize_to_int y))’ +val u8_mul_def = Define ‘u8_mul x y = mk_u8 ((u8_to_int x) * (u8_to_int y))’ +val u16_mul_def = Define ‘u16_mul x y = mk_u16 ((u16_to_int x) * (u16_to_int y))’ +val u32_mul_def = Define ‘u32_mul x y = mk_u32 ((u32_to_int x) * (u32_to_int y))’ +val u64_mul_def = Define ‘u64_mul x y = mk_u64 ((u64_to_int x) * (u64_to_int y))’ +val u128_mul_def = Define ‘u128_mul x y = mk_u128 ((u128_to_int x) * (u128_to_int y))’ + +val all_mul_defs = [ + isize_mul_def, + i8_mul_def, + i16_mul_def, + i32_mul_def, + i64_mul_def, + i128_mul_def, + usize_mul_def, + u8_mul_def, + u16_mul_def, + u32_mul_def, + u64_mul_def, + u128_mul_def +] + +val isize_div_def = Define ‘isize_div x y = + if isize_to_int y = 0 then Fail Failure else mk_isize ((isize_to_int x) / (isize_to_int y))’ +val i8_div_def = Define ‘i8_div x y = + if i8_to_int y = 0 then Fail Failure else mk_i8 ((i8_to_int x) / (i8_to_int y))’ +val i16_div_def = Define ‘i16_div x y = + if i16_to_int y = 0 then Fail Failure else mk_i16 ((i16_to_int x) / (i16_to_int y))’ +val i32_div_def = Define ‘i32_div x y = + if i32_to_int y = 0 then Fail Failure else mk_i32 ((i32_to_int x) / (i32_to_int y))’ +val i64_div_def = Define ‘i64_div x y = + if i64_to_int y = 0 then Fail Failure else mk_i64 ((i64_to_int x) / (i64_to_int y))’ +val i128_div_def = Define ‘i128_div x y = + if i128_to_int y = 0 then Fail Failure else mk_i128 ((i128_to_int x) / (i128_to_int y))’ +val usize_div_def = Define ‘usize_div x y = + if usize_to_int y = 0 then Fail Failure else mk_usize ((usize_to_int x) / (usize_to_int y))’ +val u8_div_def = Define ‘u8_div x y = + if u8_to_int y = 0 then Fail Failure else mk_u8 ((u8_to_int x) / (u8_to_int y))’ +val u16_div_def = Define ‘u16_div x y = + if u16_to_int y = 0 then Fail Failure else mk_u16 ((u16_to_int x) / (u16_to_int y))’ +val u32_div_def = Define ‘u32_div x y = + if u32_to_int y = 0 then Fail Failure else mk_u32 ((u32_to_int x) / (u32_to_int y))’ +val u64_div_def = Define ‘u64_div x y = + if u64_to_int y = 0 then Fail Failure else mk_u64 ((u64_to_int x) / (u64_to_int y))’ +val u128_div_def = Define ‘u128_div x y = + if u128_to_int y = 0 then Fail Failure else mk_u128 ((u128_to_int x) / (u128_to_int y))’ + +val all_div_defs = [ + isize_div_def, + i8_div_def, + i16_div_def, + i32_div_def, + i64_div_def, + i128_div_def, + usize_div_def, + u8_div_def, + u16_div_def, + u32_div_def, + u64_div_def, + u128_div_def +] + +(* The remainder operation is not a modulo. + + In Rust, the remainder has the sign of the dividend. + In HOL4, it has the sign of the divisor. + *) +val int_rem_def = Define ‘int_rem (x : int) (y : int) : int = + if (x >= 0 /\ y >= 0) \/ (x < 0 /\ y < 0) then x % y else -(x % y)’ + +(* Checking consistency with Rust *) +val _ = prove(“int_rem 1 2 = 1”, EVAL_TAC) +val _ = prove(“int_rem (-1) 2 = -1”, EVAL_TAC) +val _ = prove(“int_rem 1 (-2) = 1”, EVAL_TAC) +val _ = prove(“int_rem (-1) (-2) = -1”, EVAL_TAC) + +val isize_rem_def = Define ‘isize_rem x y = + if isize_to_int y = 0 then Fail Failure else mk_isize (int_rem (isize_to_int x) (isize_to_int y))’ +val i8_rem_def = Define ‘i8_rem x y = + if i8_to_int y = 0 then Fail Failure else mk_i8 (int_rem (i8_to_int x) (i8_to_int y))’ +val i16_rem_def = Define ‘i16_rem x y = + if i16_to_int y = 0 then Fail Failure else mk_i16 (int_rem (i16_to_int x) (i16_to_int y))’ +val i32_rem_def = Define ‘i32_rem x y = + if i32_to_int y = 0 then Fail Failure else mk_i32 (int_rem (i32_to_int x) (i32_to_int y))’ +val i64_rem_def = Define ‘i64_rem x y = + if i64_to_int y = 0 then Fail Failure else mk_i64 (int_rem (i64_to_int x) (i64_to_int y))’ +val i128_rem_def = Define ‘i128_rem x y = + if i128_to_int y = 0 then Fail Failure else mk_i128 (int_rem (i128_to_int x) (i128_to_int y))’ +val usize_rem_def = Define ‘usize_rem x y = + if usize_to_int y = 0 then Fail Failure else mk_usize (int_rem (usize_to_int x) (usize_to_int y))’ +val u8_rem_def = Define ‘u8_rem x y = + if u8_to_int y = 0 then Fail Failure else mk_u8 (int_rem (u8_to_int x) (u8_to_int y))’ +val u16_rem_def = Define ‘u16_rem x y = + if u16_to_int y = 0 then Fail Failure else mk_u16 (int_rem (u16_to_int x) (u16_to_int y))’ +val u32_rem_def = Define ‘u32_rem x y = + if u32_to_int y = 0 then Fail Failure else mk_u32 (int_rem (u32_to_int x) (u32_to_int y))’ +val u64_rem_def = Define ‘u64_rem x y = + if u64_to_int y = 0 then Fail Failure else mk_u64 (int_rem (u64_to_int x) (u64_to_int y))’ +val u128_rem_def = Define ‘u128_rem x y = + if u128_to_int y = 0 then Fail Failure else mk_u128 (int_rem (u128_to_int x) (u128_to_int y))’ + +val all_rem_defs = [ + isize_rem_def, + i8_rem_def, + i16_rem_def, + i32_rem_def, + i64_rem_def, + i128_rem_def, + usize_rem_def, + u8_rem_def, + u16_rem_def, + u32_rem_def, + u64_rem_def, + u128_rem_def +] + +(* Ignore a theorem. + + To be used in conjunction with {!pop_assum} for instance. + *) +fun IGNORE_TAC (_ : thm) : tactic = ALL_TAC + +val POP_IGNORE_TAC = POP_ASSUM IGNORE_TAC + +(* TODO: we need a better library of lemmas about arithmetic *) + +(* TODO: add those as rewriting tactics by default *) +val NOT_LE_EQ_GT = store_thm("NOT_LE_EQ_GT", “!(x y: int). ~(x <= y) <=> x > y”, COOPER_TAC) +val NOT_LT_EQ_GE = store_thm("NOT_LT_EQ_GE", “!(x y: int). ~(x < y) <=> x >= y”, COOPER_TAC) +val NOT_GE_EQ_LT = store_thm("NOT_GE_EQ_LT", “!(x y: int). ~(x >= y) <=> x < y”, COOPER_TAC) +val NOT_GT_EQ_LE = store_thm("NOT_GT_EQ_LE", “!(x y: int). ~(x > y) <=> x <= y”, COOPER_TAC) + +Theorem POS_MUL_POS_IS_POS: + !(x y : int). 0 <= x ==> 0 <= y ==> 0 <= x * y +Proof + rpt strip_tac >> + sg ‘0 <= &(Num x) * &(Num y)’ >- (rw [INT_MUL_CALCULATE] >> COOPER_TAC) >> + sg ‘&(Num x) = x’ >- (irule EQ_SYM >> rw [INT_OF_NUM] >> COOPER_TAC) >> + sg ‘&(Num y) = y’ >- (irule EQ_SYM >> rw [INT_OF_NUM] >> COOPER_TAC) >> + metis_tac[] +QED + +val GE_EQ_LE = store_thm("GE_EQ_LE", “!(x y : int). x >= y <=> y <= x”, COOPER_TAC) +val LE_EQ_GE = store_thm("LE_EQ_GE", “!(x y : int). x <= y <=> y >= x”, COOPER_TAC) +val GT_EQ_LT = store_thm("GT_EQ_LT", “!(x y : int). x > y <=> y < x”, COOPER_TAC) +val LT_EQ_GT = store_thm("LT_EQ_GT", “!(x y : int). x < y <=> y > x”, COOPER_TAC) + +Theorem POS_DIV_POS_IS_POS: + !(x y : int). 0 <= x ==> 0 < y ==> 0 <= x / y +Proof + rpt strip_tac >> + rw [LE_EQ_GE] >> + sg ‘y <> 0’ >- COOPER_TAC >> + qspecl_then [‘\x. x >= 0’, ‘x’, ‘y’] ASSUME_TAC INT_DIV_FORALL_P >> + fs [] >> POP_IGNORE_TAC >> rw [] >- COOPER_TAC >> + fs [NOT_LT_EQ_GE] >> + (* Proof by contradiction: assume k < 0 *) + spose_not_then ASSUME_TAC >> + fs [NOT_GE_EQ_LT] >> + sg ‘k * y = (k + 1) * y + - y’ >- (fs [INT_RDISTRIB] >> COOPER_TAC) >> + sg ‘0 <= (-(k + 1)) * y’ >- (irule POS_MUL_POS_IS_POS >> COOPER_TAC) >> + COOPER_TAC +QED + +Theorem POS_DIV_POS_LE: + !(x y d : int). 0 <= x ==> 0 <= y ==> 0 < d ==> x <= y ==> x / d <= y / d +Proof + rpt strip_tac >> + sg ‘d <> 0’ >- COOPER_TAC >> + qspecl_then [‘\k. k = x / d’, ‘x’, ‘d’] ASSUME_TAC INT_DIV_P >> + qspecl_then [‘\k. k = y / d’, ‘y’, ‘d’] ASSUME_TAC INT_DIV_P >> + rfs [NOT_LT_EQ_GE] >> TRY COOPER_TAC >> + sg ‘y = (x / d) * d + (r' + y - x)’ >- COOPER_TAC >> + qspecl_then [‘(x / d) * d’, ‘r' + y - x’, ‘d’] ASSUME_TAC INT_ADD_DIV >> + rfs [] >> + Cases_on ‘x = y’ >- fs [] >> + sg ‘r' + y ≠ x’ >- COOPER_TAC >> fs [] >> + sg ‘((x / d) * d) / d = x / d’ >- (irule INT_DIV_RMUL >> COOPER_TAC) >> + fs [] >> + sg ‘0 <= (r' + y − x) / d’ >- (irule POS_DIV_POS_IS_POS >> COOPER_TAC) >> + metis_tac [INT_LE_ADDR] +QED + +Theorem POS_DIV_POS_LE_INIT: + !(x y : int). 0 <= x ==> 0 < y ==> x / y <= x +Proof + rpt strip_tac >> + sg ‘y <> 0’ >- COOPER_TAC >> + qspecl_then [‘\k. k = x / y’, ‘x’, ‘y’] ASSUME_TAC INT_DIV_P >> + rfs [NOT_LT_EQ_GE] >- COOPER_TAC >> + sg ‘y = (y - 1) + 1’ >- rw [] >> + sg ‘x = x / y + ((x / y) * (y - 1) + r)’ >-( + qspecl_then [‘1’, ‘y-1’, ‘x / y’] ASSUME_TAC INT_LDISTRIB >> + rfs [] >> + COOPER_TAC + ) >> + sg ‘!a b c. 0 <= c ==> a = b + c ==> b <= a’ >- (COOPER_TAC) >> + pop_assum irule >> + exists_tac “x / y * (y − 1) + r” >> + sg ‘0 <= x / y’ >- (irule POS_DIV_POS_IS_POS >> COOPER_TAC) >> + sg ‘0 <= (x / y) * (y - 1)’ >- (irule POS_MUL_POS_IS_POS >> COOPER_TAC) >> + COOPER_TAC +QED + +Theorem POS_MOD_POS_IS_POS: + !(x y : int). 0 <= x ==> 0 < y ==> 0 <= x % y +Proof + rpt strip_tac >> + sg ‘y <> 0’ >- COOPER_TAC >> + imp_res_tac INT_DIVISION >> + first_x_assum (qspec_then ‘x’ assume_tac) >> + first_x_assum (qspec_then ‘x’ assume_tac) >> + sg ‘~(y < 0)’ >- COOPER_TAC >> fs [] +QED + +Theorem POS_MOD_POS_LE_INIT: + !(x y : int). 0 <= x ==> 0 < y ==> x % y <= x +Proof + rpt strip_tac >> + sg ‘y <> 0’ >- COOPER_TAC >> + imp_res_tac INT_DIVISION >> + first_x_assum (qspec_then ‘x’ assume_tac) >> + first_x_assum (qspec_then ‘x’ assume_tac) >> + sg ‘~(y < 0)’ >- COOPER_TAC >> fs [] >> + sg ‘0 <= x % y’ >- (irule POS_MOD_POS_IS_POS >> COOPER_TAC) >> + sg ‘0 <= x / y’ >- (irule POS_DIV_POS_IS_POS >> COOPER_TAC) >> + sg ‘0 <= (x / y) * y’ >- (irule POS_MUL_POS_IS_POS >> COOPER_TAC) >> + COOPER_TAC +QED + +(* +val (asms,g) = top_goal () +*) + +fun prove_arith_op_eq (asms, g) = + let + val (_, t) = (dest_exists o snd o strip_imp o snd o strip_forall) g; + val (x_to_int, y_to_int) = + case (snd o strip_comb o rhs o snd o dest_conj) t of + [x, y] => (x,y) + | _ => failwith "Unexpected" + val x = (snd o dest_comb) x_to_int; + val y = (snd o dest_comb) y_to_int; + fun inst_first_lem arg lems = + MAP_FIRST (fn th => (ASSUME_TAC (SPEC arg th) handle HOL_ERR _ => FAIL_TAC "")) lems; + in + (rpt gen_tac >> + rpt DISCH_TAC >> + ASSUME_TAC usize_bounds >> (* Only useful for usize of course *) + ASSUME_TAC isize_bounds >> (* Only useful for isize of course *) + rw (int_rem_def :: List.concat [all_rem_defs, all_add_defs, all_sub_defs, all_mul_defs, all_div_defs, all_mk_int_defs, all_to_int_bounds_lemmas, all_conversion_id_lemmas]) >> + fs (int_rem_def :: List.concat [all_rem_defs, all_add_defs, all_sub_defs, all_mul_defs, all_div_defs, all_mk_int_defs, all_to_int_bounds_lemmas, all_conversion_id_lemmas]) >> + inst_first_lem x all_to_int_bounds_lemmas >> + inst_first_lem y all_to_int_bounds_lemmas >> + gs [NOT_LE_EQ_GT, NOT_LT_EQ_GE, NOT_GE_EQ_LT, NOT_GT_EQ_LE, GE_EQ_LE, GT_EQ_LT] >> + TRY COOPER_TAC >> + FIRST [ + (* For division *) + qspecl_then [‘^x_to_int’, ‘^y_to_int’] ASSUME_TAC POS_DIV_POS_IS_POS >> + qspecl_then [‘^x_to_int’, ‘^y_to_int’] ASSUME_TAC POS_DIV_POS_LE_INIT >> + COOPER_TAC, + (* For remainder *) + dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC all_conversion_id_lemmas >> fs [] >> + qspecl_then [‘^x_to_int’, ‘^y_to_int’] ASSUME_TAC POS_MOD_POS_IS_POS >> + qspecl_then [‘^x_to_int’, ‘^y_to_int’] ASSUME_TAC POS_MOD_POS_LE_INIT >> + COOPER_TAC, + dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC all_conversion_id_lemmas >> fs [] + ]) (asms, g) + end + +Theorem U8_ADD_EQ: + !x y. + u8_to_int x + u8_to_int y <= u8_max ==> + ?z. u8_add x y = Return z /\ u8_to_int z = u8_to_int x + u8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U16_ADD_EQ: + !(x y). + u16_to_int x + u16_to_int y <= u16_max ==> + ?(z). u16_add x y = Return z /\ u16_to_int z = u16_to_int x + u16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U32_ADD_EQ: + !x y. + u32_to_int x + u32_to_int y <= u32_max ==> + ?z. u32_add x y = Return z /\ u32_to_int z = u32_to_int x + u32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U64_ADD_EQ: + !x y. + u64_to_int x + u64_to_int y <= u64_max ==> + ?z. u64_add x y = Return z /\ u64_to_int z = u64_to_int x + u64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U128_ADD_EQ: + !x y. + u128_to_int x + u128_to_int y <= u128_max ==> + ?z. u128_add x y = Return z /\ u128_to_int z = u128_to_int x + u128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem USIZE_ADD_EQ: + !x y. + (usize_to_int x + usize_to_int y <= u16_max) \/ (usize_to_int x + usize_to_int y <= usize_max) ==> + ?z. usize_add x y = Return z /\ usize_to_int z = usize_to_int x + usize_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I8_ADD_EQ: + !x y. + i8_min <= i8_to_int x + i8_to_int y ==> + i8_to_int x + i8_to_int y <= i8_max ==> + ?z. i8_add x y = Return z /\ i8_to_int z = i8_to_int x + i8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I16_ADD_EQ: + !x y. + i16_min <= i16_to_int x + i16_to_int y ==> + i16_to_int x + i16_to_int y <= i16_max ==> + ?z. i16_add x y = Return z /\ i16_to_int z = i16_to_int x + i16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I32_ADD_EQ: + !x y. + i32_min <= i32_to_int x + i32_to_int y ==> + i32_to_int x + i32_to_int y <= i32_max ==> + ?z. i32_add x y = Return z /\ i32_to_int z = i32_to_int x + i32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I64_ADD_EQ: + !x y. + i64_min <= i64_to_int x + i64_to_int y ==> + i64_to_int x + i64_to_int y <= i64_max ==> + ?z. i64_add x y = Return z /\ i64_to_int z = i64_to_int x + i64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I128_ADD_EQ: + !x y. + i128_min <= i128_to_int x + i128_to_int y ==> + i128_to_int x + i128_to_int y <= i128_max ==> + ?z. i128_add x y = Return z /\ i128_to_int z = i128_to_int x + i128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem ISIZE_ADD_EQ: + !x y. + (i16_min <= isize_to_int x + isize_to_int y \/ isize_min <= isize_to_int x + isize_to_int y) ==> + (isize_to_int x + isize_to_int y <= i16_max \/ isize_to_int x + isize_to_int y <= isize_max) ==> + ?z. isize_add x y = Return z /\ isize_to_int z = isize_to_int x + isize_to_int y +Proof + prove_arith_op_eq +QED + +val all_add_eqs = [ + ISIZE_ADD_EQ, + I8_ADD_EQ, + I16_ADD_EQ, + I32_ADD_EQ, + I64_ADD_EQ, + I128_ADD_EQ, + USIZE_ADD_EQ, + U8_ADD_EQ, + U16_ADD_EQ, + U32_ADD_EQ, + U64_ADD_EQ, + U128_ADD_EQ +] + +Theorem U8_SUB_EQ: + !x y. + 0 <= u8_to_int x - u8_to_int y ==> + ?z. u8_sub x y = Return z /\ u8_to_int z = u8_to_int x - u8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U16_SUB_EQ: + !x y. + 0 <= u16_to_int x - u16_to_int y ==> + ?z. u16_sub x y = Return z /\ u16_to_int z = u16_to_int x - u16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U32_SUB_EQ: + !x y. + 0 <= u32_to_int x - u32_to_int y ==> + ?z. u32_sub x y = Return z /\ u32_to_int z = u32_to_int x - u32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U64_SUB_EQ: + !x y. + 0 <= u64_to_int x - u64_to_int y ==> + ?z. u64_sub x y = Return z /\ u64_to_int z = u64_to_int x - u64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U128_SUB_EQ: + !x y. + 0 <= u128_to_int x - u128_to_int y ==> + ?z. u128_sub x y = Return z /\ u128_to_int z = u128_to_int x - u128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem USIZE_SUB_EQ: + !x y. + 0 <= usize_to_int x - usize_to_int y ==> + ?z. usize_sub x y = Return z /\ usize_to_int z = usize_to_int x - usize_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I8_SUB_EQ: + !x y. + i8_min <= i8_to_int x - i8_to_int y ==> + i8_to_int x - i8_to_int y <= i8_max ==> + ?z. i8_sub x y = Return z /\ i8_to_int z = i8_to_int x - i8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I16_SUB_EQ: + !x y. + i16_min <= i16_to_int x - i16_to_int y ==> + i16_to_int x - i16_to_int y <= i16_max ==> + ?z. i16_sub x y = Return z /\ i16_to_int z = i16_to_int x - i16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I32_SUB_EQ: + !x y. + i32_min <= i32_to_int x - i32_to_int y ==> + i32_to_int x - i32_to_int y <= i32_max ==> + ?z. i32_sub x y = Return z /\ i32_to_int z = i32_to_int x - i32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I64_SUB_EQ: + !x y. + i64_min <= i64_to_int x - i64_to_int y ==> + i64_to_int x - i64_to_int y <= i64_max ==> + ?z. i64_sub x y = Return z /\ i64_to_int z = i64_to_int x - i64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I128_SUB_EQ: + !x y. + i128_min <= i128_to_int x - i128_to_int y ==> + i128_to_int x - i128_to_int y <= i128_max ==> + ?z. i128_sub x y = Return z /\ i128_to_int z = i128_to_int x - i128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem ISIZE_SUB_EQ: + !x y. + (i16_min <= isize_to_int x - isize_to_int y \/ isize_min <= isize_to_int x - isize_to_int y) ==> + (isize_to_int x - isize_to_int y <= i16_max \/ isize_to_int x - isize_to_int y <= isize_max) ==> + ?z. isize_sub x y = Return z /\ isize_to_int z = isize_to_int x - isize_to_int y +Proof + prove_arith_op_eq +QED + +val all_sub_eqs = [ + ISIZE_SUB_EQ, + I8_SUB_EQ, + I16_SUB_EQ, + I32_SUB_EQ, + I64_SUB_EQ, + I128_SUB_EQ, + USIZE_SUB_EQ, + U8_SUB_EQ, + U16_SUB_EQ, + U32_SUB_EQ, + U64_SUB_EQ, + U128_SUB_EQ +] + +Theorem U8_MUL_EQ: + !x y. + u8_to_int x * u8_to_int y <= u8_max ==> + ?z. u8_mul x y = Return z /\ u8_to_int z = u8_to_int x * u8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U16_MUL_EQ: + !x y. + u16_to_int x * u16_to_int y <= u16_max ==> + ?z. u16_mul x y = Return z /\ u16_to_int z = u16_to_int x * u16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U32_MUL_EQ: + !x y. + u32_to_int x * u32_to_int y <= u32_max ==> + ?z. u32_mul x y = Return z /\ u32_to_int z = u32_to_int x * u32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U64_MUL_EQ: + !x y. + u64_to_int x * u64_to_int y <= u64_max ==> + ?z. u64_mul x y = Return z /\ u64_to_int z = u64_to_int x * u64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U128_MUL_EQ: + !x y. + u128_to_int x * u128_to_int y <= u128_max ==> + ?z. u128_mul x y = Return z /\ u128_to_int z = u128_to_int x * u128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem USIZE_MUL_EQ: + !x y. + (usize_to_int x * usize_to_int y <= u16_max) \/ (usize_to_int x * usize_to_int y <= usize_max) ==> + ?z. usize_mul x y = Return z /\ usize_to_int z = usize_to_int x * usize_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I8_MUL_EQ: + !x y. + i8_min <= i8_to_int x * i8_to_int y ==> + i8_to_int x * i8_to_int y <= i8_max ==> + ?z. i8_mul x y = Return z /\ i8_to_int z = i8_to_int x * i8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I16_MUL_EQ: + !x y. + i16_min <= i16_to_int x * i16_to_int y ==> + i16_to_int x * i16_to_int y <= i16_max ==> + ?z. i16_mul x y = Return z /\ i16_to_int z = i16_to_int x * i16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I32_MUL_EQ: + !x y. + i32_min <= i32_to_int x * i32_to_int y ==> + i32_to_int x * i32_to_int y <= i32_max ==> + ?z. i32_mul x y = Return z /\ i32_to_int z = i32_to_int x * i32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I64_MUL_EQ: + !x y. + i64_min <= i64_to_int x * i64_to_int y ==> + i64_to_int x * i64_to_int y <= i64_max ==> + ?z. i64_mul x y = Return z /\ i64_to_int z = i64_to_int x * i64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I128_MUL_EQ: + !x y. + i128_min <= i128_to_int x * i128_to_int y ==> + i128_to_int x * i128_to_int y <= i128_max ==> + ?z. i128_mul x y = Return z /\ i128_to_int z = i128_to_int x * i128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem ISIZE_MUL_EQ: + !x y. + (i16_min <= isize_to_int x * isize_to_int y \/ isize_min <= isize_to_int x * isize_to_int y) ==> + (isize_to_int x * isize_to_int y <= i16_max \/ isize_to_int x * isize_to_int y <= isize_max) ==> + ?z. isize_mul x y = Return z /\ isize_to_int z = isize_to_int x * isize_to_int y +Proof + prove_arith_op_eq +QED + +val all_mul_eqs = [ + ISIZE_MUL_EQ, + I8_MUL_EQ, + I16_MUL_EQ, + I32_MUL_EQ, + I64_MUL_EQ, + I128_MUL_EQ, + USIZE_MUL_EQ, + U8_MUL_EQ, + U16_MUL_EQ, + U32_MUL_EQ, + U64_MUL_EQ, + U128_MUL_EQ +] + +Theorem U8_DIV_EQ: + !x y. + u8_to_int y <> 0 ==> + ?z. u8_div x y = Return z /\ u8_to_int z = u8_to_int x / u8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U16_DIV_EQ: + !x y. + u16_to_int y <> 0 ==> + ?z. u16_div x y = Return z /\ u16_to_int z = u16_to_int x / u16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U32_DIV_EQ: + !x y. + u32_to_int y <> 0 ==> + ?z. u32_div x y = Return z /\ u32_to_int z = u32_to_int x / u32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U64_DIV_EQ: + !x y. + u64_to_int y <> 0 ==> + ?z. u64_div x y = Return z /\ u64_to_int z = u64_to_int x / u64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U128_DIV_EQ: + !x y. + u128_to_int y <> 0 ==> + ?z. u128_div x y = Return z /\ u128_to_int z = u128_to_int x / u128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem USIZE_DIV_EQ: + !x y. + usize_to_int y <> 0 ==> + ?z. usize_div x y = Return z /\ usize_to_int z = usize_to_int x / usize_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I8_DIV_EQ: + !x y. + i8_to_int y <> 0 ==> + i8_min <= i8_to_int x / i8_to_int y ==> + i8_to_int x / i8_to_int y <= i8_max ==> + ?z. i8_div x y = Return z /\ i8_to_int z = i8_to_int x / i8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I16_DIV_EQ: + !x y. + i16_to_int y <> 0 ==> + i16_min <= i16_to_int x / i16_to_int y ==> + i16_to_int x / i16_to_int y <= i16_max ==> + ?z. i16_div x y = Return z /\ i16_to_int z = i16_to_int x / i16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I32_DIV_EQ: + !x y. + i32_to_int y <> 0 ==> + i32_min <= i32_to_int x / i32_to_int y ==> + i32_to_int x / i32_to_int y <= i32_max ==> + ?z. i32_div x y = Return z /\ i32_to_int z = i32_to_int x / i32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I64_DIV_EQ: + !x y. + i64_to_int y <> 0 ==> + i64_min <= i64_to_int x / i64_to_int y ==> + i64_to_int x / i64_to_int y <= i64_max ==> + ?z. i64_div x y = Return z /\ i64_to_int z = i64_to_int x / i64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I128_DIV_EQ: + !x y. + i128_to_int y <> 0 ==> + i128_min <= i128_to_int x / i128_to_int y ==> + i128_to_int x / i128_to_int y <= i128_max ==> + ?z. i128_div x y = Return z /\ i128_to_int z = i128_to_int x / i128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem ISIZE_DIV_EQ: + !x y. + isize_to_int y <> 0 ==> + (i16_min <= isize_to_int x / isize_to_int y \/ isize_min <= isize_to_int x / isize_to_int y) ==> + (isize_to_int x / isize_to_int y <= i16_max \/ isize_to_int x / isize_to_int y <= isize_max) ==> + ?z. isize_div x y = Return z /\ isize_to_int z = isize_to_int x / isize_to_int y +Proof + prove_arith_op_eq +QED + +val all_div_eqs = [ + ISIZE_DIV_EQ, + I8_DIV_EQ, + I16_DIV_EQ, + I32_DIV_EQ, + I64_DIV_EQ, + I128_DIV_EQ, + USIZE_DIV_EQ, + U8_DIV_EQ, + U16_DIV_EQ, + U32_DIV_EQ, + U64_DIV_EQ, + U128_DIV_EQ +] + +Theorem U8_REM_EQ: + !x y. + u8_to_int y <> 0 ==> + ?z. u8_rem x y = Return z /\ u8_to_int z = int_rem (u8_to_int x) (u8_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem U16_REM_EQ: + !x y. + u16_to_int y <> 0 ==> + ?z. u16_rem x y = Return z /\ u16_to_int z = int_rem (u16_to_int x) (u16_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem U32_REM_EQ: + !x y. + u32_to_int y <> 0 ==> + ?z. u32_rem x y = Return z /\ u32_to_int z = int_rem (u32_to_int x) (u32_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem U64_REM_EQ: + !x y. + u64_to_int y <> 0 ==> + ?z. u64_rem x y = Return z /\ u64_to_int z = int_rem (u64_to_int x) (u64_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem U128_REM_EQ: + !x y. + u128_to_int y <> 0 ==> + ?z. u128_rem x y = Return z /\ u128_to_int z = int_rem (u128_to_int x) (u128_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem USIZE_REM_EQ: + !x y. + usize_to_int y <> 0 ==> + ?z. usize_rem x y = Return z /\ usize_to_int z = int_rem (usize_to_int x) (usize_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem I8_REM_EQ: + !x y. + i8_to_int y <> 0 ==> + i8_min <= int_rem (i8_to_int x) (i8_to_int y) ==> + int_rem (i8_to_int x) (i8_to_int y) <= i8_max ==> + ?z. i8_rem x y = Return z /\ i8_to_int z = int_rem (i8_to_int x) (i8_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem I16_REM_EQ: + !x y. + i16_to_int y <> 0 ==> + i16_min <= int_rem (i16_to_int x) (i16_to_int y) ==> + int_rem (i16_to_int x) (i16_to_int y) <= i16_max ==> + ?z. i16_rem x y = Return z /\ i16_to_int z = int_rem (i16_to_int x) (i16_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem I32_REM_EQ: + !x y. + i32_to_int y <> 0 ==> + i32_min <= int_rem (i32_to_int x) (i32_to_int y) ==> + int_rem (i32_to_int x) (i32_to_int y) <= i32_max ==> + ?z. i32_rem x y = Return z /\ i32_to_int z = int_rem (i32_to_int x) (i32_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem I64_REM_EQ: + !x y. + i64_to_int y <> 0 ==> + i64_min <= int_rem (i64_to_int x) (i64_to_int y) ==> + int_rem (i64_to_int x) (i64_to_int y) <= i64_max ==> + ?z. i64_rem x y = Return z /\ i64_to_int z = int_rem (i64_to_int x) (i64_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem I8_REM_EQ: + !x y. + i8_to_int y <> 0 ==> + i8_min <= int_rem (i8_to_int x) (i8_to_int y) ==> + int_rem (i8_to_int x) (i8_to_int y) <= i8_max ==> + ?z. i8_rem x y = Return z /\ i8_to_int z = int_rem (i8_to_int x) (i8_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem I8_REM_EQ: + !x y. + i8_to_int y <> 0 ==> + i8_min <= int_rem (i8_to_int x) (i8_to_int y) ==> + int_rem (i8_to_int x) (i8_to_int y) <= i8_max ==> + ?z. i8_rem x y = Return z /\ i8_to_int z = int_rem (i8_to_int x) (i8_to_int y) +Proof + prove_arith_op_eq +QED + +Theorem U16_DIV_EQ: + !x y. + u16_to_int y <> 0 ==> + ?z. u16_div x y = Return z /\ u16_to_int z = u16_to_int x / u16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U32_DIV_EQ: + !x y. + u32_to_int y <> 0 ==> + ?z. u32_div x y = Return z /\ u32_to_int z = u32_to_int x / u32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U64_DIV_EQ: + !x y. + u64_to_int y <> 0 ==> + ?z. u64_div x y = Return z /\ u64_to_int z = u64_to_int x / u64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem U128_DIV_EQ: + !x y. + u128_to_int y <> 0 ==> + ?z. u128_div x y = Return z /\ u128_to_int z = u128_to_int x / u128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem USIZE_DIV_EQ: + !x y. + usize_to_int y <> 0 ==> + ?z. usize_div x y = Return z /\ usize_to_int z = usize_to_int x / usize_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I8_DIV_EQ: + !x y. + i8_to_int y <> 0 ==> + i8_min <= i8_to_int x / i8_to_int y ==> + i8_to_int x / i8_to_int y <= i8_max ==> + ?z. i8_div x y = Return z /\ i8_to_int z = i8_to_int x / i8_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I16_DIV_EQ: + !x y. + i16_to_int y <> 0 ==> + i16_min <= i16_to_int x / i16_to_int y ==> + i16_to_int x / i16_to_int y <= i16_max ==> + ?z. i16_div x y = Return z /\ i16_to_int z = i16_to_int x / i16_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I32_DIV_EQ: + !x y. + i32_to_int y <> 0 ==> + i32_min <= i32_to_int x / i32_to_int y ==> + i32_to_int x / i32_to_int y <= i32_max ==> + ?z. i32_div x y = Return z /\ i32_to_int z = i32_to_int x / i32_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I64_DIV_EQ: + !x y. + i64_to_int y <> 0 ==> + i64_min <= i64_to_int x / i64_to_int y ==> + i64_to_int x / i64_to_int y <= i64_max ==> + ?z. i64_div x y = Return z /\ i64_to_int z = i64_to_int x / i64_to_int y +Proof + prove_arith_op_eq +QED + +Theorem I128_DIV_EQ: + !x y. + i128_to_int y <> 0 ==> + i128_min <= i128_to_int x / i128_to_int y ==> + i128_to_int x / i128_to_int y <= i128_max ==> + ?z. i128_div x y = Return z /\ i128_to_int z = i128_to_int x / i128_to_int y +Proof + prove_arith_op_eq +QED + +Theorem ISIZE_DIV_EQ: + !x y. + isize_to_int y <> 0 ==> + (i16_min <= isize_to_int x / isize_to_int y \/ isize_min <= isize_to_int x / isize_to_int y) ==> + (isize_to_int x / isize_to_int y <= i16_max \/ isize_to_int x / isize_to_int y <= isize_max) ==> + ?z. isize_div x y = Return z /\ isize_to_int z = isize_to_int x / isize_to_int y +Proof + prove_arith_op_eq +QED + +val all_div_eqs = [ + ISIZE_DIV_EQ, + I8_DIV_EQ, + I16_DIV_EQ, + I32_DIV_EQ, + I64_DIV_EQ, + I128_DIV_EQ, + USIZE_DIV_EQ, + U8_DIV_EQ, + U16_DIV_EQ, + U32_DIV_EQ, + U64_DIV_EQ, + U128_DIV_EQ +] + +val _ = export_theory () diff --git a/backends/hol4/PrimitivesTheory.sig b/backends/hol4/PrimitivesTheory.sig new file mode 100644 index 00000000..8ec350e7 --- /dev/null +++ b/backends/hol4/PrimitivesTheory.sig @@ -0,0 +1,1667 @@ +signature PrimitivesTheory = +sig + type thm = Thm.thm + + (* Axioms *) + val i128_to_int_bounds : thm + val i16_to_int_bounds : thm + val i32_to_int_bounds : thm + val i64_to_int_bounds : thm + val i8_to_int_bounds : thm + val int_to_i128_id : thm + val int_to_i16_id : thm + val int_to_i32_id : thm + val int_to_i64_id : thm + val int_to_i8_id : thm + val int_to_isize_id : thm + val int_to_u128_id : thm + val int_to_u16_id : thm + val int_to_u32_id : thm + val int_to_u64_id : thm + val int_to_u8_id : thm + val int_to_usize_id : thm + val isize_bounds : thm + val isize_to_int_bounds : thm + val u128_to_int_bounds : thm + val u16_to_int_bounds : thm + val u32_to_int_bounds : thm + val u64_to_int_bounds : thm + val u8_to_int_bounds : thm + val usize_bounds : thm + val usize_to_int_bounds : thm + + (* Definitions *) + val bind_def : thm + val error_BIJ : thm + val error_CASE : thm + val error_TY_DEF : thm + val error_size_def : thm + val i128_add_def : thm + val i128_div_def : thm + val i128_max_def : thm + val i128_min_def : thm + val i128_mul_def : thm + val i128_rem_def : thm + val i128_sub_def : thm + val i16_add_def : thm + val i16_div_def : thm + val i16_max_def : thm + val i16_min_def : thm + val i16_mul_def : thm + val i16_rem_def : thm + val i16_sub_def : thm + val i32_add_def : thm + val i32_div_def : thm + val i32_max_def : thm + val i32_min_def : thm + val i32_mul_def : thm + val i32_rem_def : thm + val i32_sub_def : thm + val i64_add_def : thm + val i64_div_def : thm + val i64_max_def : thm + val i64_min_def : thm + val i64_mul_def : thm + val i64_rem_def : thm + val i64_sub_def : thm + val i8_add_def : thm + val i8_div_def : thm + val i8_max_def : thm + val i8_min_def : thm + val i8_mul_def : thm + val i8_rem_def : thm + val i8_sub_def : thm + val int_rem_def : thm + val isize_add_def : thm + val isize_div_def : thm + val isize_mul_def : thm + val isize_rem_def : thm + val isize_sub_def : thm + val massert_def : thm + val mem_replace_back_def : thm + val mem_replace_fwd_def : thm + val mk_i128_def : thm + val mk_i16_def : thm + val mk_i32_def : thm + val mk_i64_def : thm + val mk_i8_def : thm + val mk_isize_def : thm + val mk_u128_def : thm + val mk_u16_def : thm + val mk_u32_def : thm + val mk_u64_def : thm + val mk_u8_def : thm + val mk_usize_def : thm + val result_TY_DEF : thm + val result_case_def : thm + val result_size_def : thm + val return_def : thm + val u128_add_def : thm + val u128_div_def : thm + val u128_max_def : thm + val u128_mul_def : thm + val u128_rem_def : thm + val u128_sub_def : thm + val u16_add_def : thm + val u16_div_def : thm + val u16_max_def : thm + val u16_mul_def : thm + val u16_rem_def : thm + val u16_sub_def : thm + val u32_add_def : thm + val u32_div_def : thm + val u32_max_def : thm + val u32_mul_def : thm + val u32_rem_def : thm + val u32_sub_def : thm + val u64_add_def : thm + val u64_div_def : thm + val u64_max_def : thm + val u64_mul_def : thm + val u64_rem_def : thm + val u64_sub_def : thm + val u8_add_def : thm + val u8_div_def : thm + val u8_max_def : thm + val u8_mul_def : thm + val u8_rem_def : thm + val u8_sub_def : thm + val usize_add_def : thm + val usize_div_def : thm + val usize_mul_def : thm + val usize_rem_def : thm + val usize_sub_def : thm + + (* Theorems *) + val GE_EQ_LE : thm + val GT_EQ_LT : thm + val I128_ADD_EQ : thm + val I128_DIV_EQ : thm + val I128_MUL_EQ : thm + val I128_SUB_EQ : thm + val I16_ADD_EQ : thm + val I16_DIV_EQ : thm + val I16_MUL_EQ : thm + val I16_REM_EQ : thm + val I16_SUB_EQ : thm + val I32_ADD_EQ : thm + val I32_DIV_EQ : thm + val I32_MUL_EQ : thm + val I32_REM_EQ : thm + val I32_SUB_EQ : thm + val I64_ADD_EQ : thm + val I64_DIV_EQ : thm + val I64_MUL_EQ : thm + val I64_REM_EQ : thm + val I64_SUB_EQ : thm + val I8_ADD_EQ : thm + val I8_DIV_EQ : thm + val I8_MUL_EQ : thm + val I8_REM_EQ : thm + val I8_SUB_EQ : thm + val ISIZE_ADD_EQ : thm + val ISIZE_DIV_EQ : thm + val ISIZE_MUL_EQ : thm + val ISIZE_SUB_EQ : thm + val LE_EQ_GE : thm + val LT_EQ_GT : thm + val NOT_GE_EQ_LT : thm + val NOT_GT_EQ_LE : thm + val NOT_LE_EQ_GT : thm + val NOT_LT_EQ_GE : thm + val POS_DIV_POS_IS_POS : thm + val POS_DIV_POS_LE : thm + val POS_DIV_POS_LE_INIT : thm + val POS_MOD_POS_IS_POS : thm + val POS_MOD_POS_LE_INIT : thm + val POS_MUL_POS_IS_POS : thm + val U128_ADD_EQ : thm + val U128_DIV_EQ : thm + val U128_MUL_EQ : thm + val U128_REM_EQ : thm + val U128_SUB_EQ : thm + val U16_ADD_EQ : thm + val U16_DIV_EQ : thm + val U16_MUL_EQ : thm + val U16_REM_EQ : thm + val U16_SUB_EQ : thm + val U32_ADD_EQ : thm + val U32_DIV_EQ : thm + val U32_MUL_EQ : thm + val U32_REM_EQ : thm + val U32_SUB_EQ : thm + val U64_ADD_EQ : thm + val U64_DIV_EQ : thm + val U64_MUL_EQ : thm + val U64_REM_EQ : thm + val U64_SUB_EQ : thm + val U8_ADD_EQ : thm + val U8_DIV_EQ : thm + val U8_MUL_EQ : thm + val U8_REM_EQ : thm + val U8_SUB_EQ : thm + val USIZE_ADD_EQ : thm + val USIZE_DIV_EQ : thm + val USIZE_MUL_EQ : thm + val USIZE_REM_EQ : thm + val USIZE_SUB_EQ : thm + val datatype_error : thm + val datatype_result : thm + val error2num_11 : thm + val error2num_ONTO : thm + val error2num_num2error : thm + val error2num_thm : thm + val error_Axiom : thm + val error_EQ_error : thm + val error_case_cong : thm + val error_case_def : thm + val error_case_eq : thm + val error_induction : thm + val error_nchotomy : thm + val num2error_11 : thm + val num2error_ONTO : thm + val num2error_error2num : thm + val num2error_thm : thm + val result_11 : thm + val result_Axiom : thm + val result_case_cong : thm + val result_case_eq : thm + val result_distinct : thm + val result_induction : thm + val result_nchotomy : thm + + val Primitives_grammars : type_grammar.grammar * term_grammar.grammar +(* + [Omega] Parent theory of "Primitives" + + [int_arith] Parent theory of "Primitives" + + [string] Parent theory of "Primitives" + + [int_to_u128_id] Axiom + + [oracles: ] [axioms: int_to_u128_id] [] + ⊢ ∀n. 0 ≤ n ∧ n ≤ u128_max ⇒ u128_to_int (int_to_u128 n) = n + + [int_to_u64_id] Axiom + + [oracles: ] [axioms: int_to_u64_id] [] + ⊢ ∀n. 0 ≤ n ∧ n ≤ u64_max ⇒ u64_to_int (int_to_u64 n) = n + + [int_to_u32_id] Axiom + + [oracles: ] [axioms: int_to_u32_id] [] + ⊢ ∀n. 0 ≤ n ∧ n ≤ u32_max ⇒ u32_to_int (int_to_u32 n) = n + + [int_to_u16_id] Axiom + + [oracles: ] [axioms: int_to_u16_id] [] + ⊢ ∀n. 0 ≤ n ∧ n ≤ u16_max ⇒ u16_to_int (int_to_u16 n) = n + + [int_to_u8_id] Axiom + + [oracles: ] [axioms: int_to_u8_id] [] + ⊢ ∀n. 0 ≤ n ∧ n ≤ u8_max ⇒ u8_to_int (int_to_u8 n) = n + + [int_to_i128_id] Axiom + + [oracles: ] [axioms: int_to_i128_id] [] + ⊢ ∀n. i128_min ≤ n ∧ n ≤ i128_max ⇒ i128_to_int (int_to_i128 n) = n + + [int_to_i64_id] Axiom + + [oracles: ] [axioms: int_to_i64_id] [] + ⊢ ∀n. i64_min ≤ n ∧ n ≤ i64_max ⇒ i64_to_int (int_to_i64 n) = n + + [int_to_i32_id] Axiom + + [oracles: ] [axioms: int_to_i32_id] [] + ⊢ ∀n. i32_min ≤ n ∧ n ≤ i32_max ⇒ i32_to_int (int_to_i32 n) = n + + [int_to_i16_id] Axiom + + [oracles: ] [axioms: int_to_i16_id] [] + ⊢ ∀n. i16_min ≤ n ∧ n ≤ i16_max ⇒ i16_to_int (int_to_i16 n) = n + + [int_to_i8_id] Axiom + + [oracles: ] [axioms: int_to_i8_id] [] + ⊢ ∀n. i8_min ≤ n ∧ n ≤ i8_max ⇒ i8_to_int (int_to_i8 n) = n + + [int_to_usize_id] Axiom + + [oracles: ] [axioms: int_to_usize_id] [] + ⊢ ∀n. 0 ≤ n ∧ (n ≤ u16_max ∨ n ≤ usize_max) ⇒ + usize_to_int (int_to_usize n) = n + + [int_to_isize_id] Axiom + + [oracles: ] [axioms: int_to_isize_id] [] + ⊢ ∀n. (i16_min ≤ n ∨ isize_min ≤ n) ∧ (n ≤ i16_max ∨ n ≤ isize_max) ⇒ + isize_to_int (int_to_isize n) = n + + [u128_to_int_bounds] Axiom + + [oracles: ] [axioms: u128_to_int_bounds] [] + ⊢ ∀n. 0 ≤ u128_to_int n ∧ u128_to_int n ≤ u128_max + + [u64_to_int_bounds] Axiom + + [oracles: ] [axioms: u64_to_int_bounds] [] + ⊢ ∀n. 0 ≤ u64_to_int n ∧ u64_to_int n ≤ u64_max + + [u32_to_int_bounds] Axiom + + [oracles: ] [axioms: u32_to_int_bounds] [] + ⊢ ∀n. 0 ≤ u32_to_int n ∧ u32_to_int n ≤ u32_max + + [u16_to_int_bounds] Axiom + + [oracles: ] [axioms: u16_to_int_bounds] [] + ⊢ ∀n. 0 ≤ u16_to_int n ∧ u16_to_int n ≤ u16_max + + [u8_to_int_bounds] Axiom + + [oracles: ] [axioms: u8_to_int_bounds] [] + ⊢ ∀n. 0 ≤ u8_to_int n ∧ u8_to_int n ≤ u8_max + + [usize_to_int_bounds] Axiom + + [oracles: ] [axioms: usize_to_int_bounds] [] + ⊢ ∀n. 0 ≤ usize_to_int n ∧ usize_to_int n ≤ usize_max + + [i128_to_int_bounds] Axiom + + [oracles: ] [axioms: i128_to_int_bounds] [] + ⊢ ∀n. i128_min ≤ i128_to_int n ∧ i128_to_int n ≤ i128_max + + [i64_to_int_bounds] Axiom + + [oracles: ] [axioms: i64_to_int_bounds] [] + ⊢ ∀n. i64_min ≤ i64_to_int n ∧ i64_to_int n ≤ i64_max + + [i32_to_int_bounds] Axiom + + [oracles: ] [axioms: i32_to_int_bounds] [] + ⊢ ∀n. i32_min ≤ i32_to_int n ∧ i32_to_int n ≤ i32_max + + [i16_to_int_bounds] Axiom + + [oracles: ] [axioms: i16_to_int_bounds] [] + ⊢ ∀n. i16_min ≤ i16_to_int n ∧ i16_to_int n ≤ i16_max + + [i8_to_int_bounds] Axiom + + [oracles: ] [axioms: i8_to_int_bounds] [] + ⊢ ∀n. i8_min ≤ i8_to_int n ∧ i8_to_int n ≤ i8_max + + [isize_to_int_bounds] Axiom + + [oracles: ] [axioms: isize_to_int_bounds] [] + ⊢ ∀n. isize_min ≤ isize_to_int n ∧ isize_to_int n ≤ isize_max + + [usize_bounds] Axiom + + [oracles: ] [axioms: usize_bounds] [] ⊢ usize_max ≥ u16_max + + [isize_bounds] Axiom + + [oracles: ] [axioms: isize_bounds] [] + ⊢ isize_min ≤ i16_min ∧ isize_max ≥ i16_max + + [bind_def] Definition + + ⊢ ∀x f. + monad_bind x f = + case x of Return y => f y | Fail e => Fail e | Loop => Loop + + [error_BIJ] Definition + + ⊢ (∀a. num2error (error2num a) = a) ∧ + ∀r. (λn. n < 1) r ⇔ error2num (num2error r) = r + + [error_CASE] Definition + + ⊢ ∀x v0. (case x of Failure => v0) = (λm. v0) (error2num x) + + [error_TY_DEF] Definition + + ⊢ ∃rep. TYPE_DEFINITION (λn. n < 1) rep + + [error_size_def] Definition + + ⊢ ∀x. error_size x = 0 + + [i128_add_def] Definition + + ⊢ ∀x y. i128_add x y = mk_i128 (i128_to_int x + i128_to_int y) + + [i128_div_def] Definition + + ⊢ ∀x y. + i128_div x y = + if i128_to_int y = 0 then Fail Failure + else mk_i128 (i128_to_int x / i128_to_int y) + + [i128_max_def] Definition + + ⊢ i128_max = 170141183460469231731687303715884105727 + + [i128_min_def] Definition + + ⊢ i128_min = -170141183460469231731687303715884105728 + + [i128_mul_def] Definition + + ⊢ ∀x y. i128_mul x y = mk_i128 (i128_to_int x * i128_to_int y) + + [i128_rem_def] Definition + + ⊢ ∀x y. + i128_rem x y = + if i128_to_int y = 0 then Fail Failure + else mk_i128 (int_rem (i128_to_int x) (i128_to_int y)) + + [i128_sub_def] Definition + + ⊢ ∀x y. i128_sub x y = mk_i128 (i128_to_int x − i128_to_int y) + + [i16_add_def] Definition + + ⊢ ∀x y. i16_add x y = mk_i16 (i16_to_int x + i16_to_int y) + + [i16_div_def] Definition + + ⊢ ∀x y. + i16_div x y = + if i16_to_int y = 0 then Fail Failure + else mk_i16 (i16_to_int x / i16_to_int y) + + [i16_max_def] Definition + + ⊢ i16_max = 32767 + + [i16_min_def] Definition + + ⊢ i16_min = -32768 + + [i16_mul_def] Definition + + ⊢ ∀x y. i16_mul x y = mk_i16 (i16_to_int x * i16_to_int y) + + [i16_rem_def] Definition + + ⊢ ∀x y. + i16_rem x y = + if i16_to_int y = 0 then Fail Failure + else mk_i16 (int_rem (i16_to_int x) (i16_to_int y)) + + [i16_sub_def] Definition + + ⊢ ∀x y. i16_sub x y = mk_i16 (i16_to_int x − i16_to_int y) + + [i32_add_def] Definition + + ⊢ ∀x y. i32_add x y = mk_i32 (i32_to_int x + i32_to_int y) + + [i32_div_def] Definition + + ⊢ ∀x y. + i32_div x y = + if i32_to_int y = 0 then Fail Failure + else mk_i32 (i32_to_int x / i32_to_int y) + + [i32_max_def] Definition + + ⊢ i32_max = 2147483647 + + [i32_min_def] Definition + + ⊢ i32_min = -2147483648 + + [i32_mul_def] Definition + + ⊢ ∀x y. i32_mul x y = mk_i32 (i32_to_int x * i32_to_int y) + + [i32_rem_def] Definition + + ⊢ ∀x y. + i32_rem x y = + if i32_to_int y = 0 then Fail Failure + else mk_i32 (int_rem (i32_to_int x) (i32_to_int y)) + + [i32_sub_def] Definition + + ⊢ ∀x y. i32_sub x y = mk_i32 (i32_to_int x − i32_to_int y) + + [i64_add_def] Definition + + ⊢ ∀x y. i64_add x y = mk_i64 (i64_to_int x + i64_to_int y) + + [i64_div_def] Definition + + ⊢ ∀x y. + i64_div x y = + if i64_to_int y = 0 then Fail Failure + else mk_i64 (i64_to_int x / i64_to_int y) + + [i64_max_def] Definition + + ⊢ i64_max = 9223372036854775807 + + [i64_min_def] Definition + + ⊢ i64_min = -9223372036854775808 + + [i64_mul_def] Definition + + ⊢ ∀x y. i64_mul x y = mk_i64 (i64_to_int x * i64_to_int y) + + [i64_rem_def] Definition + + ⊢ ∀x y. + i64_rem x y = + if i64_to_int y = 0 then Fail Failure + else mk_i64 (int_rem (i64_to_int x) (i64_to_int y)) + + [i64_sub_def] Definition + + ⊢ ∀x y. i64_sub x y = mk_i64 (i64_to_int x − i64_to_int y) + + [i8_add_def] Definition + + ⊢ ∀x y. i8_add x y = mk_i8 (i8_to_int x + i8_to_int y) + + [i8_div_def] Definition + + ⊢ ∀x y. + i8_div x y = + if i8_to_int y = 0 then Fail Failure + else mk_i8 (i8_to_int x / i8_to_int y) + + [i8_max_def] Definition + + ⊢ i8_max = 127 + + [i8_min_def] Definition + + ⊢ i8_min = -128 + + [i8_mul_def] Definition + + ⊢ ∀x y. i8_mul x y = mk_i8 (i8_to_int x * i8_to_int y) + + [i8_rem_def] Definition + + ⊢ ∀x y. + i8_rem x y = + if i8_to_int y = 0 then Fail Failure + else mk_i8 (int_rem (i8_to_int x) (i8_to_int y)) + + [i8_sub_def] Definition + + ⊢ ∀x y. i8_sub x y = mk_i8 (i8_to_int x − i8_to_int y) + + [int_rem_def] Definition + + ⊢ ∀x y. + int_rem x y = + if x ≥ 0 ∧ y ≥ 0 ∨ x < 0 ∧ y < 0 then x % y else -(x % y) + + [isize_add_def] Definition + + ⊢ ∀x y. isize_add x y = mk_isize (isize_to_int x + isize_to_int y) + + [isize_div_def] Definition + + ⊢ ∀x y. + isize_div x y = + if isize_to_int y = 0 then Fail Failure + else mk_isize (isize_to_int x / isize_to_int y) + + [isize_mul_def] Definition + + ⊢ ∀x y. isize_mul x y = mk_isize (isize_to_int x * isize_to_int y) + + [isize_rem_def] Definition + + ⊢ ∀x y. + isize_rem x y = + if isize_to_int y = 0 then Fail Failure + else mk_isize (int_rem (isize_to_int x) (isize_to_int y)) + + [isize_sub_def] Definition + + ⊢ ∀x y. isize_sub x y = mk_isize (isize_to_int x − isize_to_int y) + + [massert_def] Definition + + ⊢ ∀b. massert b = if b then Return () else Fail Failure + + [mem_replace_back_def] Definition + + ⊢ ∀x y. mem_replace_back x y = y + + [mem_replace_fwd_def] Definition + + ⊢ ∀x y. mem_replace_fwd x y = x + + [mk_i128_def] Definition + + ⊢ ∀n. mk_i128 n = + if i128_min ≤ n ∧ n ≤ i128_max then Return (int_to_i128 n) + else Fail Failure + + [mk_i16_def] Definition + + ⊢ ∀n. mk_i16 n = + if i16_min ≤ n ∧ n ≤ i16_max then Return (int_to_i16 n) + else Fail Failure + + [mk_i32_def] Definition + + ⊢ ∀n. mk_i32 n = + if i32_min ≤ n ∧ n ≤ i32_max then Return (int_to_i32 n) + else Fail Failure + + [mk_i64_def] Definition + + ⊢ ∀n. mk_i64 n = + if i64_min ≤ n ∧ n ≤ i64_max then Return (int_to_i64 n) + else Fail Failure + + [mk_i8_def] Definition + + ⊢ ∀n. mk_i8 n = + if i8_min ≤ n ∧ n ≤ i8_max then Return (int_to_i8 n) + else Fail Failure + + [mk_isize_def] Definition + + ⊢ ∀n. mk_isize n = + if isize_min ≤ n ∧ n ≤ isize_max then Return (int_to_isize n) + else Fail Failure + + [mk_u128_def] Definition + + ⊢ ∀n. mk_u128 n = + if 0 ≤ n ∧ n ≤ u128_max then Return (int_to_u128 n) + else Fail Failure + + [mk_u16_def] Definition + + ⊢ ∀n. mk_u16 n = + if 0 ≤ n ∧ n ≤ u16_max then Return (int_to_u16 n) + else Fail Failure + + [mk_u32_def] Definition + + ⊢ ∀n. mk_u32 n = + if 0 ≤ n ∧ n ≤ u32_max then Return (int_to_u32 n) + else Fail Failure + + [mk_u64_def] Definition + + ⊢ ∀n. mk_u64 n = + if 0 ≤ n ∧ n ≤ u64_max then Return (int_to_u64 n) + else Fail Failure + + [mk_u8_def] Definition + + ⊢ ∀n. mk_u8 n = + if 0 ≤ n ∧ n ≤ u8_max then Return (int_to_u8 n) + else Fail Failure + + [mk_usize_def] Definition + + ⊢ ∀n. mk_usize n = + if 0 ≤ n ∧ n ≤ usize_max then Return (int_to_usize n) + else Fail Failure + + [result_TY_DEF] Definition + + ⊢ ∃rep. + TYPE_DEFINITION + (λa0. + ∀ $var$('result'). + (∀a0. + (∃a. a0 = + (λa. + ind_type$CONSTR 0 (a,ARB) + (λn. ind_type$BOTTOM)) a) ∨ + (∃a. a0 = + (λa. + ind_type$CONSTR (SUC 0) (ARB,a) + (λn. ind_type$BOTTOM)) a) ∨ + a0 = + ind_type$CONSTR (SUC (SUC 0)) (ARB,ARB) + (λn. ind_type$BOTTOM) ⇒ + $var$('result') a0) ⇒ + $var$('result') a0) rep + + [result_case_def] Definition + + ⊢ (∀a f f1 v. result_CASE (Return a) f f1 v = f a) ∧ + (∀a f f1 v. result_CASE (Fail a) f f1 v = f1 a) ∧ + ∀f f1 v. result_CASE Loop f f1 v = v + + [result_size_def] Definition + + ⊢ (∀f a. result_size f (Return a) = 1 + f a) ∧ + (∀f a. result_size f (Fail a) = 1 + error_size a) ∧ + ∀f. result_size f Loop = 0 + + [return_def] Definition + + ⊢ ∀x. return x = Return x + + [u128_add_def] Definition + + ⊢ ∀x y. u128_add x y = mk_u128 (u128_to_int x + u128_to_int y) + + [u128_div_def] Definition + + ⊢ ∀x y. + u128_div x y = + if u128_to_int y = 0 then Fail Failure + else mk_u128 (u128_to_int x / u128_to_int y) + + [u128_max_def] Definition + + ⊢ u128_max = 340282366920938463463374607431768211455 + + [u128_mul_def] Definition + + ⊢ ∀x y. u128_mul x y = mk_u128 (u128_to_int x * u128_to_int y) + + [u128_rem_def] Definition + + ⊢ ∀x y. + u128_rem x y = + if u128_to_int y = 0 then Fail Failure + else mk_u128 (int_rem (u128_to_int x) (u128_to_int y)) + + [u128_sub_def] Definition + + ⊢ ∀x y. u128_sub x y = mk_u128 (u128_to_int x − u128_to_int y) + + [u16_add_def] Definition + + ⊢ ∀x y. u16_add x y = mk_u16 (u16_to_int x + u16_to_int y) + + [u16_div_def] Definition + + ⊢ ∀x y. + u16_div x y = + if u16_to_int y = 0 then Fail Failure + else mk_u16 (u16_to_int x / u16_to_int y) + + [u16_max_def] Definition + + ⊢ u16_max = 65535 + + [u16_mul_def] Definition + + ⊢ ∀x y. u16_mul x y = mk_u16 (u16_to_int x * u16_to_int y) + + [u16_rem_def] Definition + + ⊢ ∀x y. + u16_rem x y = + if u16_to_int y = 0 then Fail Failure + else mk_u16 (int_rem (u16_to_int x) (u16_to_int y)) + + [u16_sub_def] Definition + + ⊢ ∀x y. u16_sub x y = mk_u16 (u16_to_int x − u16_to_int y) + + [u32_add_def] Definition + + ⊢ ∀x y. u32_add x y = mk_u32 (u32_to_int x + u32_to_int y) + + [u32_div_def] Definition + + ⊢ ∀x y. + u32_div x y = + if u32_to_int y = 0 then Fail Failure + else mk_u32 (u32_to_int x / u32_to_int y) + + [u32_max_def] Definition + + ⊢ u32_max = 4294967295 + + [u32_mul_def] Definition + + ⊢ ∀x y. u32_mul x y = mk_u32 (u32_to_int x * u32_to_int y) + + [u32_rem_def] Definition + + ⊢ ∀x y. + u32_rem x y = + if u32_to_int y = 0 then Fail Failure + else mk_u32 (int_rem (u32_to_int x) (u32_to_int y)) + + [u32_sub_def] Definition + + ⊢ ∀x y. u32_sub x y = mk_u32 (u32_to_int x − u32_to_int y) + + [u64_add_def] Definition + + ⊢ ∀x y. u64_add x y = mk_u64 (u64_to_int x + u64_to_int y) + + [u64_div_def] Definition + + ⊢ ∀x y. + u64_div x y = + if u64_to_int y = 0 then Fail Failure + else mk_u64 (u64_to_int x / u64_to_int y) + + [u64_max_def] Definition + + ⊢ u64_max = 18446744073709551615 + + [u64_mul_def] Definition + + ⊢ ∀x y. u64_mul x y = mk_u64 (u64_to_int x * u64_to_int y) + + [u64_rem_def] Definition + + ⊢ ∀x y. + u64_rem x y = + if u64_to_int y = 0 then Fail Failure + else mk_u64 (int_rem (u64_to_int x) (u64_to_int y)) + + [u64_sub_def] Definition + + ⊢ ∀x y. u64_sub x y = mk_u64 (u64_to_int x − u64_to_int y) + + [u8_add_def] Definition + + ⊢ ∀x y. u8_add x y = mk_u8 (u8_to_int x + u8_to_int y) + + [u8_div_def] Definition + + ⊢ ∀x y. + u8_div x y = + if u8_to_int y = 0 then Fail Failure + else mk_u8 (u8_to_int x / u8_to_int y) + + [u8_max_def] Definition + + ⊢ u8_max = 255 + + [u8_mul_def] Definition + + ⊢ ∀x y. u8_mul x y = mk_u8 (u8_to_int x * u8_to_int y) + + [u8_rem_def] Definition + + ⊢ ∀x y. + u8_rem x y = + if u8_to_int y = 0 then Fail Failure + else mk_u8 (int_rem (u8_to_int x) (u8_to_int y)) + + [u8_sub_def] Definition + + ⊢ ∀x y. u8_sub x y = mk_u8 (u8_to_int x − u8_to_int y) + + [usize_add_def] Definition + + ⊢ ∀x y. usize_add x y = mk_usize (usize_to_int x + usize_to_int y) + + [usize_div_def] Definition + + ⊢ ∀x y. + usize_div x y = + if usize_to_int y = 0 then Fail Failure + else mk_usize (usize_to_int x / usize_to_int y) + + [usize_mul_def] Definition + + ⊢ ∀x y. usize_mul x y = mk_usize (usize_to_int x * usize_to_int y) + + [usize_rem_def] Definition + + ⊢ ∀x y. + usize_rem x y = + if usize_to_int y = 0 then Fail Failure + else mk_usize (int_rem (usize_to_int x) (usize_to_int y)) + + [usize_sub_def] Definition + + ⊢ ∀x y. usize_sub x y = mk_usize (usize_to_int x − usize_to_int y) + + [GE_EQ_LE] Theorem + + ⊢ ∀x y. x ≥ y ⇔ y ≤ x + + [GT_EQ_LT] Theorem + + ⊢ ∀x y. x > y ⇔ y < x + + [I128_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i128_id, usize_bounds] [] + ⊢ ∀x y. + i128_min ≤ i128_to_int x + i128_to_int y ⇒ + i128_to_int x + i128_to_int y ≤ i128_max ⇒ + ∃z. i128_add x y = Return z ∧ + i128_to_int z = i128_to_int x + i128_to_int y + + [I128_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i128_id, usize_bounds] [] + ⊢ ∀x y. + i128_to_int y ≠ 0 ⇒ + i128_min ≤ i128_to_int x / i128_to_int y ⇒ + i128_to_int x / i128_to_int y ≤ i128_max ⇒ + ∃z. i128_div x y = Return z ∧ + i128_to_int z = i128_to_int x / i128_to_int y + + [I128_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i128_id, usize_bounds] [] + ⊢ ∀x y. + i128_min ≤ i128_to_int x * i128_to_int y ⇒ + i128_to_int x * i128_to_int y ≤ i128_max ⇒ + ∃z. i128_mul x y = Return z ∧ + i128_to_int z = i128_to_int x * i128_to_int y + + [I128_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i128_id, usize_bounds] [] + ⊢ ∀x y. + i128_min ≤ i128_to_int x − i128_to_int y ⇒ + i128_to_int x − i128_to_int y ≤ i128_max ⇒ + ∃z. i128_sub x y = Return z ∧ + i128_to_int z = i128_to_int x − i128_to_int y + + [I16_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i16_id, usize_bounds] [] + ⊢ ∀x y. + i16_min ≤ i16_to_int x + i16_to_int y ⇒ + i16_to_int x + i16_to_int y ≤ i16_max ⇒ + ∃z. i16_add x y = Return z ∧ + i16_to_int z = i16_to_int x + i16_to_int y + + [I16_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i16_id, usize_bounds] [] + ⊢ ∀x y. + i16_to_int y ≠ 0 ⇒ + i16_min ≤ i16_to_int x / i16_to_int y ⇒ + i16_to_int x / i16_to_int y ≤ i16_max ⇒ + ∃z. i16_div x y = Return z ∧ + i16_to_int z = i16_to_int x / i16_to_int y + + [I16_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i16_id, usize_bounds] [] + ⊢ ∀x y. + i16_min ≤ i16_to_int x * i16_to_int y ⇒ + i16_to_int x * i16_to_int y ≤ i16_max ⇒ + ∃z. i16_mul x y = Return z ∧ + i16_to_int z = i16_to_int x * i16_to_int y + + [I16_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i16_id, i16_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + i16_to_int y ≠ 0 ⇒ + i16_min ≤ int_rem (i16_to_int x) (i16_to_int y) ⇒ + int_rem (i16_to_int x) (i16_to_int y) ≤ i16_max ⇒ + ∃z. i16_rem x y = Return z ∧ + i16_to_int z = int_rem (i16_to_int x) (i16_to_int y) + + [I16_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i16_id, usize_bounds] [] + ⊢ ∀x y. + i16_min ≤ i16_to_int x − i16_to_int y ⇒ + i16_to_int x − i16_to_int y ≤ i16_max ⇒ + ∃z. i16_sub x y = Return z ∧ + i16_to_int z = i16_to_int x − i16_to_int y + + [I32_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i32_id, usize_bounds] [] + ⊢ ∀x y. + i32_min ≤ i32_to_int x + i32_to_int y ⇒ + i32_to_int x + i32_to_int y ≤ i32_max ⇒ + ∃z. i32_add x y = Return z ∧ + i32_to_int z = i32_to_int x + i32_to_int y + + [I32_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i32_id, usize_bounds] [] + ⊢ ∀x y. + i32_to_int y ≠ 0 ⇒ + i32_min ≤ i32_to_int x / i32_to_int y ⇒ + i32_to_int x / i32_to_int y ≤ i32_max ⇒ + ∃z. i32_div x y = Return z ∧ + i32_to_int z = i32_to_int x / i32_to_int y + + [I32_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i32_id, usize_bounds] [] + ⊢ ∀x y. + i32_min ≤ i32_to_int x * i32_to_int y ⇒ + i32_to_int x * i32_to_int y ≤ i32_max ⇒ + ∃z. i32_mul x y = Return z ∧ + i32_to_int z = i32_to_int x * i32_to_int y + + [I32_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i32_id, i32_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + i32_to_int y ≠ 0 ⇒ + i32_min ≤ int_rem (i32_to_int x) (i32_to_int y) ⇒ + int_rem (i32_to_int x) (i32_to_int y) ≤ i32_max ⇒ + ∃z. i32_rem x y = Return z ∧ + i32_to_int z = int_rem (i32_to_int x) (i32_to_int y) + + [I32_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i32_id, usize_bounds] [] + ⊢ ∀x y. + i32_min ≤ i32_to_int x − i32_to_int y ⇒ + i32_to_int x − i32_to_int y ≤ i32_max ⇒ + ∃z. i32_sub x y = Return z ∧ + i32_to_int z = i32_to_int x − i32_to_int y + + [I64_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i64_id, usize_bounds] [] + ⊢ ∀x y. + i64_min ≤ i64_to_int x + i64_to_int y ⇒ + i64_to_int x + i64_to_int y ≤ i64_max ⇒ + ∃z. i64_add x y = Return z ∧ + i64_to_int z = i64_to_int x + i64_to_int y + + [I64_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i64_id, usize_bounds] [] + ⊢ ∀x y. + i64_to_int y ≠ 0 ⇒ + i64_min ≤ i64_to_int x / i64_to_int y ⇒ + i64_to_int x / i64_to_int y ≤ i64_max ⇒ + ∃z. i64_div x y = Return z ∧ + i64_to_int z = i64_to_int x / i64_to_int y + + [I64_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i64_id, usize_bounds] [] + ⊢ ∀x y. + i64_min ≤ i64_to_int x * i64_to_int y ⇒ + i64_to_int x * i64_to_int y ≤ i64_max ⇒ + ∃z. i64_mul x y = Return z ∧ + i64_to_int z = i64_to_int x * i64_to_int y + + [I64_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i64_id, i64_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + i64_to_int y ≠ 0 ⇒ + i64_min ≤ int_rem (i64_to_int x) (i64_to_int y) ⇒ + int_rem (i64_to_int x) (i64_to_int y) ≤ i64_max ⇒ + ∃z. i64_rem x y = Return z ∧ + i64_to_int z = int_rem (i64_to_int x) (i64_to_int y) + + [I64_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i64_id, usize_bounds] [] + ⊢ ∀x y. + i64_min ≤ i64_to_int x − i64_to_int y ⇒ + i64_to_int x − i64_to_int y ≤ i64_max ⇒ + ∃z. i64_sub x y = Return z ∧ + i64_to_int z = i64_to_int x − i64_to_int y + + [I8_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i8_id, usize_bounds] [] + ⊢ ∀x y. + i8_min ≤ i8_to_int x + i8_to_int y ⇒ + i8_to_int x + i8_to_int y ≤ i8_max ⇒ + ∃z. i8_add x y = Return z ∧ + i8_to_int z = i8_to_int x + i8_to_int y + + [I8_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i8_id, usize_bounds] [] + ⊢ ∀x y. + i8_to_int y ≠ 0 ⇒ + i8_min ≤ i8_to_int x / i8_to_int y ⇒ + i8_to_int x / i8_to_int y ≤ i8_max ⇒ + ∃z. i8_div x y = Return z ∧ + i8_to_int z = i8_to_int x / i8_to_int y + + [I8_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i8_id, usize_bounds] [] + ⊢ ∀x y. + i8_min ≤ i8_to_int x * i8_to_int y ⇒ + i8_to_int x * i8_to_int y ≤ i8_max ⇒ + ∃z. i8_mul x y = Return z ∧ + i8_to_int z = i8_to_int x * i8_to_int y + + [I8_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i8_id, i8_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + i8_to_int y ≠ 0 ⇒ + i8_min ≤ int_rem (i8_to_int x) (i8_to_int y) ⇒ + int_rem (i8_to_int x) (i8_to_int y) ≤ i8_max ⇒ + ∃z. i8_rem x y = Return z ∧ + i8_to_int z = int_rem (i8_to_int x) (i8_to_int y) + + [I8_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_i8_id, usize_bounds] [] + ⊢ ∀x y. + i8_min ≤ i8_to_int x − i8_to_int y ⇒ + i8_to_int x − i8_to_int y ≤ i8_max ⇒ + ∃z. i8_sub x y = Return z ∧ + i8_to_int z = i8_to_int x − i8_to_int y + + [ISIZE_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_isize_id, isize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + i16_min ≤ isize_to_int x + isize_to_int y ∨ + isize_min ≤ isize_to_int x + isize_to_int y ⇒ + isize_to_int x + isize_to_int y ≤ i16_max ∨ + isize_to_int x + isize_to_int y ≤ isize_max ⇒ + ∃z. isize_add x y = Return z ∧ + isize_to_int z = isize_to_int x + isize_to_int y + + [ISIZE_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_isize_id, isize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + isize_to_int y ≠ 0 ⇒ + i16_min ≤ isize_to_int x / isize_to_int y ∨ + isize_min ≤ isize_to_int x / isize_to_int y ⇒ + isize_to_int x / isize_to_int y ≤ i16_max ∨ + isize_to_int x / isize_to_int y ≤ isize_max ⇒ + ∃z. isize_div x y = Return z ∧ + isize_to_int z = isize_to_int x / isize_to_int y + + [ISIZE_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_isize_id, isize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + i16_min ≤ isize_to_int x * isize_to_int y ∨ + isize_min ≤ isize_to_int x * isize_to_int y ⇒ + isize_to_int x * isize_to_int y ≤ i16_max ∨ + isize_to_int x * isize_to_int y ≤ isize_max ⇒ + ∃z. isize_mul x y = Return z ∧ + isize_to_int z = isize_to_int x * isize_to_int y + + [ISIZE_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_isize_id, isize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + i16_min ≤ isize_to_int x − isize_to_int y ∨ + isize_min ≤ isize_to_int x − isize_to_int y ⇒ + isize_to_int x − isize_to_int y ≤ i16_max ∨ + isize_to_int x − isize_to_int y ≤ isize_max ⇒ + ∃z. isize_sub x y = Return z ∧ + isize_to_int z = isize_to_int x − isize_to_int y + + [LE_EQ_GE] Theorem + + ⊢ ∀x y. x ≤ y ⇔ y ≥ x + + [LT_EQ_GT] Theorem + + ⊢ ∀x y. x < y ⇔ y > x + + [NOT_GE_EQ_LT] Theorem + + ⊢ ∀x y. ¬(x ≥ y) ⇔ x < y + + [NOT_GT_EQ_LE] Theorem + + ⊢ ∀x y. ¬(x > y) ⇔ x ≤ y + + [NOT_LE_EQ_GT] Theorem + + ⊢ ∀x y. ¬(x ≤ y) ⇔ x > y + + [NOT_LT_EQ_GE] Theorem + + ⊢ ∀x y. ¬(x < y) ⇔ x ≥ y + + [POS_DIV_POS_IS_POS] Theorem + + ⊢ ∀x y. 0 ≤ x ⇒ 0 < y ⇒ 0 ≤ x / y + + [POS_DIV_POS_LE] Theorem + + ⊢ ∀x y d. 0 ≤ x ⇒ 0 ≤ y ⇒ 0 < d ⇒ x ≤ y ⇒ x / d ≤ y / d + + [POS_DIV_POS_LE_INIT] Theorem + + ⊢ ∀x y. 0 ≤ x ⇒ 0 < y ⇒ x / y ≤ x + + [POS_MOD_POS_IS_POS] Theorem + + ⊢ ∀x y. 0 ≤ x ⇒ 0 < y ⇒ 0 ≤ x % y + + [POS_MOD_POS_LE_INIT] Theorem + + ⊢ ∀x y. 0 ≤ x ⇒ 0 < y ⇒ x % y ≤ x + + [POS_MUL_POS_IS_POS] Theorem + + ⊢ ∀x y. 0 ≤ x ⇒ 0 ≤ y ⇒ 0 ≤ x * y + + [U128_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u128_id, u128_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + u128_to_int x + u128_to_int y ≤ u128_max ⇒ + ∃z. u128_add x y = Return z ∧ + u128_to_int z = u128_to_int x + u128_to_int y + + [U128_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u128_id, u128_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + u128_to_int y ≠ 0 ⇒ + ∃z. u128_div x y = Return z ∧ + u128_to_int z = u128_to_int x / u128_to_int y + + [U128_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u128_id, u128_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + u128_to_int x * u128_to_int y ≤ u128_max ⇒ + ∃z. u128_mul x y = Return z ∧ + u128_to_int z = u128_to_int x * u128_to_int y + + [U128_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u128_id, u128_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + u128_to_int y ≠ 0 ⇒ + ∃z. u128_rem x y = Return z ∧ + u128_to_int z = int_rem (u128_to_int x) (u128_to_int y) + + [U128_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u128_id, u128_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + 0 ≤ u128_to_int x − u128_to_int y ⇒ + ∃z. u128_sub x y = Return z ∧ + u128_to_int z = u128_to_int x − u128_to_int y + + [U16_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u16_id, u16_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u16_to_int x + u16_to_int y ≤ u16_max ⇒ + ∃z. u16_add x y = Return z ∧ + u16_to_int z = u16_to_int x + u16_to_int y + + [U16_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u16_id, u16_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u16_to_int y ≠ 0 ⇒ + ∃z. u16_div x y = Return z ∧ + u16_to_int z = u16_to_int x / u16_to_int y + + [U16_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u16_id, u16_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u16_to_int x * u16_to_int y ≤ u16_max ⇒ + ∃z. u16_mul x y = Return z ∧ + u16_to_int z = u16_to_int x * u16_to_int y + + [U16_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u16_id, u16_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u16_to_int y ≠ 0 ⇒ + ∃z. u16_rem x y = Return z ∧ + u16_to_int z = int_rem (u16_to_int x) (u16_to_int y) + + [U16_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u16_id, u16_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + 0 ≤ u16_to_int x − u16_to_int y ⇒ + ∃z. u16_sub x y = Return z ∧ + u16_to_int z = u16_to_int x − u16_to_int y + + [U32_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u32_id, u32_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u32_to_int x + u32_to_int y ≤ u32_max ⇒ + ∃z. u32_add x y = Return z ∧ + u32_to_int z = u32_to_int x + u32_to_int y + + [U32_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u32_id, u32_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u32_to_int y ≠ 0 ⇒ + ∃z. u32_div x y = Return z ∧ + u32_to_int z = u32_to_int x / u32_to_int y + + [U32_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u32_id, u32_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u32_to_int x * u32_to_int y ≤ u32_max ⇒ + ∃z. u32_mul x y = Return z ∧ + u32_to_int z = u32_to_int x * u32_to_int y + + [U32_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u32_id, u32_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u32_to_int y ≠ 0 ⇒ + ∃z. u32_rem x y = Return z ∧ + u32_to_int z = int_rem (u32_to_int x) (u32_to_int y) + + [U32_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u32_id, u32_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + 0 ≤ u32_to_int x − u32_to_int y ⇒ + ∃z. u32_sub x y = Return z ∧ + u32_to_int z = u32_to_int x − u32_to_int y + + [U64_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u64_id, u64_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u64_to_int x + u64_to_int y ≤ u64_max ⇒ + ∃z. u64_add x y = Return z ∧ + u64_to_int z = u64_to_int x + u64_to_int y + + [U64_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u64_id, u64_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u64_to_int y ≠ 0 ⇒ + ∃z. u64_div x y = Return z ∧ + u64_to_int z = u64_to_int x / u64_to_int y + + [U64_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u64_id, u64_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u64_to_int x * u64_to_int y ≤ u64_max ⇒ + ∃z. u64_mul x y = Return z ∧ + u64_to_int z = u64_to_int x * u64_to_int y + + [U64_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u64_id, u64_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u64_to_int y ≠ 0 ⇒ + ∃z. u64_rem x y = Return z ∧ + u64_to_int z = int_rem (u64_to_int x) (u64_to_int y) + + [U64_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u64_id, u64_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + 0 ≤ u64_to_int x − u64_to_int y ⇒ + ∃z. u64_sub x y = Return z ∧ + u64_to_int z = u64_to_int x − u64_to_int y + + [U8_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u8_id, u8_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u8_to_int x + u8_to_int y ≤ u8_max ⇒ + ∃z. u8_add x y = Return z ∧ + u8_to_int z = u8_to_int x + u8_to_int y + + [U8_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u8_id, u8_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u8_to_int y ≠ 0 ⇒ + ∃z. u8_div x y = Return z ∧ + u8_to_int z = u8_to_int x / u8_to_int y + + [U8_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u8_id, u8_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u8_to_int x * u8_to_int y ≤ u8_max ⇒ + ∃z. u8_mul x y = Return z ∧ + u8_to_int z = u8_to_int x * u8_to_int y + + [U8_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u8_id, u8_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + u8_to_int y ≠ 0 ⇒ + ∃z. u8_rem x y = Return z ∧ + u8_to_int z = int_rem (u8_to_int x) (u8_to_int y) + + [U8_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_u8_id, u8_to_int_bounds, usize_bounds] + [] + ⊢ ∀x y. + 0 ≤ u8_to_int x − u8_to_int y ⇒ + ∃z. u8_sub x y = Return z ∧ + u8_to_int z = u8_to_int x − u8_to_int y + + [USIZE_ADD_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_usize_id, usize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + usize_to_int x + usize_to_int y ≤ u16_max ∨ + usize_to_int x + usize_to_int y ≤ usize_max ⇒ + ∃z. usize_add x y = Return z ∧ + usize_to_int z = usize_to_int x + usize_to_int y + + [USIZE_DIV_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_usize_id, usize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + usize_to_int y ≠ 0 ⇒ + ∃z. usize_div x y = Return z ∧ + usize_to_int z = usize_to_int x / usize_to_int y + + [USIZE_MUL_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_usize_id, usize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + usize_to_int x * usize_to_int y ≤ u16_max ∨ + usize_to_int x * usize_to_int y ≤ usize_max ⇒ + ∃z. usize_mul x y = Return z ∧ + usize_to_int z = usize_to_int x * usize_to_int y + + [USIZE_REM_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_usize_id, usize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + usize_to_int y ≠ 0 ⇒ + ∃z. usize_rem x y = Return z ∧ + usize_to_int z = int_rem (usize_to_int x) (usize_to_int y) + + [USIZE_SUB_EQ] Theorem + + [oracles: DISK_THM] + [axioms: isize_bounds, int_to_usize_id, usize_to_int_bounds, + usize_bounds] [] + ⊢ ∀x y. + 0 ≤ usize_to_int x − usize_to_int y ⇒ + ∃z. usize_sub x y = Return z ∧ + usize_to_int z = usize_to_int x − usize_to_int y + + [datatype_error] Theorem + + ⊢ DATATYPE (error Failure) + + [datatype_result] Theorem + + ⊢ DATATYPE (result Return Fail Loop) + + [error2num_11] Theorem + + ⊢ ∀a a'. error2num a = error2num a' ⇔ a = a' + + [error2num_ONTO] Theorem + + ⊢ ∀r. r < 1 ⇔ ∃a. r = error2num a + + [error2num_num2error] Theorem + + ⊢ ∀r. r < 1 ⇔ error2num (num2error r) = r + + [error2num_thm] Theorem + + ⊢ error2num Failure = 0 + + [error_Axiom] Theorem + + ⊢ ∀x0. ∃f. f Failure = x0 + + [error_EQ_error] Theorem + + ⊢ ∀a a'. a = a' ⇔ error2num a = error2num a' + + [error_case_cong] Theorem + + ⊢ ∀M M' v0. + M = M' ∧ (M' = Failure ⇒ v0 = v0') ⇒ + (case M of Failure => v0) = case M' of Failure => v0' + + [error_case_def] Theorem + + ⊢ ∀v0. (case Failure of Failure => v0) = v0 + + [error_case_eq] Theorem + + ⊢ (case x of Failure => v0) = v ⇔ x = Failure ∧ v0 = v + + [error_induction] Theorem + + ⊢ ∀P. P Failure ⇒ ∀a. P a + + [error_nchotomy] Theorem + + ⊢ ∀a. a = Failure + + [num2error_11] Theorem + + ⊢ ∀r r'. r < 1 ⇒ r' < 1 ⇒ (num2error r = num2error r' ⇔ r = r') + + [num2error_ONTO] Theorem + + ⊢ ∀a. ∃r. a = num2error r ∧ r < 1 + + [num2error_error2num] Theorem + + ⊢ ∀a. num2error (error2num a) = a + + [num2error_thm] Theorem + + ⊢ num2error 0 = Failure + + [result_11] Theorem + + ⊢ (∀a a'. Return a = Return a' ⇔ a = a') ∧ + ∀a a'. Fail a = Fail a' ⇔ a = a' + + [result_Axiom] Theorem + + ⊢ ∀f0 f1 f2. ∃fn. + (∀a. fn (Return a) = f0 a) ∧ (∀a. fn (Fail a) = f1 a) ∧ + fn Loop = f2 + + [result_case_cong] Theorem + + ⊢ ∀M M' f f1 v. + M = M' ∧ (∀a. M' = Return a ⇒ f a = f' a) ∧ + (∀a. M' = Fail a ⇒ f1 a = f1' a) ∧ (M' = Loop ⇒ v = v') ⇒ + result_CASE M f f1 v = result_CASE M' f' f1' v' + + [result_case_eq] Theorem + + ⊢ result_CASE x f f1 v = v' ⇔ + (∃a. x = Return a ∧ f a = v') ∨ (∃e. x = Fail e ∧ f1 e = v') ∨ + x = Loop ∧ v = v' + + [result_distinct] Theorem + + ⊢ (∀a' a. Return a ≠ Fail a') ∧ (∀a. Return a ≠ Loop) ∧ + ∀a. Fail a ≠ Loop + + [result_induction] Theorem + + ⊢ ∀P. (∀a. P (Return a)) ∧ (∀e. P (Fail e)) ∧ P Loop ⇒ ∀r. P r + + [result_nchotomy] Theorem + + ⊢ ∀rr. (∃a. rr = Return a) ∨ (∃e. rr = Fail e) ∨ rr = Loop + + +*) +end diff --git a/backends/hol4/Test.sml b/backends/hol4/Test.sml deleted file mode 100644 index 61d0706d..00000000 --- a/backends/hol4/Test.sml +++ /dev/null @@ -1,1749 +0,0 @@ -open HolKernel boolLib bossLib Parse - -val primitives_theory_name = "Primitives" -val _ = new_theory primitives_theory_name - -(* SML declarations *) -(* for example: *) -(*val th = save_thm("SKOLEM_AGAIN",SKOLEM_THM) *) - -local open boolTheory integerTheory wordsTheory stringTheory in end - -Datatype: - error = Failure -End - -Datatype: - result = Return 'a | Fail error | Loop -End - -Type M = ``: 'a result`` - -(* TODO: rename *) -val st_ex_bind_def = Define ` - (st_ex_bind : 'a M -> ('a -> 'b M) -> 'b M) x f = - case x of - Return y => f y - | Fail e => Fail e - | Loop => Loop`; - -val bind_name = fst (dest_const “st_ex_bind”) - -val st_ex_return_def = Define ` - (st_ex_return : 'a -> 'a M) x = - Return x`; - -Overload monad_bind[local] = ``st_ex_bind`` -Overload monad_unitbind[local] = ``\x y. st_ex_bind x (\z. y)`` -Overload monad_ignore_bind[local] = ``\x y. st_ex_bind x (\z. y)`` -(*Overload ex_bind[local] = ``st_ex_bind`` *) -(* Overload ex_return[local] = ``st_ex_return`` *) -(*Overload failwith = ``raise_Fail``*) - -(* Temporarily allow the monadic syntax *) -val _ = monadsyntax.temp_add_monadsyntax (); - -val test1_def = Define ` - test1 (x : bool) = Return x` - -val is_true_def = Define ‘ - is_true (x : bool) = if x then Return () else Fail Failure’ - -val test1_def = Define ‘ - test1 (x : bool) = Return x’ - -val test_monad_def = Define ` - test_monad v = - do - x <- Return v; - Return x - od`; - - -val test_monad2_def = Define ` - test_monad2 = - do - x <- Return T; - Return x - od`; - -val test_monad3_def = Define ` - test_monad3 x = - do - is_true x; - Return x - od`; - -(** - * Arithmetic - *) - -open intLib - -val test_int1 = Define ‘int1 = 32’ -val test_int2 = Define ‘int2 = -32’ - -Theorem INT_THM1: - !(x y : int). x > 0 ==> y > 0 ==> x + y > 0 -Proof - ARITH_TAC -QED - -Theorem INT_THM2: - !(x : int). T -Proof - rw[] -QED - -val _ = prefer_int () - -val x = “-36217863217862718” - -(* Deactivate notations for int *) -val _ = deprecate_int () -open arithmeticTheory - - -val m = Hol_pp.print_apropos -val f = Hol_pp.print_find - -(* Display types on/off: M-h C-t *) -(* Move back: M-h b *) - -val _ = numLib.deprecate_num () -val _ = numLib.prefer_num () - -Theorem NAT_THM1: - !(n : num). n < n + 1 -Proof - Induct_on ‘n’ >> DECIDE_TAC -QED - -Theorem NAT_THM2: - !(n : num). n < n + (1 : num) -Proof - gen_tac >> - Induct_on ‘n’ >- ( - PURE_REWRITE_TAC [ADD, NUMERAL_DEF, BIT1, ALT_ZERO] >> - PURE_REWRITE_TAC [prim_recTheory.LESS_0_0]) >> - PURE_REWRITE_TAC [ADD] >> - irule prim_recTheory.LESS_MONO >> - asm_rewrite_tac [] -QED - - -val x = “1278361286371286:num” - - -(********************** PRIMITIVES *) -val _ = prefer_int () - -val _ = new_type ("u32", 0) -val _ = new_type ("i32", 0) - -(*val u32_min_def = Define ‘u32_min = (0:int)’*) -val u32_max_def = Define ‘u32_max = (4294967295:int)’ - -(* TODO: change that *) -val usize_max_def = Define ‘usize_max = (4294967295:int)’ - -val i32_min_def = Define ‘i32_min = (-2147483648:int)’ -val i32_max_def = Define ‘i32_max = (2147483647:int)’ - -val _ = new_constant ("u32_to_int", “:u32 -> int”) -val _ = new_constant ("i32_to_int", “:i32 -> int”) - -val _ = new_constant ("int_to_u32", “:int -> u32”) -val _ = new_constant ("int_to_i32", “:int -> i32”) - - -(* TODO: change to "...of..." *) -val u32_to_int_bounds = - new_axiom ( - "u32_to_int_bounds", - “!n. 0 <= u32_to_int n /\ u32_to_int n <= u32_max”) - -val i32_to_int_bounds = - new_axiom ( - "i32_to_int_bounds", - “!n. i32_min <= i32_to_int n /\ i32_to_int n <= i32_max”) - -val int_to_u32_id = new_axiom ("int_to_u32_id", - “!n. 0 <= n /\ n <= u32_max ==> u32_to_int (int_to_u32 n) = n”) - -val int_to_i32_id = - new_axiom ( - "int_to_i32_id", - “!n. i32_min <= n /\ n <= i32_max ==> - i32_to_int (int_to_i32 n) = n”) - -val mk_u32_def = Define - ‘mk_u32 n = - if 0 <= n /\ n <= u32_max then Return (int_to_u32 n) - else Fail Failure’ - -val u32_add_def = Define ‘u32_add x y = mk_u32 ((u32_to_int x) + (u32_to_int y))’ - -Theorem MK_U32_SUCCESS: - !n. 0 <= n /\ n <= u32_max ==> - mk_u32 n = Return (int_to_u32 n) -Proof - rw[mk_u32_def] -QED - -Theorem U32_ADD_EQ: - !x y. - u32_to_int x + u32_to_int y <= u32_max ==> - ?z. u32_add x y = Return z /\ u32_to_int z = u32_to_int x + u32_to_int y -Proof - rpt gen_tac >> - rpt DISCH_TAC >> - exists_tac “int_to_u32 (u32_to_int x + u32_to_int y)” >> - imp_res_tac MK_U32_SUCCESS >> - (* There is probably a better way of doing this *) - sg ‘0 <= u32_to_int x’ >- (rw[u32_to_int_bounds]) >> - sg ‘0 <= u32_to_int y’ >- (rw[u32_to_int_bounds]) >> - fs [u32_add_def] >> - irule int_to_u32_id >> - fs[] -QED - -val u32_sub_def = Define ‘u32_sub x y = mk_u32 ((u32_to_int x) - (u32_to_int y))’ - -Theorem U32_SUB_EQ: - !x y. - 0 <= u32_to_int x - u32_to_int y ==> - ?z. u32_sub x y = Return z /\ u32_to_int z = u32_to_int x - u32_to_int y -Proof - rpt gen_tac >> - rpt DISCH_TAC >> - exists_tac “int_to_u32 (u32_to_int x - u32_to_int y)” >> - imp_res_tac MK_U32_SUCCESS >> - (* There is probably a better way of doing this *) - sg ‘u32_to_int x − u32_to_int y ≤ u32_max’ >-( - sg ‘u32_to_int x <= u32_max’ >- (rw[u32_to_int_bounds]) >> - sg ‘0 <= u32_to_int y’ >- (rw[u32_to_int_bounds]) >> - COOPER_TAC - ) >> - fs [u32_sub_def] >> - irule int_to_u32_id >> - fs[] -QED - -val mk_i32_def = Define - ‘mk_i32 n = - if i32_min <= n /\ n <= i32_max then Return (int_to_i32 n) - else Fail Failure’ - -val i32_add_def = Define ‘i32_add x y = mk_i32 ((i32_to_int x) + (i32_to_int y))’ - -Theorem MK_I32_SUCCESS: - !n. i32_min <= n /\ n <= i32_max ==> - mk_i32 n = Return (int_to_i32 n) -Proof - rw[mk_i32_def] -QED - -Theorem I32_ADD_EQ: - !x y. - i32_min <= i32_to_int x + i32_to_int y ==> - i32_to_int x + i32_to_int y <= i32_max ==> - ?z. i32_add x y = Return z /\ i32_to_int z = i32_to_int x + i32_to_int y -Proof - rpt gen_tac >> - rpt DISCH_TAC >> - exists_tac “int_to_i32 (i32_to_int x + i32_to_int y)” >> - imp_res_tac MK_I32_SUCCESS >> - fs [i32_min_def, i32_add_def] >> - irule int_to_i32_id >> - fs[i32_min_def] -QED - -open listTheory - -val _ = new_type ("vec", 1) -val _ = new_constant ("vec_to_list", “:'a vec -> 'a list”) - -val VEC_TO_LIST_NUM_BOUNDS = - new_axiom ( - "VEC_TO_LIST_BOUNDS", - “!v. let l = LENGTH (vec_to_list v) in - (0:num) <= l /\ l <= (4294967295:num)”) - -Theorem VEC_TO_LIST_INT_BOUNDS: - !v. let l = int_of_num (LENGTH (vec_to_list v)) in - 0 <= l /\ l <= u32_max -Proof - gen_tac >> - rw [u32_max_def] >> - assume_tac VEC_TO_LIST_NUM_BOUNDS >> - fs[] -QED - -val VEC_LEN_DEF = Define ‘vec_len v = int_to_u32 (int_of_num (LENGTH (vec_to_list v)))’ - -(* -(* Useless *) -Theorem VEC_LEN_BOUNDS: - !v. u32_min <= u32_to_int (vec_len v) /\ u32_to_int (vec_len v) <= u32_max -Proof - gen_tac >> - qspec_then ‘v’ assume_tac VEC_TO_LIST_INT_BOUNDS >> - fs[VEC_LEN_DEF] >> - IMP_RES_TAC int_to_u32_id >> - fs[] -QED -*) - -(* The type parameters are ordered in alphabetical order *) -Datatype: - test = Variant1 'b | Variant2 'a -End - -Datatype: - test2 = Variant1_1 'T2 | Variant2_1 'T1 -End - -Datatype: - test2 = Variant1_2 'T1 | Variant2_2 'T2 -End - -(* -“Variant1_1 3” -“Variant1_2 3” - -type_of “CONS 3” -*) - -(* TODO: argument order, we must also omit arguments in new type *) -Datatype: - list_t = - ListCons 't list_t - | ListNil -End - -val list_nth_mut_loop_loop_fwd_def = Define ‘ - list_nth_mut_loop_loop_fwd (ls : 't list_t) (i : u32) : 't result = - case ls of - | ListCons x tl => - if u32_to_int i = (0:int) - then Return x - else - do - i0 <- u32_sub i (int_to_u32 1); - list_nth_mut_loop_loop_fwd tl i0 - od - | ListNil => - Fail Failure -’ - -(* -CoInductive coind: - !x y. coind x /\ coind y ==> coind (x + y) -End -*) - -(* -(* This generates inconsistent theorems *) -CoInductive loop: - !x. loop x = if x then loop x else 0 -End - -CoInductive loop: - !(x : int). loop x = if x > 0 then loop (x - 1) else 0 -End -*) - -(* This terminates *) -val list_nth_mut_loop_loop_fwd_def = Define ‘ - list_nth_mut_loop_loop_fwd (ls : 't list_t) (i : u32) : 't result = - case ls of - | ListCons x tl => - if u32_to_int i = (0:int) - then Return x - else - do - i0 <- u32_sub i (int_to_u32 1); - list_nth_mut_loop_loop_fwd tl i0 - od - | ListNil => - Fail Failure -’ - -(* This is sort of a coinductive definition. - - This can be justified: - - we first define a version [nth_fuel] which uses fuel (and is thus terminating) - - we define the predicate P: - P ls i n = case nth_fuel n ls i of Return _ => T | _ => F - - we then use [LEAST] (least upper bound for natural numbers) to define nth as: - “nth ls i = if (?n. P n) then nth_fuel (LEAST (P ls i)) ls i else Fail Loop ” - - we finally prove that nth satisfies the proper equation. - - We would need the following intermediate lemma: - !n. - n < LEAST (P ls i) ==> nth_fuel n ls i = Fail _ /\ - n >= LEAST (P ls i) ==> nth_fuel n ls i = nth_fuel (LEAST P ls i) ls i - - *) -val _ = new_constant ("nth", “:'t list_t -> u32 -> 't result”) -val nth_def = new_axiom ("nth_def", “ - nth (ls : 't list_t) (i : u32) : 't result = - case ls of - | ListCons x tl => - if u32_to_int i = (0:int) - then Return x - else - do - i0 <- u32_sub i (int_to_u32 1); - nth tl i0 - od - | ListNil => - Fail Failure - ”) - - -(*** Examples of proofs on [nth] *) -val list_t_v_def = Define ‘ - list_t_v ListNil = [] /\ - list_t_v (ListCons x tl) = x :: list_t_v tl -’ - -(* TODO: move *) -open dep_rewrite -open integerTheory - -(* Ignore a theorem. - - To be used in conjunction with {!pop_assum} for instance. - *) -fun IGNORE_TAC (_ : thm) : tactic = ALL_TAC - - -Theorem INT_OF_NUM_INJ: - !n m. &n = &m ==> n = m -Proof - rpt strip_tac >> - fs [Num] -QED - -Theorem NUM_SUB_EQ: - !(x y z : int). x = y - z ==> 0 <= x ==> 0 <= z ==> Num y = Num z + Num x -Proof - rpt strip_tac >> - sg ‘0 <= y’ >- COOPER_TAC >> - rfs [] >> - (* Convert to integers *) - irule INT_OF_NUM_INJ >> - imp_res_tac (GSYM INT_OF_NUM) >> - (* Associativity of & *) - PURE_REWRITE_TAC [GSYM INT_ADD] >> - fs [] -QED - -Theorem NUM_SUB_1_EQ: - !(x y : int). x = y - 1 ==> 0 <= x ==> Num y = SUC (Num x) -Proof - rpt strip_tac >> - (* Get rid of the SUC *) - sg ‘SUC (Num x) = 1 + Num x’ >-(rw [ADD]) >> rw [] >> - (* Massage a bit the goal *) - qsuff_tac ‘Num y = Num (y − 1) + Num 1’ >- COOPER_TAC >> - (* Apply the general theorem *) - irule NUM_SUB_EQ >> - COOPER_TAC -QED - -(* TODO: remove *) -Theorem NUM_SUB_1_EQ1: - !i. 0 <= i - 1 ==> Num i = SUC (Num (i-1)) -Proof - rpt strip_tac >> - (* 0 <= i *) - sg ‘0 <= i’ >- COOPER_TAC >> - (* Get rid of the SUC *) - sg ‘SUC (Num (i - 1)) = 1 + Num (i - 1)’ >-(rw [ADD]) >> - rw [] >> - (* Convert to integers*) - irule INT_OF_NUM_INJ >> - imp_res_tac (GSYM INT_OF_NUM) >> - (* Associativity of & *) - PURE_REWRITE_TAC [GSYM INT_ADD] >> - fs [] -QED - -(* TODO: - - list all the integer variables, and insert bounds in the assumptions - - replace u32_min by 0? - - i - 1 - - auto lookup of spec lemmas -*) - -(* Add a list of theorems in the assumptions - TODO: move *) -fun ASSUME_TACL (thms : thm list) : tactic = - let - (* TODO: use MAP_EVERY *) - fun t thms = - case thms of - [] => ALL_TAC - | thm :: thms => ASSUME_TAC thm >> t thms - in - t thms - end - -(* The map from integer type to bounds lemmas *) -val integer_bounds_lemmas = - Redblackmap.fromList String.compare - [ - ("u32", u32_to_int_bounds), - ("i32", i32_to_int_bounds) - ] - -(* The map from integer type to conversion lemmas *) -val integer_conversion_lemmas = - Redblackmap.fromList String.compare - [ - ("u32", int_to_u32_id), - ("i32", int_to_i32_id) - ] - -val integer_conversion_lemmas_list = - map snd (Redblackmap.listItems integer_conversion_lemmas) - -(* Not sure how term nets work, nor how we are supposed to convert Term.term - to mlibTerm.term. - - TODO: it seems we need to explore the term and convert everything to strings. - *) -fun term_to_mlib_term (t : term) : mlibTerm.term = - mlibTerm.string_to_term (term_to_string t) - -(* -(* The lhs of the conclusion of the integer conversion lemmas - we use this for - pattern matching *) -val integer_conversion_lhs_concls = - let - val thms = map snd (Redblackmap.listItems integer_conversion_lemmas); - val concls = map (lhs o concl o UNDISCH_ALL o SPEC_ALL) thms; - in concls end -*) - -(* -val integer_conversion_concls_net = - let - val maplets = map (fn x => fst (dest_eq x) |-> ()) integer_conversion_concls; - - val maplets = map (fn x => fst (mlibTerm.dest_eq x) |-> ()) integer_conversion_concls; - val maplets = map (fn x => fst (mlibThm.dest_unit_eq x) |-> ()) integer_conversion_concls; - val parameters = { fifo=false }; - in mlibTermnet.from_maplets parameters maplets end - -mlibTerm.string_to_term (term_to_string “u32_to_int (int_to_u32 n) = n”) -term_to_quote - -SIMP_CONV -mlibThm.dest_thm u32_to_int_bounds -mlibThm.dest_unit u32_to_int_bounds -*) - -(* The integer types *) -val integer_types_names = - Redblackset.fromList String.compare - (map fst (Redblackmap.listItems integer_bounds_lemmas)) - -val all_integer_bounds = [ - u32_max_def, - i32_min_def, - i32_max_def -] - -(* Small utility: compute the set of assumptions in the context. - - We isolate this code in a utility in order to be able to improve it: - for now we simply put all the assumptions in a set, but in the future - we might want to split the assumptions which are conjunctions in order - to be more precise. - *) -fun compute_asms_set ((asms,g) : goal) : term Redblackset.set = - Redblackset.fromList Term.compare asms - -(* See {!assume_bounds_for_all_int_vars}. - - This tactic is in charge of adding assumptions for one variable. - *) - -fun assume_bounds_for_int_var - (asms_set: term Redblackset.set) (var : string) (ty : string) : - tactic = - let - (* Lookup the lemma to apply *) - val lemma = Redblackmap.find (integer_bounds_lemmas, ty); - (* Instantiate the lemma *) - val ty_t = mk_type (ty, []); - val var_t = mk_var (var, ty_t); - val lemma = SPEC var_t lemma; - (* Split the theorem into a list of conjuncts. - - The bounds are typically a conjunction: - {[ - ⊢ 0 ≤ u32_to_int x ∧ u32_to_int x ≤ u32_max: thm - ]} - *) - val lemmas = CONJUNCTS lemma; - (* Filter the conjuncts: some of them might already be in the context, - we don't want to introduce them again, as it would pollute it. - *) - val lemmas = filter (fn lem => not (Redblackset.member (asms_set, concl lem))) lemmas; - in - (* Introduce the assumptions in the context *) - ASSUME_TACL lemmas - end - -(* Destruct if possible a term of the shape: [x y], - where [x] is not a comb. - - Returns [(x, y)] - *) -fun dest_single_comb (t : term) : (term * term) option = - case strip_comb t of - (x, [y]) => SOME (x, y) - | _ => NONE - -(** Destruct if possible a term of the shape: [x (y z)]. - Returns [(x, y, z)] - *) -fun dest_single_comb_twice (t : term) : (term * term * term) option = - case dest_single_comb t of - NONE => NONE - | SOME (x, y) => - case dest_single_comb y of - NONE => NONE - | SOME (y, z) => SOME (x, y, z) - -(* A utility map to lookup integer conversion lemmas *) -val integer_conversion_pat_map = - let - val thms = map snd (Redblackmap.listItems integer_conversion_lemmas); - val tl = map (lhs o concl o UNDISCH_ALL o SPEC_ALL) thms; - val tl = map (valOf o dest_single_comb_twice) tl; - val tl = map (fn (x, y, _) => (x, y)) tl; - val m = Redblackmap.fromList Term.compare tl - in m end - -(* Introduce bound assumptions for all the machine integers in the context. - - Exemple: - ======== - If there is “x : u32” in the input set, then we introduce: - {[ - 0 <= u32_to_int x - u32_to_int x <= u32_max - ]} - *) -fun assume_bounds_for_all_int_vars (asms, g) = - let - (* Compute the set of integer variables in the context *) - val vars = free_varsl (g :: asms); - (* Compute the set of assumptions already present in the context *) - val asms_set = compute_asms_set (asms, g); - (* Filter the variables to keep only the ones with type machine integer, - decompose the types at the same time *) - fun decompose_var (v : term) : (string * string) = - let - val (v, ty) = dest_var v; - val {Args=args, Thy=thy, Tyop=ty} = dest_thy_type ty; - val _ = assert null args; - val _ = assert (fn thy => thy = primitives_theory_name) thy; - val _ = assert (fn ty => Redblackset.member (integer_types_names, ty)) ty; - in (v, ty) end; - val vars = mapfilter decompose_var vars; - (* Add assumptions for one variable *) - fun add_var_asm (v, ty) : tactic = - assume_bounds_for_int_var asms_set v ty; - (* Add assumptions for all the variables *) - (* TODO: use MAP_EVERY *) - fun add_vars_asm vl : tactic = - case vl of - [] => ALL_TAC - | v :: vl => - add_var_asm v >> add_vars_asm vl; - in - add_vars_asm vars (asms, g) - end - -(* -dest_thy_type “:u32” -val massage : tactic = assume_bounds_for_all_int_vars -val vl = vars -val (v::vl) = vl -*) - -(* -val (asms, g) = top_goal () -fun bounds_for_ints_in_list (vars : (string * hol_type) list) : tactic = - foldl - FAIL_TAC "" -val var = "x" -val ty = "u32" - -val asms_set = Redblackset.fromList Term.compare asms; - -val x = “1: int” -val ty = "u32" - -val thm = lemma -*) - -(* Given a theorem of the shape: - {[ - A0, ..., An ⊢ B0 ==> ... ==> Bm ==> concl - ]} - - Rewrite it so that it has the shape: - {[ - ⊢ (A0 /\ ... /\ An /\ B0 /\ ... /\ Bm) ==> concl - ]} - *) -fun thm_to_conj_implies (thm : thm) : thm = - let - (* Discharge all the assumptions *) - val thm = DISCH_ALL thm; - (* Rewrite the implications as one conjunction *) - val thm = PURE_REWRITE_RULE [GSYM satTheory.AND_IMP] thm; - in thm end - - -(* Like THEN1 and >-, but doesn't fail if the first subgoal is not completely - solved. - - TODO: how to get the notation right? - *) -fun op PARTIAL_THEN1 (tac1: tactic) (tac2: tactic) : tactic = tac1 THEN_LT (NTH_GOAL tac2 1) - -(* If the current goal is [asms ⊢ g], and given a lemma of the form - [⊢ H ==> C], do the following: - - introduce [asms ⊢ H] as a subgoal and apply the given tactic on it - - also calls the theorem tactic with the theorem [asms ⊢ C] - - If the lemma is not an implication, we directly call the theorem tactic. - *) -fun intro_premise_then (premise_tac: tactic) (then_tac: thm_tactic) (thm : thm) : tactic = - let - val c = concl thm; - (* First case: there is a premise to prove *) - fun prove_premise_then (h : term) = - PARTIAL_THEN1 (SUBGOAL_THEN h (fn h_thm => then_tac (MP thm h_thm))) premise_tac; - (* Second case: no premise to prove *) - val no_prove_premise_then = then_tac thm; - in - if is_imp c then prove_premise_then (fst (dest_imp c)) else no_prove_premise_then - end - -(* Same as {!intro_premise_then} but fails if the premise_tac fails to prove the premise *) -fun prove_premise_then (premise_tac: tactic) (then_tac: thm_tactic) (thm : thm) : tactic = - intro_premise_then - (premise_tac >> FAIL_TAC "prove_premise_then: could not prove premise") - then_tac thm - -(* -val thm = th -*) - -(* Call a function on all the subterms of a term *) -fun dep_apply_in_subterms - (f : string Redblackset.set -> term -> unit) - (bound_vars : string Redblackset.set) - (t : term) : unit = - let - val dep = dep_apply_in_subterms f; - val _ = f bound_vars t; - in - case dest_term t of - VAR (name, ty) => () - | CONST {Name=name, Thy=thy, Ty=ty} => () - | COMB (app, arg) => - let - val _ = dep bound_vars app; - val _ = dep bound_vars arg; - in () end - | LAMB (bvar, body) => - let - val (varname, ty) = dest_var bvar; - val bound_vars = Redblackset.add (bound_vars, varname); - val _ = dep bound_vars body; - in () end - end - -(* Return the set of free variables appearing in the residues of a term substitution *) -fun free_vars_in_subst_residue (s: (term, term) Term.subst) : string Redblackset.set = - let - val free_vars = free_varsl (map (fn {redex=_, residue=x} => x) s); - val free_vars = map (fst o dest_var) free_vars; - val free_vars = Redblackset.fromList String.compare free_vars; - in free_vars end - -(* Attempt to instantiate a rewrite theorem. - - Remark: this theorem should be of the form: - H ⊢ x = y - - (without quantified variables). - - **REMARK**: the function raises a HOL_ERR exception if it fails. - - [forbid_vars]: forbid substituting with those vars (typically because - we are maching in a subterm under lambdas, and some of those variables - are bounds in the outer lambdas). -*) -fun inst_match_concl (forbid_vars : string Redblackset.set) (th : thm) (t : term) : thm = - let - (* Retrieve the lhs of the conclusion of the theorem *) - val l = lhs (concl th); - (* Match this lhs with the term *) - val (var_s, ty_s) = match_term l t; - (* Check that we are allowed to perform the substitution *) - val free_vars = free_vars_in_subst_residue var_s; - val _ = assert Redblackset.isEmpty (Redblackset.intersection (free_vars, forbid_vars)); - in - (* Perform the substitution *) - INST var_s (INST_TYPE ty_s th) - end - -(* -val forbid_vars = Redblackset.empty String.compare -val t = “u32_to_int (int_to_u32 x)” -val t = “u32_to_int (int_to_u32 3)” -val th = (UNDISCH_ALL o SPEC_ALL) int_to_u32_id -*) - -(* Attempt to instantiate a theorem by matching its first premise. - - Note that we make the hypothesis tha all the free variables which need - to be instantiated appear in the first premise, of course (the caller should - enforce this). - - Remark: this theorem should be of the form: - ⊢ H0 ==> ... ==> Hn ==> H - - (without quantified variables). - - **REMARK**: the function raises a HOL_ERR exception if it fails. - - [forbid_vars]: see [inst_match_concl] -*) -fun inst_match_first_premise - (forbid_vars : string Redblackset.set) (th : thm) (t : term) : thm = - let - (* Retrieve the first premise *) - val l = (fst o dest_imp o concl) th; - (* Match this with the term *) - val (var_s, ty_s) = match_term l t; - (* Check that we are allowed to perform the substitution *) - val free_vars = free_vars_in_subst_residue var_s; - val _ = assert Redblackset.isEmpty (Redblackset.intersection (free_vars, forbid_vars)); - in - (* Perform the substitution *) - INST var_s (INST_TYPE ty_s th) - end - -(* -val forbid_vars = Redblackset.empty String.compare -val t = “u32_to_int z = u32_to_int i − 1” -val th = SPEC_ALL NUM_SUB_1_EQ -*) - -(* Call a matching function on all the subterms in the provided list of term. - This is a generic function. - - [try_match] should return an instantiated theorem, as well as a term which - identifies this theorem (the lhs of the equality, if this is a rewriting - theorem for instance - we use this to check for collisions, and discard - redundant instantiations). - *) -fun inst_match_in_terms - (try_match: string Redblackset.set -> term -> term * thm) - (tl : term list) : thm list = - let - (* We use a map when storing the theorems, to avoid storing the same theorem twice *) - val inst_thms: (term, thm) Redblackmap.dict ref = ref (Redblackmap.mkDict Term.compare); - fun try_instantiate bvars t = - let - val (inst_th_tm, inst_th) = try_match bvars t; - in - inst_thms := Redblackmap.insert (!inst_thms, inst_th_tm, inst_th) - end - handle HOL_ERR _ => (); - (* Explore the term *) - val _ = app (dep_apply_in_subterms try_instantiate (Redblackset.empty String.compare)) tl; - in - map snd (Redblackmap.listItems (!inst_thms)) - end - -(* Given a rewriting theorem [th] which has premises, return all the - instantiations of this theorem which make its conclusion match subterms - in the provided list of term. - *) -fun inst_match_concl_in_terms (th : thm) (tl : term list) : thm list = - let - val th = (UNDISCH_ALL o SPEC_ALL) th; - fun try_match bvars t = - let - val inst_th = inst_match_concl bvars th t; - in - (lhs (concl inst_th), inst_th) - end; - in - inst_match_in_terms try_match tl - end - -(* -val t = “!x. u32_to_int (int_to_u32 x) = u32_to_int (int_to_u32 y)” -val th = int_to_u32_id - -val thms = inst_match_concl_in_terms int_to_u32_id [t] -*) - - -(* Given a theorem [th] which has premises, return all the - instantiations of this theorem which make its first premise match subterms - in the provided list of term. - *) -fun inst_match_first_premise_in_terms (th : thm) (tl : term list) : thm list = - let - val th = SPEC_ALL th; - fun try_match bvars t = - let - val inst_th = inst_match_first_premise bvars th t; - in - ((fst o dest_imp o concl) inst_th, inst_th) - end; - in - inst_match_in_terms try_match tl - end - -(* -val t = “x = y - 1 ==> T” -val th = SPEC_ALL NUM_SUB_1_EQ - -val thms = inst_match_first_premise_in_terms th [t] -*) - -(* Attempt to apply dependent rewrites with a theorem by matching its - conclusion with subterms of the goal. - *) -fun apply_dep_rewrites_match_concl_tac - (prove_premise : tactic) (then_tac : thm_tactic) (th : thm) : tactic = - fn (asms, g) => - let - (* Discharge the assumptions so that the goal is one single term *) - val thms = inst_match_concl_in_terms th (g :: asms); - val thms = map thm_to_conj_implies thms; - in - (* Apply each theorem *) - MAP_EVERY (prove_premise_then prove_premise then_tac) thms (asms, g) - end - -(* -val (asms, g) = ([ - “u32_to_int z = u32_to_int i − u32_to_int (int_to_u32 1)”, - “u32_to_int (int_to_u32 2) = 2” -], “T”) - -apply_dep_rewrites_match_concl_tac - (FULL_SIMP_TAC simpLib.empty_ss all_integer_bounds >> COOPER_TAC) - (fn th => FULL_SIMP_TAC simpLib.empty_ss [th]) - int_to_u32_id -*) - -(* Attempt to apply dependent rewrites with a theorem by matching its - first premise with subterms of the goal. - *) -fun apply_dep_rewrites_match_first_premise_tac - (prove_premise : tactic) (then_tac : thm_tactic) (th : thm) : tactic = - fn (asms, g) => - let - (* Discharge the assumptions so that the goal is one single term *) - val thms = inst_match_first_premise_in_terms th (g :: asms); - val thms = map thm_to_conj_implies thms; - fun apply_tac th = - let - val th = thm_to_conj_implies th; - in - prove_premise_then prove_premise then_tac th - end; - in - (* Apply each theorem *) - MAP_EVERY apply_tac thms (asms, g) - end - -(* See {!rewrite_all_int_conversion_ids}. - - Small utility which takes care of one rewriting. - - TODO: we actually don't use it. REMOVE? - *) -fun rewrite_int_conversion_id - (asms_set: term Redblackset.set) (x : term) (ty : string) : - tactic = - let - (* Lookup the theorem *) - val lemma = Redblackmap.find (integer_conversion_lemmas, ty); - (* Instantiate *) - val lemma = SPEC x lemma; - (* Rewrite the lemma. The lemma typically has the shape: - ⊢ u32_min <= x /\ x <= u32_max ==> u32_to_int (int_to_u32 x) = x - - Make sure the lemma has the proper shape, attempt to prove the premise, - then use the conclusion if it succeeds. - *) - val lemma = thm_to_conj_implies lemma; - (* Retrieve the conclusion of the lemma - we do this to check if it is not - already in the assumptions *) - val c = concl (UNDISCH_ALL lemma); - val already_in_asms = Redblackset.member (asms_set, c); - (* Small utility: the tactic to prove the premise *) - val prove_premise = - (* We might need to unfold the bound definitions, in particular if the - term is a constant (e.g., “3:int”) *) - FULL_SIMP_TAC simpLib.empty_ss all_integer_bounds >> - COOPER_TAC; - (* Rewrite with a lemma, then assume it *) - fun rewrite_then_assum (thm : thm) : tactic = - FULL_SIMP_TAC simpLib.empty_ss [thm] >> assume_tac thm; - in - (* If the conclusion is not already in the assumptions, prove it, use - it to rewrite the goal and add it in the assumptions, otherwise do nothing *) - if already_in_asms then ALL_TAC - else prove_premise_then prove_premise rewrite_then_assum lemma - end - -(* Look for conversions from integers to machine integers and back. - {[ - u32_to_int (int_to_u32 x) - ]} - - Attempts to prove and apply equalities of the form: - {[ - u32_to_int (int_to_u32 x) = x - ]} - - **REMARK**: this function can fail, if it doesn't manage to prove the - premises of the theorem to apply. - - TODO: update - *) -val rewrite_with_dep_int_lemmas : tactic = - (* We're not trying to be smart: we just try to rewrite with each theorem at - a time *) - let - val prove_premise = FULL_SIMP_TAC simpLib.empty_ss all_integer_bounds >> COOPER_TAC; - val then_tac1 = (fn th => FULL_SIMP_TAC simpLib.empty_ss [th]); - val rewr_tac1 = apply_dep_rewrites_match_concl_tac prove_premise then_tac1; - val then_tac2 = (fn th => FULL_SIMP_TAC simpLib.empty_ss [th]); - val rewr_tac2 = apply_dep_rewrites_match_first_premise_tac prove_premise then_tac2; - in - MAP_EVERY rewr_tac1 integer_conversion_lemmas_list >> - MAP_EVERY rewr_tac2 [NUM_SUB_1_EQ] - end - -(* -apply_dep_rewrites_match_first_premise_tac prove_premise then_tac NUM_SUB_1_EQ - -sg ‘u32_to_int z = u32_to_int i − 1 /\ 0 ≤ u32_to_int z’ >- prove_premise - -prove_premise_then prove_premise - -val thm = thm_to_conj_implies (SPECL [“u32_to_int z”, “u32_to_int i”] NUM_SUB_1_EQ) - -val h = “u32_to_int z = u32_to_int i − 1 ∧ 0 ≤ u32_to_int z” -*) - -(* Massage a bit the goal, for instance by introducing integer bounds in the - assumptions. -*) -val massage : tactic = - assume_bounds_for_all_int_vars >> - rewrite_with_dep_int_lemmas - -(* Lexicographic order over pairs *) -fun pair_compare (comp1 : 'a * 'a -> order) (comp2 : 'b * 'b -> order) - ((p1, p2) : (('a * 'b) * ('a * 'b))) : order = - let - val (x1, y1) = p1; - val (x2, y2) = p2; - in - case comp1 (x1, x2) of - LESS => LESS - | GREATER => GREATER - | EQUAL => comp2 (y1, y2) - end - -(* A constant name (theory, constant name) *) -type const_name = string * string - -val const_name_compare = pair_compare String.compare String.compare - -(* The registered spec theorems, that {!progress} will automatically apply. - - The keys are the function names (it is a pair, because constant names - are made of the theory name and the name of the constant itself). - - Also note that we can store several specs per definition (in practice, when - looking up specs, we will try them all one by one, in a LIFO order). - - We store theorems where all the premises are in the goal, with implications - (i.e.: [⊢ H0 ==> ... ==> Hn ==> H], not [H0, ..., Hn ⊢ H]). - - We do this because, when doing proofs by induction, {!progress} might have to - handle *unregistered* theorems coming the current goal assumptions and of the shape - (the conclusion of the theorem is an assumption, and we want to ignore this assumption): - {[ - [∀i. u32_to_int i < &LENGTH (list_t_v ls) ⇒ - case nth ls i of - Return x => ... - | ... => ...] - ⊢ ∀i. u32_to_int i < &LENGTH (list_t_v ls) ⇒ - case nth ls i of - Return x => ... - | ... => ... - ]} - *) -val reg_spec_thms: (const_name, thm) Redblackmap.dict ref = - ref (Redblackmap.mkDict const_name_compare) - -(* Retrieve the specified application in a spec theorem. - - A spec theorem for a function [f] typically has the shape: - {[ - !x0 ... xn. - H0 ==> ... Hm ==> - (exists ... - (exists ... . f y0 ... yp = ... /\ ...) \/ - (exists ... . f y0 ... yp = ... /\ ...) \/ - ... - ]} - - Or: - {[ - !x0 ... xn. - H0 ==> ... Hm ==> - case f y0 ... yp of - ... => ... - | ... => ... - ]} - - We return: [f y0 ... yp] -*) -fun get_spec_app (t : term) : term = - let - (* Remove the universally quantified variables, the premises and - the existentially quantified variables *) - val t = (snd o strip_exists o snd o strip_imp o snd o strip_forall) t; - (* Remove the exists, take the first disjunct *) - val t = (hd o strip_disj o snd o strip_exists) t; - (* Split the conjunctions and take the first conjunct *) - val t = (hd o strip_conj) t; - (* Remove the case if there is, otherwise destruct the equality *) - val t = - if TypeBase.is_case t then let val (_, t, _) = TypeBase.dest_case t in t end - else (fst o dest_eq) t; - in t end - -(* Given a function call [f y0 ... yn] return the name of the function *) -fun get_fun_name_from_app (t : term) : const_name = - let - val f = (fst o strip_comb) t; - val {Name=name, Thy=thy, Ty=_} = dest_thy_const f; - val cn = (thy, name); - in cn end - -(* Register a spec theorem in the spec database. - - For the shape of spec theorems, see {!get_spec_thm_app}. - *) -fun register_spec_thm (th: thm) : unit = - let - (* Transform the theroem a bit before storing it *) - val th = SPEC_ALL th; - (* Retrieve the app ([f x0 ... xn]) *) - val f = get_spec_app (concl th); - (* Retrieve the function name *) - val cn = get_fun_name_from_app f; - in - (* Store *) - reg_spec_thms := Redblackmap.insert (!reg_spec_thms, cn, th) - end - -(* TODO: I32_SUB_EQ *) -val _ = app register_spec_thm [U32_ADD_EQ, U32_SUB_EQ, I32_ADD_EQ] - -(* -app register_spec_thm [U32_ADD_EQ, U32_SUB_EQ, I32_ADD_EQ] -Redblackmap.listItems (!reg_spec_thms) -*) - -(* -(* TODO: remove? *) -datatype monadic_app_kind = - Call | Bind | Case -*) - -(* Repeatedly destruct cases and return the last scrutinee we get *) -fun strip_all_cases_get_scrutinee (t : term) : term = - if TypeBase.is_case t - then (strip_all_cases_get_scrutinee o fst o TypeBase.strip_case) t - else t - -(* -TypeBase.dest_case “case ls of [] => T | _ => F” -TypeBase.strip_case “case ls of [] => T | _ => F” -TypeBase.strip_case “case (if b then [] else [0, 1]) of [] => T | _ => F” -TypeBase.strip_case “3” -TypeBase.dest_case “3” - -strip_all_cases_get_scrutinee “case ls of [] => T | _ => F” -strip_all_cases_get_scrutinee “case (if b then [] else [0, 1]) of [] => T | _ => F” -strip_all_cases_get_scrutinee “3” -*) - - -(* Provided the goal contains a call to a monadic function, return this function call. - - The goal should be of the shape: - 1. - {[ - case (* potentially expanded function body *) of - ... => ... - | ... => ... - ]} - - 2. Or: - {[ - exists ... . - ... (* potentially expanded function body *) = Return ... /\ - ... (* Various properties *) - ]} - - 3. Or a disjunction of cases like the one above, below existential binders - (actually: note sure this last case exists in practice): - {[ - exists ... . - (exists ... . (* body *) = Return ... /\ ...) \/ - ... - ]} - - The function body should be of the shape: - {[ - x <- f y0 ... yn; - ... - ]} - - Or (typically if we expanded the monadic binds): - {[ - case f y0 ... yn of - ... - ]} - - Or simply (typically if we reached the end of the function we're analyzing): - {[ - f y0 ... yn - ]} - - For all the above cases we would return [f y0 ... yn]. - *) -fun get_monadic_app_call (t : term) : term = - (* We do something slightly imprecise but hopefully general and robut *) - let - (* Case 3.: strip the existential binders, and take the first disjuntion *) - val t = (hd o strip_disj o snd o strip_exists) t; - (* Case 2.: strip the existential binders, and take the first conjunction *) - val t = (hd o strip_conj o snd o strip_exists) t; - (* If it is an equality, take the lhs *) - val t = if is_eq t then lhs t else t; - (* Expand the binders to transform them to cases *) - val t = - (rhs o concl) (REWRITE_CONV [st_ex_bind_def] t) - handle UNCHANGED => t; - (* Strip all the cases *) - val t = strip_all_cases_get_scrutinee t; - in t end - -(* Use the given theorem to progress by one step (we use this when - analyzing a function body: this goes forward by one call to a monadic function). - - We transform the goal by: - - pushing the theorem premises to a subgoal - - adding the theorem conclusion in the assumptions in another goal, and - getting rid of the monadic call - - Then [then_tac] receives as paramter the monadic call on which we applied - the lemma. This can be useful, for instance, to make a case disjunction. - - This function is the most primitive of the [progress...] functions. - *) -fun pure_progress_with (premise_tac : tactic) - (then_tac : term -> thm_tactic) (th : thm) : tactic = - fn (asms,g) => - let - (* Remove all the universally quantified variables from the theorem *) - val th = SPEC_ALL th; - (* Retrieve the monadic call from the goal *) - val fgoal = get_monadic_app_call g; - (* Retrieve the app call from the theroem *) - val gth = get_spec_app (concl th); - (* Match and instantiate *) - val (var_s, ty_s) = match_term gth fgoal; - (* Instantiate the theorem *) - val th = INST var_s (INST_TYPE ty_s th); - (* Retrieve the premises of the theorem *) - val th = PURE_REWRITE_RULE [GSYM satTheory.AND_IMP] th; - in - (* Apply the theorem *) - intro_premise_then premise_tac (then_tac fgoal) th (asms, g) - end - -(* -val (asms, g) = top_goal () -val t = g - -val th = U32_SUB_EQ - -val premise_tac = massage >> TRY COOPER_TAC -fun then_tac fgoal = - fn thm => ASSUME_TAC thm >> Cases_on ‘^fgoal’ >> - rw [] >> fs [st_ex_bind_def] >> massage >> fs [] - -pure_progress_with premise_tac then_tac th -*) - -fun progress_with (th : thm) : tactic = - let - val premise_tac = massage >> fs [] >> rw [] >> TRY COOPER_TAC; - fun then_tac fgoal thm = - ASSUME_TAC thm >> Cases_on ‘^fgoal’ >> - rw [] >> fs [st_ex_bind_def] >> massage >> fs []; - in - pure_progress_with premise_tac then_tac th - end - -(* -progress_with U32_SUB_EQ -*) - -(* This function lookups the theorem to use to make progress *) -val progress : tactic = - fn (asms, g) => - let - (* Retrieve the monadic call from the goal *) - val fgoal = get_monadic_app_call g; - val fname = get_fun_name_from_app fgoal; - (* Lookup the theorem: first look in the assumptions (we might want to - use the inductive hypothesis for instance) *) - fun asm_to_spec asm = - let - (* Fail if there are no universal quantifiers *) - val _ = - if is_forall asm then asm - else assert is_forall ((snd o strip_imp) asm); - val asm_fname = (get_fun_name_from_app o get_spec_app) asm; - (* Fail if the name is not the one we're looking for *) - val _ = assert (fn n => fname = n) asm_fname; - in - ASSUME asm - end - val asms_thl = mapfilter asm_to_spec asms; - (* Lookup a spec in the database *) - val thl = - case Redblackmap.peek (!reg_spec_thms, fname) of - NONE => asms_thl - | SOME spec => spec :: asms_thl; - val _ = - if null thl then - raise (failwith "progress: could not find a suitable theorem to apply") - else (); - in - (* Attempt to use the theorems one by one *) - MAP_FIRST progress_with thl (asms, g) - end - -(* -val (asms, g) = top_goal () -*) - -(* TODO: no exfalso tactic?? *) -val EX_FALSO : tactic = - SUBGOAL_THEN “F” (fn th => ASSUME_TAC th >> fs[]) - -Theorem nth_lem: - !(ls : 't list_t) (i : u32). - u32_to_int i < int_of_num (LENGTH (list_t_v ls)) ==> - case nth ls i of - | Return x => x = EL (Num (u32_to_int i)) (list_t_v ls) - | Fail _ => F - | Loop => F -Proof - Induct_on ‘ls’ >> rw [list_t_v_def] >~ [‘ListNil’] - >-(massage >> EX_FALSO >> COOPER_TAC) >> - PURE_ONCE_REWRITE_TAC [nth_def] >> rw [] >> - progress >> progress -QED - -(* Example from the hashmap *) -val _ = new_constant ("insert", “: u32 -> 't -> (u32 # 't) list_t -> (u32 # 't) list_t result”) -val insert_def = new_axiom ("insert_def", “ - insert (key : u32) (value : 't) (ls : (u32 # 't) list_t) : (u32 # 't) list_t result = - case ls of - | ListCons (ckey, cvalue) tl => - if ckey = key - then Return (ListCons (ckey, value) tl) - else - do - tl0 <- insert key value tl; - Return (ListCons (ckey, cvalue) tl0) - od - | ListNil => Return (ListCons (key, value) ListNil) - ”) - -(* Property that keys are pairwise distinct *) -val distinct_keys_def = Define ‘ - distinct_keys (ls : (u32 # 't) list) = - !i j. - i < LENGTH ls ==> - j < LENGTH ls ==> - FST (EL i ls) = FST (EL j ls) ==> - i = j -’ - -val lookup_raw_def = Define ‘ - lookup_raw key [] = NONE /\ - lookup_raw key ((k, v) :: ls) = - if k = key then SOME v else lookup_raw key ls -’ - -val lookup_def = Define ‘ - lookup key ls = lookup_raw key (list_t_v ls) -’ - -Theorem insert_lem: - !ls key value. - (* The keys are pairwise distinct *) - distinct_keys (list_t_v ls) ==> - case insert key value ls of - | Return ls1 => - (* We updated the binding *) - lookup key ls1 = SOME value /\ - (* The other bindings are left unchanged *) - (!k. k <> key ==> lookup k ls = lookup k ls1) - | Fail _ => F - | Loop => F -Proof - Induct_on ‘ls’ >> rw [list_t_v_def] >~ [‘ListNil’] >> - PURE_ONCE_REWRITE_TAC [insert_def] >> rw [] - >- (rw [lookup_def, lookup_raw_def, list_t_v_def]) - >- (rw [lookup_def, lookup_raw_def, list_t_v_def]) >> - CASE_TAC >> rw [] - >- (rw [lookup_def, lookup_raw_def, list_t_v_def]) - >- (rw [lookup_def, lookup_raw_def, list_t_v_def]) >> - progress - >- ( - fs [distinct_keys_def] >> - rpt strip_tac >> - first_assum (qspecl_then [‘SUC i’, ‘SUC j’] ASSUME_TAC) >> - fs [] - (* Alternative: *) - (* - PURE_ONCE_REWRITE_TAC [GSYM prim_recTheory.INV_SUC_EQ] >> - first_assum irule >> fs [] - *)) >> - fs [lookup_def, lookup_raw_def, list_t_v_def] -QED - -(*** - * Example of how to get rid of the fuel in practice - *) -val nth_fuel_def = Define ‘ - nth_fuel (n : num) (ls : 't list_t) (i : u32) : 't result = - case n of - | 0 => Loop - | SUC n => - do case ls of - | ListCons x tl => - if u32_to_int i = (0:int) - then Return x - else - do - i0 <- u32_sub i (int_to_u32 1); - nth_fuel n tl i0 - od - | ListNil => - Fail Failure - od - ’ - -val is_loop_def = Define ‘is_loop r = case r of Loop => T | _ => F’ - -val nth_fuel_P_def = Define ‘ - nth_fuel_P ls i n = ~is_loop (nth_fuel n ls i) -’ - -Theorem nth_fuel_mono: - !n m ls i. - n <= m ==> - if is_loop (nth_fuel n ls i) then T - else nth_fuel n ls i = nth_fuel m ls i -Proof - Induct_on ‘n’ >- ( - rpt gen_tac >> - DISCH_TAC >> - PURE_ONCE_REWRITE_TAC [nth_fuel_def] >> - rw[is_loop_def] - ) >> - (* Interesting case *) - rpt gen_tac >> - DISCH_TAC >> - CASE_TAC >> - Cases_on ‘m’ >- ( - (* Contradiction: SUC n < 0 *) - sg ‘SUC n = 0’ >- decide_tac >> - fs [is_loop_def] - ) >> - fs [is_loop_def] >> - pop_assum mp_tac >> - PURE_ONCE_REWRITE_TAC [nth_fuel_def] >> - fs [] >> - DISCH_TAC >> - (* We just have to explore all the paths: we can have dedicated tactics for that - (we need to do case analysis) *) - Cases_on ‘ls’ >> fs [] >> - Cases_on ‘u32_to_int (i :u32) = (0 :int)’ >> fs [] >> - fs [st_ex_bind_def] >> - Cases_on ‘u32_sub (i :u32) (int_to_u32 (1 :int))’ >> fs [] >> - (* Apply the induction hypothesis *) - first_x_assum (qspecl_then [‘n'’, ‘l’, ‘a’] assume_tac) >> - first_x_assum imp_res_tac >> - pop_assum mp_tac >> - CASE_TAC -QED - -Theorem nth_fuel_P_mono: - !n m ls i. - n <= m ==> - nth_fuel_P ls i n ==> - nth_fuel n ls i = nth_fuel m ls i -Proof - rpt gen_tac >> rpt DISCH_TAC >> - fs [nth_fuel_P_def] >> - imp_res_tac nth_fuel_mono >> - pop_assum (qspecl_then [‘ls’, ‘i’] assume_tac) >> - pop_assum mp_tac >> CASE_TAC >> fs [] -QED - -Theorem nth_fuel_least_fail_mono: - !n ls i. - n < $LEAST (nth_fuel_P ls i) ==> - nth_fuel n ls i = Loop -Proof - rpt gen_tac >> - disch_tac >> - imp_res_tac whileTheory.LESS_LEAST >> - fs [nth_fuel_P_def, is_loop_def] >> - pop_assum mp_tac >> - CASE_TAC -QED - -Theorem nth_fuel_least_success_mono: - !n ls i. - $LEAST (nth_fuel_P ls i) <= n ==> - nth_fuel n ls i = nth_fuel ($LEAST (nth_fuel_P ls i)) ls i -Proof - rpt gen_tac >> - disch_tac >> - (* Case disjunction on whether there exists a fuel such that it terminates *) - Cases_on ‘?m. nth_fuel_P ls i m’ >- ( - (* Terminates *) - irule EQ_SYM >> - irule nth_fuel_P_mono >> fs [] >> - (* Prove that calling with the least upper bound of fuel succeeds *) - qspec_then ‘nth_fuel_P (ls :α list_t) (i :u32)’ imp_res_tac whileTheory.LEAST_EXISTS_IMP - ) >> - (* Doesn't terminate *) - fs [] >> - sg ‘~(nth_fuel_P ls i n)’ >- fs [] >> - sg ‘~(nth_fuel_P ls i ($LEAST (nth_fuel_P ls i)))’ >- fs [] >> - fs [nth_fuel_P_def, is_loop_def] >> - pop_assum mp_tac >> CASE_TAC >> - pop_assum mp_tac >> - pop_assum mp_tac >> CASE_TAC -QED - -val nth_def_raw = Define ‘ - nth ls i = - if (?n. nth_fuel_P ls i n) then nth_fuel ($LEAST (nth_fuel_P ls i)) ls i - else Loop -’ - -(* This makes the proofs easier, in that it helps us control the context *) -val nth_expand_def = Define ‘ - nth_expand nth ls i = - case ls of - | ListCons x tl => - if u32_to_int i = (0:int) - then Return x - else - do - i0 <- u32_sub i (int_to_u32 1); - nth tl i0 - od - | ListNil => - Fail Failure -’ - -(* Prove the important theorems *) -Theorem nth_def_terminates: - !ls i. - (?n. nth_fuel_P ls i n) ==> - nth ls i = - nth_expand nth ls i -Proof - rpt strip_tac >> - fs [nth_expand_def] >> - PURE_ONCE_REWRITE_TAC [nth_def_raw] >> - (* Prove that the least upper bound is <= n *) - sg ‘$LEAST (nth_fuel_P ls i) <= n’ >-( - qspec_then ‘nth_fuel_P (ls :α list_t) (i :u32)’ imp_res_tac whileTheory.LEAST_EXISTS_IMP >> - spose_not_then assume_tac >> fs [] - ) >> - (* Use the monotonicity theorem - TODO: ? *) - imp_res_tac nth_fuel_least_success_mono >> - (* Rewrite only on the left - TODO: easy way ?? *) - qspecl_then [‘$LEAST (nth_fuel_P ls i)’, ‘ls’, ‘i’] assume_tac nth_fuel_def >> - (* TODO: how to discard assumptions?? *) - fs [] >> pop_assum (fn _ => fs []) >> - (* Cases on the least upper bound *) - Cases_on ‘$LEAST (nth_fuel_P ls i)’ >> rw [] >- ( - (* The bound is equal to 0: contradiction *) - sg ‘nth_fuel 0 ls i = Loop’ >- (PURE_ONCE_REWRITE_TAC [nth_fuel_def] >> rw []) >> - fs [nth_fuel_P_def, is_loop_def] - ) >> - (* Bound not equal to 0 *) - fs [nth_fuel_P_def, is_loop_def] >> - (* Explore all the paths *) - fs [st_ex_bind_def] >> - Cases_on ‘ls’ >> rw [] >> fs [] >> - Cases_on ‘u32_sub i (int_to_u32 1)’ >> rw [] >> fs [] >> - (* Recursive call: use monotonicity - we have an assumption which eliminates the Loop case *) - Cases_on ‘nth_fuel n' l a’ >> rw [] >> fs [] >> - (sg ‘nth_fuel_P l a n'’ >- fs [nth_fuel_P_def, is_loop_def]) >> - (sg ‘$LEAST (nth_fuel_P l a) <= n'’ >-( - qspec_then ‘nth_fuel_P l a’ imp_res_tac whileTheory.LEAST_EXISTS_IMP >> - spose_not_then assume_tac >> fs [])) >> - imp_res_tac nth_fuel_least_success_mono >> fs [] -QED - -(* Prove the important theorems *) -Theorem nth_def_loop: - !ls i. - (!n. ~nth_fuel_P ls i n) ==> - nth ls i = - nth_expand nth ls i -Proof - rpt gen_tac >> - PURE_ONCE_REWRITE_TAC [nth_def_raw] >> - strip_tac >> rw[] >> - (* Non-terminating case *) - sg ‘∀n. ¬nth_fuel_P ls i (SUC n)’ >- rw [] >> - fs [nth_fuel_P_def, is_loop_def] >> - pop_assum mp_tac >> - PURE_ONCE_REWRITE_TAC [nth_fuel_def] >> - rw [] >> - fs [nth_expand_def] >> - (* Evaluate all the paths *) - fs [st_ex_bind_def] >> - Cases_on ‘ls’ >> rw [] >> fs [] >> - Cases_on ‘u32_sub i (int_to_u32 1)’ >> rw [] >> fs [] >> - (* Use the definition of nth *) - rw [nth_def_raw] >> - first_x_assum (qspec_then ‘$LEAST (nth_fuel_P l a)’ assume_tac) >> - Cases_on ‘nth_fuel ($LEAST (nth_fuel_P l a)) l a’ >> fs [] -QED - -(* The final theorem *) -Theorem nth_def: - !ls i. - nth ls i = - case ls of - | ListCons x tl => - if u32_to_int i = (0:int) - then Return x - else - do - i0 <- u32_sub i (int_to_u32 1); - nth tl i0 - od - | ListNil => - Fail Failure -Proof - rpt strip_tac >> - Cases_on ‘?n. nth_fuel_P ls i n’ >-( - assume_tac nth_def_terminates >> - fs [nth_expand_def] >> - pop_assum irule >> - metis_tac []) >> - fs [] >> imp_res_tac nth_def_loop >> fs [nth_expand_def] -QED - -(* - -Je viens de finir ma petite expérimentation avec le fuel : ça marche bien. Par exemple, si je pose les définitions suivantes : -Datatype: - result = Return 'a | Fail error | Loop -End - -(* Omitting some definitions like the bind *) - -val _ = Define ‘ - nth_fuel (n : num) (ls : 't list_t) (i : u32) : 't result = - case n of - | 0 => Loop - | SUC n => - do case ls of - | ListCons x tl => - if u32_to_int i = (0:int) - then Return x - else - do - i0 <- u32_sub i (int_to_u32 1); - nth_fuel n tl i0 - od - | ListNil => - Fail Failure - od - ’ - -val _ = Define 'is_loop r = case r of Loop => T | _ => F' - -val _ = Define 'nth_fuel_P ls i n = ~is_loop (nth_fuel n ls i)' - -(* $LEAST returns the least upper bound for a predicate (if it exists - otherwise it returns an arbitrary number) *) -val _ = Define ‘ - nth ls i = - if (?n. nth_fuel_P ls i n) then nth_fuel ($LEAST (nth_fuel_P ls i)) ls i - else Loop -’ -J'arrive à montrer (c'est un chouïa technique) : -Theorem nth_def: - !ls i. - nth ls i = - case ls of - | ListCons x tl => - if u32_to_int i = (0:int) - then Return x - else - do - i0 <- u32_sub i (int_to_u32 1); - nth tl i0 - od - | ListNil => - Fail Failure - -*) diff --git a/backends/hol4/TestScript.sml b/backends/hol4/TestScript.sml new file mode 100644 index 00000000..2eb3f23b --- /dev/null +++ b/backends/hol4/TestScript.sml @@ -0,0 +1,1746 @@ +open HolKernel boolLib bossLib Parse + +val primitives_theory_name = "Test" +val _ = new_theory primitives_theory_name + +open boolTheory integerTheory wordsTheory stringTheory + +Datatype: + error = Failure +End + +Datatype: + result = Return 'a | Fail error | Loop +End + +Type M = ``: 'a result`` + +(* TODO: rename *) +val st_ex_bind_def = Define ` + (st_ex_bind : 'a M -> ('a -> 'b M) -> 'b M) x f = + case x of + Return y => f y + | Fail e => Fail e + | Loop => Loop`; + +val bind_name = fst (dest_const “st_ex_bind”) + +val st_ex_return_def = Define ` + (st_ex_return : 'a -> 'a M) x = + Return x`; + +Overload monad_bind[local] = ``st_ex_bind`` +Overload monad_unitbind[local] = ``\x y. st_ex_bind x (\z. y)`` +Overload monad_ignore_bind[local] = ``\x y. st_ex_bind x (\z. y)`` +(*Overload ex_bind[local] = ``st_ex_bind`` *) +(* Overload ex_return[local] = ``st_ex_return`` *) +(*Overload failwith = ``raise_Fail``*) + +(* Temporarily allow the monadic syntax *) +val _ = monadsyntax.temp_add_monadsyntax () + +val test1_def = Define ` + test1 (x : bool) = Return x` + +val is_true_def = Define ‘ + is_true (x : bool) = if x then Return () else Fail Failure’ + +val test1_def = Define ‘ + test1 (x : bool) = Return x’ + +val test_monad_def = Define ` + test_monad v = + do + x <- Return v; + Return x + od` + +val test_monad2_def = Define ` + test_monad2 = + do + x <- Return T; + Return x + od` + +val test_monad3_def = Define ` + test_monad3 x = + do + is_true x; + Return x + od` + +(** + * Arithmetic + *) + +open intLib + +val test_int1 = Define ‘int1 = 32’ +val test_int2 = Define ‘int2 = -32’ + +Theorem INT_THM1: + !(x y : int). x > 0 ==> y > 0 ==> x + y > 0 +Proof + ARITH_TAC +QED + +Theorem INT_THM2: + !(x : int). T +Proof + rw[] +QED + +val _ = prefer_int () + +val x = “-36217863217862718” + +(* Deactivate notations for int *) +val _ = deprecate_int () +open arithmeticTheory + + +val m = Hol_pp.print_apropos +val f = Hol_pp.print_find + +(* Display types on/off: M-h C-t *) +(* Move back: M-h b *) + +val _ = numLib.deprecate_num () +val _ = numLib.prefer_num () + +Theorem NAT_THM1: + !(n : num). n < n + 1 +Proof + Induct_on ‘n’ >> DECIDE_TAC +QED + +Theorem NAT_THM2: + !(n : num). n < n + (1 : num) +Proof + gen_tac >> + Induct_on ‘n’ >- ( + PURE_REWRITE_TAC [ADD, NUMERAL_DEF, BIT1, ALT_ZERO] >> + PURE_REWRITE_TAC [prim_recTheory.LESS_0_0]) >> + PURE_REWRITE_TAC [ADD] >> + irule prim_recTheory.LESS_MONO >> + asm_rewrite_tac [] +QED + + +val x = “1278361286371286:num” + + +(********************** PRIMITIVES *) +val _ = prefer_int () + +val _ = new_type ("u32", 0) +val _ = new_type ("i32", 0) + +(*val u32_min_def = Define ‘u32_min = (0:int)’*) +val u32_max_def = Define ‘u32_max = (4294967295:int)’ + +(* TODO: change that *) +val usize_max_def = Define ‘usize_max = (4294967295:int)’ + +val i32_min_def = Define ‘i32_min = (-2147483648:int)’ +val i32_max_def = Define ‘i32_max = (2147483647:int)’ + +val _ = new_constant ("u32_to_int", “:u32 -> int”) +val _ = new_constant ("i32_to_int", “:i32 -> int”) + +val _ = new_constant ("int_to_u32", “:int -> u32”) +val _ = new_constant ("int_to_i32", “:int -> i32”) + + +(* TODO: change to "...of..." *) +val u32_to_int_bounds = + new_axiom ( + "u32_to_int_bounds", + “!n. 0 <= u32_to_int n /\ u32_to_int n <= u32_max”) + +val i32_to_int_bounds = + new_axiom ( + "i32_to_int_bounds", + “!n. i32_min <= i32_to_int n /\ i32_to_int n <= i32_max”) + +val int_to_u32_id = new_axiom ("int_to_u32_id", + “!n. 0 <= n /\ n <= u32_max ==> u32_to_int (int_to_u32 n) = n”) + +val int_to_i32_id = + new_axiom ( + "int_to_i32_id", + “!n. i32_min <= n /\ n <= i32_max ==> + i32_to_int (int_to_i32 n) = n”) + +val mk_u32_def = Define + ‘mk_u32 n = + if 0 <= n /\ n <= u32_max then Return (int_to_u32 n) + else Fail Failure’ + +val u32_add_def = Define ‘u32_add x y = mk_u32 ((u32_to_int x) + (u32_to_int y))’ + +Theorem MK_U32_SUCCESS: + !n. 0 <= n /\ n <= u32_max ==> + mk_u32 n = Return (int_to_u32 n) +Proof + rw[mk_u32_def] +QED + +Theorem U32_ADD_EQ: + !x y. + u32_to_int x + u32_to_int y <= u32_max ==> + ?z. u32_add x y = Return z /\ u32_to_int z = u32_to_int x + u32_to_int y +Proof + rpt gen_tac >> + rpt DISCH_TAC >> + exists_tac “int_to_u32 (u32_to_int x + u32_to_int y)” >> + imp_res_tac MK_U32_SUCCESS >> + (* There is probably a better way of doing this *) + sg ‘0 <= u32_to_int x’ >- (rw[u32_to_int_bounds]) >> + sg ‘0 <= u32_to_int y’ >- (rw[u32_to_int_bounds]) >> + fs [u32_add_def] >> + irule int_to_u32_id >> + fs[] +QED + +val u32_sub_def = Define ‘u32_sub x y = mk_u32 ((u32_to_int x) - (u32_to_int y))’ + +Theorem U32_SUB_EQ: + !x y. + 0 <= u32_to_int x - u32_to_int y ==> + ?z. u32_sub x y = Return z /\ u32_to_int z = u32_to_int x - u32_to_int y +Proof + rpt gen_tac >> + rpt DISCH_TAC >> + exists_tac “int_to_u32 (u32_to_int x - u32_to_int y)” >> + imp_res_tac MK_U32_SUCCESS >> + (* There is probably a better way of doing this *) + sg ‘u32_to_int x − u32_to_int y ≤ u32_max’ >-( + sg ‘u32_to_int x <= u32_max’ >- (rw[u32_to_int_bounds]) >> + sg ‘0 <= u32_to_int y’ >- (rw[u32_to_int_bounds]) >> + COOPER_TAC + ) >> + fs [u32_sub_def] >> + irule int_to_u32_id >> + fs[] +QED + +val mk_i32_def = Define + ‘mk_i32 n = + if i32_min <= n /\ n <= i32_max then Return (int_to_i32 n) + else Fail Failure’ + +val i32_add_def = Define ‘i32_add x y = mk_i32 ((i32_to_int x) + (i32_to_int y))’ + +Theorem MK_I32_SUCCESS: + !n. i32_min <= n /\ n <= i32_max ==> + mk_i32 n = Return (int_to_i32 n) +Proof + rw[mk_i32_def] +QED + +Theorem I32_ADD_EQ: + !x y. + i32_min <= i32_to_int x + i32_to_int y ==> + i32_to_int x + i32_to_int y <= i32_max ==> + ?z. i32_add x y = Return z /\ i32_to_int z = i32_to_int x + i32_to_int y +Proof + rpt gen_tac >> + rpt DISCH_TAC >> + exists_tac “int_to_i32 (i32_to_int x + i32_to_int y)” >> + imp_res_tac MK_I32_SUCCESS >> + fs [i32_min_def, i32_add_def] >> + irule int_to_i32_id >> + fs[i32_min_def] +QED + +open listTheory + +val _ = new_type ("vec", 1) +val _ = new_constant ("vec_to_list", “:'a vec -> 'a list”) + +val VEC_TO_LIST_NUM_BOUNDS = + new_axiom ( + "VEC_TO_LIST_BOUNDS", + “!v. let l = LENGTH (vec_to_list v) in + (0:num) <= l /\ l <= (4294967295:num)”) + +Theorem VEC_TO_LIST_INT_BOUNDS: + !v. let l = int_of_num (LENGTH (vec_to_list v)) in + 0 <= l /\ l <= u32_max +Proof + gen_tac >> + rw [u32_max_def] >> + assume_tac VEC_TO_LIST_NUM_BOUNDS >> + fs[] +QED + +val VEC_LEN_DEF = Define ‘vec_len v = int_to_u32 (int_of_num (LENGTH (vec_to_list v)))’ + +(* +(* Useless *) +Theorem VEC_LEN_BOUNDS: + !v. u32_min <= u32_to_int (vec_len v) /\ u32_to_int (vec_len v) <= u32_max +Proof + gen_tac >> + qspec_then ‘v’ assume_tac VEC_TO_LIST_INT_BOUNDS >> + fs[VEC_LEN_DEF] >> + IMP_RES_TAC int_to_u32_id >> + fs[] +QED +*) + +(* The type parameters are ordered in alphabetical order *) +Datatype: + test = Variant1 'b | Variant2 'a +End + +Datatype: + test2 = Variant1_1 'T2 | Variant2_1 'T1 +End + +Datatype: + test2 = Variant1_2 'T1 | Variant2_2 'T2 +End + +(* +“Variant1_1 3” +“Variant1_2 3” + +type_of “CONS 3” +*) + +(* TODO: argument order, we must also omit arguments in new type *) +Datatype: + list_t = + ListCons 't list_t + | ListNil +End + +val list_nth_mut_loop_loop_fwd_def = Define ‘ + list_nth_mut_loop_loop_fwd (ls : 't list_t) (i : u32) : 't result = + case ls of + | ListCons x tl => + if u32_to_int i = (0:int) + then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + list_nth_mut_loop_loop_fwd tl i0 + od + | ListNil => + Fail Failure +’ + +(* +CoInductive coind: + !x y. coind x /\ coind y ==> coind (x + y) +End +*) + +(* +(* This generates inconsistent theorems *) +CoInductive loop: + !x. loop x = if x then loop x else 0 +End + +CoInductive loop: + !(x : int). loop x = if x > 0 then loop (x - 1) else 0 +End +*) + +(* This terminates *) +val list_nth_mut_loop_loop_fwd_def = Define ‘ + list_nth_mut_loop_loop_fwd (ls : 't list_t) (i : u32) : 't result = + case ls of + | ListCons x tl => + if u32_to_int i = (0:int) + then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + list_nth_mut_loop_loop_fwd tl i0 + od + | ListNil => + Fail Failure +’ + +(* This is sort of a coinductive definition. + + This can be justified: + - we first define a version [nth_fuel] which uses fuel (and is thus terminating) + - we define the predicate P: + P ls i n = case nth_fuel n ls i of Return _ => T | _ => F + - we then use [LEAST] (least upper bound for natural numbers) to define nth as: + “nth ls i = if (?n. P n) then nth_fuel (LEAST (P ls i)) ls i else Fail Loop ” + - we finally prove that nth satisfies the proper equation. + + We would need the following intermediate lemma: + !n. + n < LEAST (P ls i) ==> nth_fuel n ls i = Fail _ /\ + n >= LEAST (P ls i) ==> nth_fuel n ls i = nth_fuel (LEAST P ls i) ls i + + *) +val _ = new_constant ("nth", “:'t list_t -> u32 -> 't result”) +val nth_def = new_axiom ("nth_def", “ + nth (ls : 't list_t) (i : u32) : 't result = + case ls of + | ListCons x tl => + if u32_to_int i = (0:int) + then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + nth tl i0 + od + | ListNil => + Fail Failure + ”) + + +(*** Examples of proofs on [nth] *) +val list_t_v_def = Define ‘ + list_t_v ListNil = [] /\ + list_t_v (ListCons x tl) = x :: list_t_v tl +’ + +(* TODO: move *) +open dep_rewrite +open integerTheory + +(* Ignore a theorem. + + To be used in conjunction with {!pop_assum} for instance. + *) +fun IGNORE_TAC (_ : thm) : tactic = ALL_TAC + + +Theorem INT_OF_NUM_INJ: + !n m. &n = &m ==> n = m +Proof + rpt strip_tac >> + fs [Num] +QED + +Theorem NUM_SUB_EQ: + !(x y z : int). x = y - z ==> 0 <= x ==> 0 <= z ==> Num y = Num z + Num x +Proof + rpt strip_tac >> + sg ‘0 <= y’ >- COOPER_TAC >> + rfs [] >> + (* Convert to integers *) + irule INT_OF_NUM_INJ >> + imp_res_tac (GSYM INT_OF_NUM) >> + (* Associativity of & *) + PURE_REWRITE_TAC [GSYM INT_ADD] >> + fs [] +QED + +Theorem NUM_SUB_1_EQ: + !(x y : int). x = y - 1 ==> 0 <= x ==> Num y = SUC (Num x) +Proof + rpt strip_tac >> + (* Get rid of the SUC *) + sg ‘SUC (Num x) = 1 + Num x’ >-(rw [ADD]) >> rw [] >> + (* Massage a bit the goal *) + qsuff_tac ‘Num y = Num (y − 1) + Num 1’ >- COOPER_TAC >> + (* Apply the general theorem *) + irule NUM_SUB_EQ >> + COOPER_TAC +QED + +(* TODO: remove *) +Theorem NUM_SUB_1_EQ1: + !i. 0 <= i - 1 ==> Num i = SUC (Num (i-1)) +Proof + rpt strip_tac >> + (* 0 <= i *) + sg ‘0 <= i’ >- COOPER_TAC >> + (* Get rid of the SUC *) + sg ‘SUC (Num (i - 1)) = 1 + Num (i - 1)’ >-(rw [ADD]) >> + rw [] >> + (* Convert to integers*) + irule INT_OF_NUM_INJ >> + imp_res_tac (GSYM INT_OF_NUM) >> + (* Associativity of & *) + PURE_REWRITE_TAC [GSYM INT_ADD] >> + fs [] +QED + +(* TODO: + - list all the integer variables, and insert bounds in the assumptions + - replace u32_min by 0? + - i - 1 + - auto lookup of spec lemmas +*) + +(* Add a list of theorems in the assumptions - TODO: move *) +fun ASSUME_TACL (thms : thm list) : tactic = + let + (* TODO: use MAP_EVERY *) + fun t thms = + case thms of + [] => ALL_TAC + | thm :: thms => ASSUME_TAC thm >> t thms + in + t thms + end + +(* The map from integer type to bounds lemmas *) +val integer_bounds_lemmas = + Redblackmap.fromList String.compare + [ + ("u32", u32_to_int_bounds), + ("i32", i32_to_int_bounds) + ] + +(* The map from integer type to conversion lemmas *) +val integer_conversion_lemmas = + Redblackmap.fromList String.compare + [ + ("u32", int_to_u32_id), + ("i32", int_to_i32_id) + ] + +val integer_conversion_lemmas_list = + map snd (Redblackmap.listItems integer_conversion_lemmas) + +(* Not sure how term nets work, nor how we are supposed to convert Term.term + to mlibTerm.term. + + TODO: it seems we need to explore the term and convert everything to strings. + *) +fun term_to_mlib_term (t : term) : mlibTerm.term = + mlibTerm.string_to_term (term_to_string t) + +(* +(* The lhs of the conclusion of the integer conversion lemmas - we use this for + pattern matching *) +val integer_conversion_lhs_concls = + let + val thms = map snd (Redblackmap.listItems integer_conversion_lemmas); + val concls = map (lhs o concl o UNDISCH_ALL o SPEC_ALL) thms; + in concls end +*) + +(* +val integer_conversion_concls_net = + let + val maplets = map (fn x => fst (dest_eq x) |-> ()) integer_conversion_concls; + + val maplets = map (fn x => fst (mlibTerm.dest_eq x) |-> ()) integer_conversion_concls; + val maplets = map (fn x => fst (mlibThm.dest_unit_eq x) |-> ()) integer_conversion_concls; + val parameters = { fifo=false }; + in mlibTermnet.from_maplets parameters maplets end + +mlibTerm.string_to_term (term_to_string “u32_to_int (int_to_u32 n) = n”) +term_to_quote + +SIMP_CONV +mlibThm.dest_thm u32_to_int_bounds +mlibThm.dest_unit u32_to_int_bounds +*) + +(* The integer types *) +val integer_types_names = + Redblackset.fromList String.compare + (map fst (Redblackmap.listItems integer_bounds_lemmas)) + +val all_integer_bounds = [ + u32_max_def, + i32_min_def, + i32_max_def +] + +(* Small utility: compute the set of assumptions in the context. + + We isolate this code in a utility in order to be able to improve it: + for now we simply put all the assumptions in a set, but in the future + we might want to split the assumptions which are conjunctions in order + to be more precise. + *) +fun compute_asms_set ((asms,g) : goal) : term Redblackset.set = + Redblackset.fromList Term.compare asms + +(* See {!assume_bounds_for_all_int_vars}. + + This tactic is in charge of adding assumptions for one variable. + *) + +fun assume_bounds_for_int_var + (asms_set: term Redblackset.set) (var : string) (ty : string) : + tactic = + let + (* Lookup the lemma to apply *) + val lemma = Redblackmap.find (integer_bounds_lemmas, ty); + (* Instantiate the lemma *) + val ty_t = mk_type (ty, []); + val var_t = mk_var (var, ty_t); + val lemma = SPEC var_t lemma; + (* Split the theorem into a list of conjuncts. + + The bounds are typically a conjunction: + {[ + ⊢ 0 ≤ u32_to_int x ∧ u32_to_int x ≤ u32_max: thm + ]} + *) + val lemmas = CONJUNCTS lemma; + (* Filter the conjuncts: some of them might already be in the context, + we don't want to introduce them again, as it would pollute it. + *) + val lemmas = filter (fn lem => not (Redblackset.member (asms_set, concl lem))) lemmas; + in + (* Introduce the assumptions in the context *) + ASSUME_TACL lemmas + end + +(* Destruct if possible a term of the shape: [x y], + where [x] is not a comb. + + Returns [(x, y)] + *) +fun dest_single_comb (t : term) : (term * term) option = + case strip_comb t of + (x, [y]) => SOME (x, y) + | _ => NONE + +(** Destruct if possible a term of the shape: [x (y z)]. + Returns [(x, y, z)] + *) +fun dest_single_comb_twice (t : term) : (term * term * term) option = + case dest_single_comb t of + NONE => NONE + | SOME (x, y) => + case dest_single_comb y of + NONE => NONE + | SOME (y, z) => SOME (x, y, z) + +(* A utility map to lookup integer conversion lemmas *) +val integer_conversion_pat_map = + let + val thms = map snd (Redblackmap.listItems integer_conversion_lemmas); + val tl = map (lhs o concl o UNDISCH_ALL o SPEC_ALL) thms; + val tl = map (valOf o dest_single_comb_twice) tl; + val tl = map (fn (x, y, _) => (x, y)) tl; + val m = Redblackmap.fromList Term.compare tl + in m end + +(* Introduce bound assumptions for all the machine integers in the context. + + Exemple: + ======== + If there is “x : u32” in the input set, then we introduce: + {[ + 0 <= u32_to_int x + u32_to_int x <= u32_max + ]} + *) +fun assume_bounds_for_all_int_vars (asms, g) = + let + (* Compute the set of integer variables in the context *) + val vars = free_varsl (g :: asms); + (* Compute the set of assumptions already present in the context *) + val asms_set = compute_asms_set (asms, g); + (* Filter the variables to keep only the ones with type machine integer, + decompose the types at the same time *) + fun decompose_var (v : term) : (string * string) = + let + val (v, ty) = dest_var v; + val {Args=args, Thy=thy, Tyop=ty} = dest_thy_type ty; + val _ = assert null args; + val _ = assert (fn thy => thy = primitives_theory_name) thy; + val _ = assert (fn ty => Redblackset.member (integer_types_names, ty)) ty; + in (v, ty) end; + val vars = mapfilter decompose_var vars; + (* Add assumptions for one variable *) + fun add_var_asm (v, ty) : tactic = + assume_bounds_for_int_var asms_set v ty; + (* Add assumptions for all the variables *) + (* TODO: use MAP_EVERY *) + fun add_vars_asm vl : tactic = + case vl of + [] => ALL_TAC + | v :: vl => + add_var_asm v >> add_vars_asm vl; + in + add_vars_asm vars (asms, g) + end + +(* +dest_thy_type “:u32” +val massage : tactic = assume_bounds_for_all_int_vars +val vl = vars +val (v::vl) = vl +*) + +(* +val (asms, g) = top_goal () +fun bounds_for_ints_in_list (vars : (string * hol_type) list) : tactic = + foldl + FAIL_TAC "" +val var = "x" +val ty = "u32" + +val asms_set = Redblackset.fromList Term.compare asms; + +val x = “1: int” +val ty = "u32" + +val thm = lemma +*) + +(* Given a theorem of the shape: + {[ + A0, ..., An ⊢ B0 ==> ... ==> Bm ==> concl + ]} + + Rewrite it so that it has the shape: + {[ + ⊢ (A0 /\ ... /\ An /\ B0 /\ ... /\ Bm) ==> concl + ]} + *) +fun thm_to_conj_implies (thm : thm) : thm = + let + (* Discharge all the assumptions *) + val thm = DISCH_ALL thm; + (* Rewrite the implications as one conjunction *) + val thm = PURE_REWRITE_RULE [GSYM satTheory.AND_IMP] thm; + in thm end + + +(* Like THEN1 and >-, but doesn't fail if the first subgoal is not completely + solved. + + TODO: how to get the notation right? + *) +fun op PARTIAL_THEN1 (tac1: tactic) (tac2: tactic) : tactic = tac1 THEN_LT (NTH_GOAL tac2 1) + +(* If the current goal is [asms ⊢ g], and given a lemma of the form + [⊢ H ==> C], do the following: + - introduce [asms ⊢ H] as a subgoal and apply the given tactic on it + - also calls the theorem tactic with the theorem [asms ⊢ C] + + If the lemma is not an implication, we directly call the theorem tactic. + *) +fun intro_premise_then (premise_tac: tactic) (then_tac: thm_tactic) (thm : thm) : tactic = + let + val c = concl thm; + (* First case: there is a premise to prove *) + fun prove_premise_then (h : term) = + PARTIAL_THEN1 (SUBGOAL_THEN h (fn h_thm => then_tac (MP thm h_thm))) premise_tac; + (* Second case: no premise to prove *) + val no_prove_premise_then = then_tac thm; + in + if is_imp c then prove_premise_then (fst (dest_imp c)) else no_prove_premise_then + end + +(* Same as {!intro_premise_then} but fails if the premise_tac fails to prove the premise *) +fun prove_premise_then (premise_tac: tactic) (then_tac: thm_tactic) (thm : thm) : tactic = + intro_premise_then + (premise_tac >> FAIL_TAC "prove_premise_then: could not prove premise") + then_tac thm + +(* +val thm = th +*) + +(* Call a function on all the subterms of a term *) +fun dep_apply_in_subterms + (f : string Redblackset.set -> term -> unit) + (bound_vars : string Redblackset.set) + (t : term) : unit = + let + val dep = dep_apply_in_subterms f; + val _ = f bound_vars t; + in + case dest_term t of + VAR (name, ty) => () + | CONST {Name=name, Thy=thy, Ty=ty} => () + | COMB (app, arg) => + let + val _ = dep bound_vars app; + val _ = dep bound_vars arg; + in () end + | LAMB (bvar, body) => + let + val (varname, ty) = dest_var bvar; + val bound_vars = Redblackset.add (bound_vars, varname); + val _ = dep bound_vars body; + in () end + end + +(* Return the set of free variables appearing in the residues of a term substitution *) +fun free_vars_in_subst_residue (s: (term, term) Term.subst) : string Redblackset.set = + let + val free_vars = free_varsl (map (fn {redex=_, residue=x} => x) s); + val free_vars = map (fst o dest_var) free_vars; + val free_vars = Redblackset.fromList String.compare free_vars; + in free_vars end + +(* Attempt to instantiate a rewrite theorem. + + Remark: this theorem should be of the form: + H ⊢ x = y + + (without quantified variables). + + **REMARK**: the function raises a HOL_ERR exception if it fails. + + [forbid_vars]: forbid substituting with those vars (typically because + we are maching in a subterm under lambdas, and some of those variables + are bounds in the outer lambdas). +*) +fun inst_match_concl (forbid_vars : string Redblackset.set) (th : thm) (t : term) : thm = + let + (* Retrieve the lhs of the conclusion of the theorem *) + val l = lhs (concl th); + (* Match this lhs with the term *) + val (var_s, ty_s) = match_term l t; + (* Check that we are allowed to perform the substitution *) + val free_vars = free_vars_in_subst_residue var_s; + val _ = assert Redblackset.isEmpty (Redblackset.intersection (free_vars, forbid_vars)); + in + (* Perform the substitution *) + INST var_s (INST_TYPE ty_s th) + end + +(* +val forbid_vars = Redblackset.empty String.compare +val t = “u32_to_int (int_to_u32 x)” +val t = “u32_to_int (int_to_u32 3)” +val th = (UNDISCH_ALL o SPEC_ALL) int_to_u32_id +*) + +(* Attempt to instantiate a theorem by matching its first premise. + + Note that we make the hypothesis tha all the free variables which need + to be instantiated appear in the first premise, of course (the caller should + enforce this). + + Remark: this theorem should be of the form: + ⊢ H0 ==> ... ==> Hn ==> H + + (without quantified variables). + + **REMARK**: the function raises a HOL_ERR exception if it fails. + + [forbid_vars]: see [inst_match_concl] +*) +fun inst_match_first_premise + (forbid_vars : string Redblackset.set) (th : thm) (t : term) : thm = + let + (* Retrieve the first premise *) + val l = (fst o dest_imp o concl) th; + (* Match this with the term *) + val (var_s, ty_s) = match_term l t; + (* Check that we are allowed to perform the substitution *) + val free_vars = free_vars_in_subst_residue var_s; + val _ = assert Redblackset.isEmpty (Redblackset.intersection (free_vars, forbid_vars)); + in + (* Perform the substitution *) + INST var_s (INST_TYPE ty_s th) + end + +(* +val forbid_vars = Redblackset.empty String.compare +val t = “u32_to_int z = u32_to_int i − 1” +val th = SPEC_ALL NUM_SUB_1_EQ +*) + +(* Call a matching function on all the subterms in the provided list of term. + This is a generic function. + + [try_match] should return an instantiated theorem, as well as a term which + identifies this theorem (the lhs of the equality, if this is a rewriting + theorem for instance - we use this to check for collisions, and discard + redundant instantiations). + *) +fun inst_match_in_terms + (try_match: string Redblackset.set -> term -> term * thm) + (tl : term list) : thm list = + let + (* We use a map when storing the theorems, to avoid storing the same theorem twice *) + val inst_thms: (term, thm) Redblackmap.dict ref = ref (Redblackmap.mkDict Term.compare); + fun try_instantiate bvars t = + let + val (inst_th_tm, inst_th) = try_match bvars t; + in + inst_thms := Redblackmap.insert (!inst_thms, inst_th_tm, inst_th) + end + handle HOL_ERR _ => (); + (* Explore the term *) + val _ = app (dep_apply_in_subterms try_instantiate (Redblackset.empty String.compare)) tl; + in + map snd (Redblackmap.listItems (!inst_thms)) + end + +(* Given a rewriting theorem [th] which has premises, return all the + instantiations of this theorem which make its conclusion match subterms + in the provided list of term. + *) +fun inst_match_concl_in_terms (th : thm) (tl : term list) : thm list = + let + val th = (UNDISCH_ALL o SPEC_ALL) th; + fun try_match bvars t = + let + val inst_th = inst_match_concl bvars th t; + in + (lhs (concl inst_th), inst_th) + end; + in + inst_match_in_terms try_match tl + end + +(* +val t = “!x. u32_to_int (int_to_u32 x) = u32_to_int (int_to_u32 y)” +val th = int_to_u32_id + +val thms = inst_match_concl_in_terms int_to_u32_id [t] +*) + + +(* Given a theorem [th] which has premises, return all the + instantiations of this theorem which make its first premise match subterms + in the provided list of term. + *) +fun inst_match_first_premise_in_terms (th : thm) (tl : term list) : thm list = + let + val th = SPEC_ALL th; + fun try_match bvars t = + let + val inst_th = inst_match_first_premise bvars th t; + in + ((fst o dest_imp o concl) inst_th, inst_th) + end; + in + inst_match_in_terms try_match tl + end + +(* +val t = “x = y - 1 ==> T” +val th = SPEC_ALL NUM_SUB_1_EQ + +val thms = inst_match_first_premise_in_terms th [t] +*) + +(* Attempt to apply dependent rewrites with a theorem by matching its + conclusion with subterms of the goal. + *) +fun apply_dep_rewrites_match_concl_tac + (prove_premise : tactic) (then_tac : thm_tactic) (th : thm) : tactic = + fn (asms, g) => + let + (* Discharge the assumptions so that the goal is one single term *) + val thms = inst_match_concl_in_terms th (g :: asms); + val thms = map thm_to_conj_implies thms; + in + (* Apply each theorem *) + MAP_EVERY (prove_premise_then prove_premise then_tac) thms (asms, g) + end + +(* +val (asms, g) = ([ + “u32_to_int z = u32_to_int i − u32_to_int (int_to_u32 1)”, + “u32_to_int (int_to_u32 2) = 2” +], “T”) + +apply_dep_rewrites_match_concl_tac + (FULL_SIMP_TAC simpLib.empty_ss all_integer_bounds >> COOPER_TAC) + (fn th => FULL_SIMP_TAC simpLib.empty_ss [th]) + int_to_u32_id +*) + +(* Attempt to apply dependent rewrites with a theorem by matching its + first premise with subterms of the goal. + *) +fun apply_dep_rewrites_match_first_premise_tac + (prove_premise : tactic) (then_tac : thm_tactic) (th : thm) : tactic = + fn (asms, g) => + let + (* Discharge the assumptions so that the goal is one single term *) + val thms = inst_match_first_premise_in_terms th (g :: asms); + val thms = map thm_to_conj_implies thms; + fun apply_tac th = + let + val th = thm_to_conj_implies th; + in + prove_premise_then prove_premise then_tac th + end; + in + (* Apply each theorem *) + MAP_EVERY apply_tac thms (asms, g) + end + +(* See {!rewrite_all_int_conversion_ids}. + + Small utility which takes care of one rewriting. + + TODO: we actually don't use it. REMOVE? + *) +fun rewrite_int_conversion_id + (asms_set: term Redblackset.set) (x : term) (ty : string) : + tactic = + let + (* Lookup the theorem *) + val lemma = Redblackmap.find (integer_conversion_lemmas, ty); + (* Instantiate *) + val lemma = SPEC x lemma; + (* Rewrite the lemma. The lemma typically has the shape: + ⊢ u32_min <= x /\ x <= u32_max ==> u32_to_int (int_to_u32 x) = x + + Make sure the lemma has the proper shape, attempt to prove the premise, + then use the conclusion if it succeeds. + *) + val lemma = thm_to_conj_implies lemma; + (* Retrieve the conclusion of the lemma - we do this to check if it is not + already in the assumptions *) + val c = concl (UNDISCH_ALL lemma); + val already_in_asms = Redblackset.member (asms_set, c); + (* Small utility: the tactic to prove the premise *) + val prove_premise = + (* We might need to unfold the bound definitions, in particular if the + term is a constant (e.g., “3:int”) *) + FULL_SIMP_TAC simpLib.empty_ss all_integer_bounds >> + COOPER_TAC; + (* Rewrite with a lemma, then assume it *) + fun rewrite_then_assum (thm : thm) : tactic = + FULL_SIMP_TAC simpLib.empty_ss [thm] >> assume_tac thm; + in + (* If the conclusion is not already in the assumptions, prove it, use + it to rewrite the goal and add it in the assumptions, otherwise do nothing *) + if already_in_asms then ALL_TAC + else prove_premise_then prove_premise rewrite_then_assum lemma + end + +(* Look for conversions from integers to machine integers and back. + {[ + u32_to_int (int_to_u32 x) + ]} + + Attempts to prove and apply equalities of the form: + {[ + u32_to_int (int_to_u32 x) = x + ]} + + **REMARK**: this function can fail, if it doesn't manage to prove the + premises of the theorem to apply. + + TODO: update + *) +val rewrite_with_dep_int_lemmas : tactic = + (* We're not trying to be smart: we just try to rewrite with each theorem at + a time *) + let + val prove_premise = FULL_SIMP_TAC simpLib.empty_ss all_integer_bounds >> COOPER_TAC; + val then_tac1 = (fn th => FULL_SIMP_TAC simpLib.empty_ss [th]); + val rewr_tac1 = apply_dep_rewrites_match_concl_tac prove_premise then_tac1; + val then_tac2 = (fn th => FULL_SIMP_TAC simpLib.empty_ss [th]); + val rewr_tac2 = apply_dep_rewrites_match_first_premise_tac prove_premise then_tac2; + in + MAP_EVERY rewr_tac1 integer_conversion_lemmas_list >> + MAP_EVERY rewr_tac2 [NUM_SUB_1_EQ] + end + +(* +apply_dep_rewrites_match_first_premise_tac prove_premise then_tac NUM_SUB_1_EQ + +sg ‘u32_to_int z = u32_to_int i − 1 /\ 0 ≤ u32_to_int z’ >- prove_premise + +prove_premise_then prove_premise + +val thm = thm_to_conj_implies (SPECL [“u32_to_int z”, “u32_to_int i”] NUM_SUB_1_EQ) + +val h = “u32_to_int z = u32_to_int i − 1 ∧ 0 ≤ u32_to_int z” +*) + +(* Massage a bit the goal, for instance by introducing integer bounds in the + assumptions. +*) +val massage : tactic = + assume_bounds_for_all_int_vars >> + rewrite_with_dep_int_lemmas + +(* Lexicographic order over pairs *) +fun pair_compare (comp1 : 'a * 'a -> order) (comp2 : 'b * 'b -> order) + ((p1, p2) : (('a * 'b) * ('a * 'b))) : order = + let + val (x1, y1) = p1; + val (x2, y2) = p2; + in + case comp1 (x1, x2) of + LESS => LESS + | GREATER => GREATER + | EQUAL => comp2 (y1, y2) + end + +(* A constant name (theory, constant name) *) +type const_name = string * string + +val const_name_compare = pair_compare String.compare String.compare + +(* The registered spec theorems, that {!progress} will automatically apply. + + The keys are the function names (it is a pair, because constant names + are made of the theory name and the name of the constant itself). + + Also note that we can store several specs per definition (in practice, when + looking up specs, we will try them all one by one, in a LIFO order). + + We store theorems where all the premises are in the goal, with implications + (i.e.: [⊢ H0 ==> ... ==> Hn ==> H], not [H0, ..., Hn ⊢ H]). + + We do this because, when doing proofs by induction, {!progress} might have to + handle *unregistered* theorems coming the current goal assumptions and of the shape + (the conclusion of the theorem is an assumption, and we want to ignore this assumption): + {[ + [∀i. u32_to_int i < &LENGTH (list_t_v ls) ⇒ + case nth ls i of + Return x => ... + | ... => ...] + ⊢ ∀i. u32_to_int i < &LENGTH (list_t_v ls) ⇒ + case nth ls i of + Return x => ... + | ... => ... + ]} + *) +val reg_spec_thms: (const_name, thm) Redblackmap.dict ref = + ref (Redblackmap.mkDict const_name_compare) + +(* Retrieve the specified application in a spec theorem. + + A spec theorem for a function [f] typically has the shape: + {[ + !x0 ... xn. + H0 ==> ... Hm ==> + (exists ... + (exists ... . f y0 ... yp = ... /\ ...) \/ + (exists ... . f y0 ... yp = ... /\ ...) \/ + ... + ]} + + Or: + {[ + !x0 ... xn. + H0 ==> ... Hm ==> + case f y0 ... yp of + ... => ... + | ... => ... + ]} + + We return: [f y0 ... yp] +*) +fun get_spec_app (t : term) : term = + let + (* Remove the universally quantified variables, the premises and + the existentially quantified variables *) + val t = (snd o strip_exists o snd o strip_imp o snd o strip_forall) t; + (* Remove the exists, take the first disjunct *) + val t = (hd o strip_disj o snd o strip_exists) t; + (* Split the conjunctions and take the first conjunct *) + val t = (hd o strip_conj) t; + (* Remove the case if there is, otherwise destruct the equality *) + val t = + if TypeBase.is_case t then let val (_, t, _) = TypeBase.dest_case t in t end + else (fst o dest_eq) t; + in t end + +(* Given a function call [f y0 ... yn] return the name of the function *) +fun get_fun_name_from_app (t : term) : const_name = + let + val f = (fst o strip_comb) t; + val {Name=name, Thy=thy, Ty=_} = dest_thy_const f; + val cn = (thy, name); + in cn end + +(* Register a spec theorem in the spec database. + + For the shape of spec theorems, see {!get_spec_thm_app}. + *) +fun register_spec_thm (th: thm) : unit = + let + (* Transform the theroem a bit before storing it *) + val th = SPEC_ALL th; + (* Retrieve the app ([f x0 ... xn]) *) + val f = get_spec_app (concl th); + (* Retrieve the function name *) + val cn = get_fun_name_from_app f; + in + (* Store *) + reg_spec_thms := Redblackmap.insert (!reg_spec_thms, cn, th) + end + +(* TODO: I32_SUB_EQ *) +val _ = app register_spec_thm [U32_ADD_EQ, U32_SUB_EQ, I32_ADD_EQ] + +(* +app register_spec_thm [U32_ADD_EQ, U32_SUB_EQ, I32_ADD_EQ] +Redblackmap.listItems (!reg_spec_thms) +*) + +(* +(* TODO: remove? *) +datatype monadic_app_kind = + Call | Bind | Case +*) + +(* Repeatedly destruct cases and return the last scrutinee we get *) +fun strip_all_cases_get_scrutinee (t : term) : term = + if TypeBase.is_case t + then (strip_all_cases_get_scrutinee o fst o TypeBase.strip_case) t + else t + +(* +TypeBase.dest_case “case ls of [] => T | _ => F” +TypeBase.strip_case “case ls of [] => T | _ => F” +TypeBase.strip_case “case (if b then [] else [0, 1]) of [] => T | _ => F” +TypeBase.strip_case “3” +TypeBase.dest_case “3” + +strip_all_cases_get_scrutinee “case ls of [] => T | _ => F” +strip_all_cases_get_scrutinee “case (if b then [] else [0, 1]) of [] => T | _ => F” +strip_all_cases_get_scrutinee “3” +*) + + +(* Provided the goal contains a call to a monadic function, return this function call. + + The goal should be of the shape: + 1. + {[ + case (* potentially expanded function body *) of + ... => ... + | ... => ... + ]} + + 2. Or: + {[ + exists ... . + ... (* potentially expanded function body *) = Return ... /\ + ... (* Various properties *) + ]} + + 3. Or a disjunction of cases like the one above, below existential binders + (actually: note sure this last case exists in practice): + {[ + exists ... . + (exists ... . (* body *) = Return ... /\ ...) \/ + ... + ]} + + The function body should be of the shape: + {[ + x <- f y0 ... yn; + ... + ]} + + Or (typically if we expanded the monadic binds): + {[ + case f y0 ... yn of + ... + ]} + + Or simply (typically if we reached the end of the function we're analyzing): + {[ + f y0 ... yn + ]} + + For all the above cases we would return [f y0 ... yn]. + *) +fun get_monadic_app_call (t : term) : term = + (* We do something slightly imprecise but hopefully general and robut *) + let + (* Case 3.: strip the existential binders, and take the first disjuntion *) + val t = (hd o strip_disj o snd o strip_exists) t; + (* Case 2.: strip the existential binders, and take the first conjunction *) + val t = (hd o strip_conj o snd o strip_exists) t; + (* If it is an equality, take the lhs *) + val t = if is_eq t then lhs t else t; + (* Expand the binders to transform them to cases *) + val t = + (rhs o concl) (REWRITE_CONV [st_ex_bind_def] t) + handle UNCHANGED => t; + (* Strip all the cases *) + val t = strip_all_cases_get_scrutinee t; + in t end + +(* Use the given theorem to progress by one step (we use this when + analyzing a function body: this goes forward by one call to a monadic function). + + We transform the goal by: + - pushing the theorem premises to a subgoal + - adding the theorem conclusion in the assumptions in another goal, and + getting rid of the monadic call + + Then [then_tac] receives as paramter the monadic call on which we applied + the lemma. This can be useful, for instance, to make a case disjunction. + + This function is the most primitive of the [progress...] functions. + *) +fun pure_progress_with (premise_tac : tactic) + (then_tac : term -> thm_tactic) (th : thm) : tactic = + fn (asms,g) => + let + (* Remove all the universally quantified variables from the theorem *) + val th = SPEC_ALL th; + (* Retrieve the monadic call from the goal *) + val fgoal = get_monadic_app_call g; + (* Retrieve the app call from the theroem *) + val gth = get_spec_app (concl th); + (* Match and instantiate *) + val (var_s, ty_s) = match_term gth fgoal; + (* Instantiate the theorem *) + val th = INST var_s (INST_TYPE ty_s th); + (* Retrieve the premises of the theorem *) + val th = PURE_REWRITE_RULE [GSYM satTheory.AND_IMP] th; + in + (* Apply the theorem *) + intro_premise_then premise_tac (then_tac fgoal) th (asms, g) + end + +(* +val (asms, g) = top_goal () +val t = g + +val th = U32_SUB_EQ + +val premise_tac = massage >> TRY COOPER_TAC +fun then_tac fgoal = + fn thm => ASSUME_TAC thm >> Cases_on ‘^fgoal’ >> + rw [] >> fs [st_ex_bind_def] >> massage >> fs [] + +pure_progress_with premise_tac then_tac th +*) + +fun progress_with (th : thm) : tactic = + let + val premise_tac = massage >> fs [] >> rw [] >> TRY COOPER_TAC; + fun then_tac fgoal thm = + ASSUME_TAC thm >> Cases_on ‘^fgoal’ >> + rw [] >> fs [st_ex_bind_def] >> massage >> fs []; + in + pure_progress_with premise_tac then_tac th + end + +(* +progress_with U32_SUB_EQ +*) + +(* This function lookups the theorem to use to make progress *) +val progress : tactic = + fn (asms, g) => + let + (* Retrieve the monadic call from the goal *) + val fgoal = get_monadic_app_call g; + val fname = get_fun_name_from_app fgoal; + (* Lookup the theorem: first look in the assumptions (we might want to + use the inductive hypothesis for instance) *) + fun asm_to_spec asm = + let + (* Fail if there are no universal quantifiers *) + val _ = + if is_forall asm then asm + else assert is_forall ((snd o strip_imp) asm); + val asm_fname = (get_fun_name_from_app o get_spec_app) asm; + (* Fail if the name is not the one we're looking for *) + val _ = assert (fn n => fname = n) asm_fname; + in + ASSUME asm + end + val asms_thl = mapfilter asm_to_spec asms; + (* Lookup a spec in the database *) + val thl = + case Redblackmap.peek (!reg_spec_thms, fname) of + NONE => asms_thl + | SOME spec => spec :: asms_thl; + val _ = + if null thl then + raise (failwith "progress: could not find a suitable theorem to apply") + else (); + in + (* Attempt to use the theorems one by one *) + MAP_FIRST progress_with thl (asms, g) + end + +(* +val (asms, g) = top_goal () +*) + +(* TODO: no exfalso tactic?? *) +val EX_FALSO : tactic = + SUBGOAL_THEN “F” (fn th => ASSUME_TAC th >> fs[]) + +Theorem nth_lem: + !(ls : 't list_t) (i : u32). + u32_to_int i < int_of_num (LENGTH (list_t_v ls)) ==> + case nth ls i of + | Return x => x = EL (Num (u32_to_int i)) (list_t_v ls) + | Fail _ => F + | Loop => F +Proof + Induct_on ‘ls’ >> rw [list_t_v_def] >~ [‘ListNil’] + >-(massage >> EX_FALSO >> COOPER_TAC) >> + PURE_ONCE_REWRITE_TAC [nth_def] >> rw [] >> + progress >> progress +QED + +(* Example from the hashmap *) +val _ = new_constant ("insert", “: u32 -> 't -> (u32 # 't) list_t -> (u32 # 't) list_t result”) +val insert_def = new_axiom ("insert_def", “ + insert (key : u32) (value : 't) (ls : (u32 # 't) list_t) : (u32 # 't) list_t result = + case ls of + | ListCons (ckey, cvalue) tl => + if ckey = key + then Return (ListCons (ckey, value) tl) + else + do + tl0 <- insert key value tl; + Return (ListCons (ckey, cvalue) tl0) + od + | ListNil => Return (ListCons (key, value) ListNil) + ”) + +(* Property that keys are pairwise distinct *) +val distinct_keys_def = Define ‘ + distinct_keys (ls : (u32 # 't) list) = + !i j. + i < LENGTH ls ==> + j < LENGTH ls ==> + FST (EL i ls) = FST (EL j ls) ==> + i = j +’ + +val lookup_raw_def = Define ‘ + lookup_raw key [] = NONE /\ + lookup_raw key ((k, v) :: ls) = + if k = key then SOME v else lookup_raw key ls +’ + +val lookup_def = Define ‘ + lookup key ls = lookup_raw key (list_t_v ls) +’ + +Theorem insert_lem: + !ls key value. + (* The keys are pairwise distinct *) + distinct_keys (list_t_v ls) ==> + case insert key value ls of + | Return ls1 => + (* We updated the binding *) + lookup key ls1 = SOME value /\ + (* The other bindings are left unchanged *) + (!k. k <> key ==> lookup k ls = lookup k ls1) + | Fail _ => F + | Loop => F +Proof + Induct_on ‘ls’ >> rw [list_t_v_def] >~ [‘ListNil’] >> + PURE_ONCE_REWRITE_TAC [insert_def] >> rw [] + >- (rw [lookup_def, lookup_raw_def, list_t_v_def]) + >- (rw [lookup_def, lookup_raw_def, list_t_v_def]) >> + CASE_TAC >> rw [] + >- (rw [lookup_def, lookup_raw_def, list_t_v_def]) + >- (rw [lookup_def, lookup_raw_def, list_t_v_def]) >> + progress + >- ( + fs [distinct_keys_def] >> + rpt strip_tac >> + first_assum (qspecl_then [‘SUC i’, ‘SUC j’] ASSUME_TAC) >> + fs [] + (* Alternative: *) + (* + PURE_ONCE_REWRITE_TAC [GSYM prim_recTheory.INV_SUC_EQ] >> + first_assum irule >> fs [] + *)) >> + fs [lookup_def, lookup_raw_def, list_t_v_def] +QED + +(*** + * Example of how to get rid of the fuel in practice + *) +val nth_fuel_def = Define ‘ + nth_fuel (n : num) (ls : 't list_t) (i : u32) : 't result = + case n of + | 0 => Loop + | SUC n => + do case ls of + | ListCons x tl => + if u32_to_int i = (0:int) + then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + nth_fuel n tl i0 + od + | ListNil => + Fail Failure + od + ’ + +val is_loop_def = Define ‘is_loop r = case r of Loop => T | _ => F’ + +val nth_fuel_P_def = Define ‘ + nth_fuel_P ls i n = ~is_loop (nth_fuel n ls i) +’ + +Theorem nth_fuel_mono: + !n m ls i. + n <= m ==> + if is_loop (nth_fuel n ls i) then T + else nth_fuel n ls i = nth_fuel m ls i +Proof + Induct_on ‘n’ >- ( + rpt gen_tac >> + DISCH_TAC >> + PURE_ONCE_REWRITE_TAC [nth_fuel_def] >> + rw[is_loop_def] + ) >> + (* Interesting case *) + rpt gen_tac >> + DISCH_TAC >> + CASE_TAC >> + Cases_on ‘m’ >- ( + (* Contradiction: SUC n < 0 *) + sg ‘SUC n = 0’ >- decide_tac >> + fs [is_loop_def] + ) >> + fs [is_loop_def] >> + pop_assum mp_tac >> + PURE_ONCE_REWRITE_TAC [nth_fuel_def] >> + fs [] >> + DISCH_TAC >> + (* We just have to explore all the paths: we can have dedicated tactics for that + (we need to do case analysis) *) + Cases_on ‘ls’ >> fs [] >> + Cases_on ‘u32_to_int (i :u32) = (0 :int)’ >> fs [] >> + fs [st_ex_bind_def] >> + Cases_on ‘u32_sub (i :u32) (int_to_u32 (1 :int))’ >> fs [] >> + (* Apply the induction hypothesis *) + first_x_assum (qspecl_then [‘n'’, ‘l’, ‘a’] assume_tac) >> + first_x_assum imp_res_tac >> + pop_assum mp_tac >> + CASE_TAC +QED + +Theorem nth_fuel_P_mono: + !n m ls i. + n <= m ==> + nth_fuel_P ls i n ==> + nth_fuel n ls i = nth_fuel m ls i +Proof + rpt gen_tac >> rpt DISCH_TAC >> + fs [nth_fuel_P_def] >> + imp_res_tac nth_fuel_mono >> + pop_assum (qspecl_then [‘ls’, ‘i’] assume_tac) >> + pop_assum mp_tac >> CASE_TAC >> fs [] +QED + +Theorem nth_fuel_least_fail_mono: + !n ls i. + n < $LEAST (nth_fuel_P ls i) ==> + nth_fuel n ls i = Loop +Proof + rpt gen_tac >> + disch_tac >> + imp_res_tac whileTheory.LESS_LEAST >> + fs [nth_fuel_P_def, is_loop_def] >> + pop_assum mp_tac >> + CASE_TAC +QED + +Theorem nth_fuel_least_success_mono: + !n ls i. + $LEAST (nth_fuel_P ls i) <= n ==> + nth_fuel n ls i = nth_fuel ($LEAST (nth_fuel_P ls i)) ls i +Proof + rpt gen_tac >> + disch_tac >> + (* Case disjunction on whether there exists a fuel such that it terminates *) + Cases_on ‘?m. nth_fuel_P ls i m’ >- ( + (* Terminates *) + irule EQ_SYM >> + irule nth_fuel_P_mono >> fs [] >> + (* Prove that calling with the least upper bound of fuel succeeds *) + qspec_then ‘nth_fuel_P (ls :α list_t) (i :u32)’ imp_res_tac whileTheory.LEAST_EXISTS_IMP + ) >> + (* Doesn't terminate *) + fs [] >> + sg ‘~(nth_fuel_P ls i n)’ >- fs [] >> + sg ‘~(nth_fuel_P ls i ($LEAST (nth_fuel_P ls i)))’ >- fs [] >> + fs [nth_fuel_P_def, is_loop_def] >> + pop_assum mp_tac >> CASE_TAC >> + pop_assum mp_tac >> + pop_assum mp_tac >> CASE_TAC +QED + +val nth_def_raw = Define ‘ + nth ls i = + if (?n. nth_fuel_P ls i n) then nth_fuel ($LEAST (nth_fuel_P ls i)) ls i + else Loop +’ + +(* This makes the proofs easier, in that it helps us control the context *) +val nth_expand_def = Define ‘ + nth_expand nth ls i = + case ls of + | ListCons x tl => + if u32_to_int i = (0:int) + then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + nth tl i0 + od + | ListNil => + Fail Failure +’ + +(* Prove the important theorems *) +Theorem nth_def_terminates: + !ls i. + (?n. nth_fuel_P ls i n) ==> + nth ls i = + nth_expand nth ls i +Proof + rpt strip_tac >> + fs [nth_expand_def] >> + PURE_ONCE_REWRITE_TAC [nth_def_raw] >> + (* Prove that the least upper bound is <= n *) + sg ‘$LEAST (nth_fuel_P ls i) <= n’ >-( + qspec_then ‘nth_fuel_P (ls :α list_t) (i :u32)’ imp_res_tac whileTheory.LEAST_EXISTS_IMP >> + spose_not_then assume_tac >> fs [] + ) >> + (* Use the monotonicity theorem - TODO: ? *) + imp_res_tac nth_fuel_least_success_mono >> + (* Rewrite only on the left - TODO: easy way ?? *) + qspecl_then [‘$LEAST (nth_fuel_P ls i)’, ‘ls’, ‘i’] assume_tac nth_fuel_def >> + (* TODO: how to discard assumptions?? *) + fs [] >> pop_assum (fn _ => fs []) >> + (* Cases on the least upper bound *) + Cases_on ‘$LEAST (nth_fuel_P ls i)’ >> rw [] >- ( + (* The bound is equal to 0: contradiction *) + sg ‘nth_fuel 0 ls i = Loop’ >- (PURE_ONCE_REWRITE_TAC [nth_fuel_def] >> rw []) >> + fs [nth_fuel_P_def, is_loop_def] + ) >> + (* Bound not equal to 0 *) + fs [nth_fuel_P_def, is_loop_def] >> + (* Explore all the paths *) + fs [st_ex_bind_def] >> + Cases_on ‘ls’ >> rw [] >> fs [] >> + Cases_on ‘u32_sub i (int_to_u32 1)’ >> rw [] >> fs [] >> + (* Recursive call: use monotonicity - we have an assumption which eliminates the Loop case *) + Cases_on ‘nth_fuel n' l a’ >> rw [] >> fs [] >> + (sg ‘nth_fuel_P l a n'’ >- fs [nth_fuel_P_def, is_loop_def]) >> + (sg ‘$LEAST (nth_fuel_P l a) <= n'’ >-( + qspec_then ‘nth_fuel_P l a’ imp_res_tac whileTheory.LEAST_EXISTS_IMP >> + spose_not_then assume_tac >> fs [])) >> + imp_res_tac nth_fuel_least_success_mono >> fs [] +QED + +(* Prove the important theorems *) +Theorem nth_def_loop: + !ls i. + (!n. ~nth_fuel_P ls i n) ==> + nth ls i = + nth_expand nth ls i +Proof + rpt gen_tac >> + PURE_ONCE_REWRITE_TAC [nth_def_raw] >> + strip_tac >> rw[] >> + (* Non-terminating case *) + sg ‘∀n. ¬nth_fuel_P ls i (SUC n)’ >- rw [] >> + fs [nth_fuel_P_def, is_loop_def] >> + pop_assum mp_tac >> + PURE_ONCE_REWRITE_TAC [nth_fuel_def] >> + rw [] >> + fs [nth_expand_def] >> + (* Evaluate all the paths *) + fs [st_ex_bind_def] >> + Cases_on ‘ls’ >> rw [] >> fs [] >> + Cases_on ‘u32_sub i (int_to_u32 1)’ >> rw [] >> fs [] >> + (* Use the definition of nth *) + rw [nth_def_raw] >> + first_x_assum (qspec_then ‘$LEAST (nth_fuel_P l a)’ assume_tac) >> + Cases_on ‘nth_fuel ($LEAST (nth_fuel_P l a)) l a’ >> fs [] +QED + +(* The final theorem *) +Theorem nth_def: + !ls i. + nth ls i = + case ls of + | ListCons x tl => + if u32_to_int i = (0:int) + then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + nth tl i0 + od + | ListNil => + Fail Failure +Proof + rpt strip_tac >> + Cases_on ‘?n. nth_fuel_P ls i n’ >-( + assume_tac nth_def_terminates >> + fs [nth_expand_def] >> + pop_assum irule >> + metis_tac []) >> + fs [] >> imp_res_tac nth_def_loop >> fs [nth_expand_def] +QED + +(* + +Je viens de finir ma petite expérimentation avec le fuel : ça marche bien. Par exemple, si je pose les définitions suivantes : +Datatype: + result = Return 'a | Fail error | Loop +End + +(* Omitting some definitions like the bind *) + +val _ = Define ‘ + nth_fuel (n : num) (ls : 't list_t) (i : u32) : 't result = + case n of + | 0 => Loop + | SUC n => + do case ls of + | ListCons x tl => + if u32_to_int i = (0:int) + then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + nth_fuel n tl i0 + od + | ListNil => + Fail Failure + od + ’ + +val _ = Define 'is_loop r = case r of Loop => T | _ => F' + +val _ = Define 'nth_fuel_P ls i n = ~is_loop (nth_fuel n ls i)' + +(* $LEAST returns the least upper bound for a predicate (if it exists - otherwise it returns an arbitrary number) *) +val _ = Define ‘ + nth ls i = + if (?n. nth_fuel_P ls i n) then nth_fuel ($LEAST (nth_fuel_P ls i)) ls i + else Loop +’ +J'arrive à montrer (c'est un chouïa technique) : +Theorem nth_def: + !ls i. + nth ls i = + case ls of + | ListCons x tl => + if u32_to_int i = (0:int) + then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + nth tl i0 + od + | ListNil => + Fail Failure + +*) + +val _ = export_theory () diff --git a/backends/hol4/TestTheory.sig b/backends/hol4/TestTheory.sig new file mode 100644 index 00000000..552662b8 --- /dev/null +++ b/backends/hol4/TestTheory.sig @@ -0,0 +1,839 @@ +signature TestTheory = +sig + type thm = Thm.thm + + (* Axioms *) + val VEC_TO_LIST_BOUNDS : thm + val i32_to_int_bounds : thm + val insert_def : thm + val int_to_i32_id : thm + val int_to_u32_id : thm + val u32_to_int_bounds : thm + + (* Definitions *) + val distinct_keys_def : thm + val error_BIJ : thm + val error_CASE : thm + val error_TY_DEF : thm + val error_size_def : thm + val i32_add_def : thm + val i32_max_def : thm + val i32_min_def : thm + val int1_def : thm + val int2_def : thm + val is_loop_def : thm + val is_true_def : thm + val list_t_TY_DEF : thm + val list_t_case_def : thm + val list_t_size_def : thm + val list_t_v_def : thm + val lookup_def : thm + val mk_i32_def : thm + val mk_u32_def : thm + val nth_expand_def : thm + val nth_fuel_P_def : thm + val result_TY_DEF : thm + val result_case_def : thm + val result_size_def : thm + val st_ex_bind_def : thm + val st_ex_return_def : thm + val test1_def : thm + val test2_TY_DEF : thm + val test2_case_def : thm + val test2_size_def : thm + val test_TY_DEF : thm + val test_case_def : thm + val test_monad2_def : thm + val test_monad3_def : thm + val test_monad_def : thm + val test_size_def : thm + val u32_add_def : thm + val u32_max_def : thm + val u32_sub_def : thm + val usize_max_def : thm + val vec_len_def : thm + + (* Theorems *) + val I32_ADD_EQ : thm + val INT_OF_NUM_INJ : thm + val INT_THM1 : thm + val INT_THM2 : thm + val MK_I32_SUCCESS : thm + val MK_U32_SUCCESS : thm + val NAT_THM1 : thm + val NAT_THM2 : thm + val NUM_SUB_1_EQ : thm + val NUM_SUB_1_EQ1 : thm + val NUM_SUB_EQ : thm + val U32_ADD_EQ : thm + val U32_SUB_EQ : thm + val VEC_TO_LIST_INT_BOUNDS : thm + val datatype_error : thm + val datatype_list_t : thm + val datatype_result : thm + val datatype_test : thm + val datatype_test2 : thm + val error2num_11 : thm + val error2num_ONTO : thm + val error2num_num2error : thm + val error2num_thm : thm + val error_Axiom : thm + val error_EQ_error : thm + val error_case_cong : thm + val error_case_def : thm + val error_case_eq : thm + val error_induction : thm + val error_nchotomy : thm + val insert_lem : thm + val list_nth_mut_loop_loop_fwd_def : thm + val list_nth_mut_loop_loop_fwd_ind : thm + val list_t_11 : thm + val list_t_Axiom : thm + val list_t_case_cong : thm + val list_t_case_eq : thm + val list_t_distinct : thm + val list_t_induction : thm + val list_t_nchotomy : thm + val lookup_raw_def : thm + val lookup_raw_ind : thm + val nth_def : thm + val nth_def_loop : thm + val nth_def_terminates : thm + val nth_fuel_P_mono : thm + val nth_fuel_def : thm + val nth_fuel_ind : thm + val nth_fuel_least_fail_mono : thm + val nth_fuel_least_success_mono : thm + val nth_fuel_mono : thm + val num2error_11 : thm + val num2error_ONTO : thm + val num2error_error2num : thm + val num2error_thm : thm + val result_11 : thm + val result_Axiom : thm + val result_case_cong : thm + val result_case_eq : thm + val result_distinct : thm + val result_induction : thm + val result_nchotomy : thm + val test2_11 : thm + val test2_Axiom : thm + val test2_case_cong : thm + val test2_case_eq : thm + val test2_distinct : thm + val test2_induction : thm + val test2_nchotomy : thm + val test_11 : thm + val test_Axiom : thm + val test_case_cong : thm + val test_case_eq : thm + val test_distinct : thm + val test_induction : thm + val test_nchotomy : thm + + val Test_grammars : type_grammar.grammar * term_grammar.grammar +(* + [Omega] Parent theory of "Test" + + [int_arith] Parent theory of "Test" + + [words] Parent theory of "Test" + + [insert_def] Axiom + + [oracles: ] [axioms: insert_def] [] + ⊢ insert key value ls = + case ls of + ListCons (ckey,cvalue) tl => + if ckey = key then Return (ListCons (ckey,value) tl) + else + do + tl0 <- insert key value tl; + Return (ListCons (ckey,cvalue) tl0) + od + | ListNil => Return (ListCons (key,value) ListNil) + + [u32_to_int_bounds] Axiom + + [oracles: ] [axioms: u32_to_int_bounds] [] + ⊢ ∀n. 0 ≤ u32_to_int n ∧ u32_to_int n ≤ u32_max + + [i32_to_int_bounds] Axiom + + [oracles: ] [axioms: i32_to_int_bounds] [] + ⊢ ∀n. i32_min ≤ i32_to_int n ∧ i32_to_int n ≤ i32_max + + [int_to_u32_id] Axiom + + [oracles: ] [axioms: int_to_u32_id] [] + ⊢ ∀n. 0 ≤ n ∧ n ≤ u32_max ⇒ u32_to_int (int_to_u32 n) = n + + [int_to_i32_id] Axiom + + [oracles: ] [axioms: int_to_i32_id] [] + ⊢ ∀n. i32_min ≤ n ∧ n ≤ i32_max ⇒ i32_to_int (int_to_i32 n) = n + + [VEC_TO_LIST_BOUNDS] Axiom + + [oracles: ] [axioms: VEC_TO_LIST_BOUNDS] [] + ⊢ ∀v. (let l = LENGTH (vec_to_list v) in 0 ≤ l ∧ l ≤ 4294967295) + + [distinct_keys_def] Definition + + ⊢ ∀ls. + distinct_keys ls ⇔ + ∀i j. + i < LENGTH ls ⇒ + j < LENGTH ls ⇒ + FST (EL i ls) = FST (EL j ls) ⇒ + i = j + + [error_BIJ] Definition + + ⊢ (∀a. num2error (error2num a) = a) ∧ + ∀r. (λn. n < 1) r ⇔ error2num (num2error r) = r + + [error_CASE] Definition + + ⊢ ∀x v0. (case x of Failure => v0) = (λm. v0) (error2num x) + + [error_TY_DEF] Definition + + ⊢ ∃rep. TYPE_DEFINITION (λn. n < 1) rep + + [error_size_def] Definition + + ⊢ ∀x. error_size x = 0 + + [i32_add_def] Definition + + ⊢ ∀x y. i32_add x y = mk_i32 (i32_to_int x + i32_to_int y) + + [i32_max_def] Definition + + ⊢ i32_max = 2147483647 + + [i32_min_def] Definition + + ⊢ i32_min = -2147483648 + + [int1_def] Definition + + ⊢ int1 = 32 + + [int2_def] Definition + + ⊢ int2 = -32 + + [is_loop_def] Definition + + ⊢ ∀r. is_loop r ⇔ case r of Return v2 => F | Fail v3 => F | Loop => T + + [is_true_def] Definition + + ⊢ ∀x. is_true x = if x then Return () else Fail Failure + + [list_t_TY_DEF] Definition + + ⊢ ∃rep. + TYPE_DEFINITION + (λa0'. + ∀ $var$('list_t'). + (∀a0'. + (∃a0 a1. + a0' = + (λa0 a1. + ind_type$CONSTR 0 a0 + (ind_type$FCONS a1 (λn. ind_type$BOTTOM))) + a0 a1 ∧ $var$('list_t') a1) ∨ + a0' = + ind_type$CONSTR (SUC 0) ARB (λn. ind_type$BOTTOM) ⇒ + $var$('list_t') a0') ⇒ + $var$('list_t') a0') rep + + [list_t_case_def] Definition + + ⊢ (∀a0 a1 f v. list_t_CASE (ListCons a0 a1) f v = f a0 a1) ∧ + ∀f v. list_t_CASE ListNil f v = v + + [list_t_size_def] Definition + + ⊢ (∀f a0 a1. + list_t_size f (ListCons a0 a1) = 1 + (f a0 + list_t_size f a1)) ∧ + ∀f. list_t_size f ListNil = 0 + + [list_t_v_def] Definition + + ⊢ list_t_v ListNil = [] ∧ + ∀x tl. list_t_v (ListCons x tl) = x::list_t_v tl + + [lookup_def] Definition + + ⊢ ∀key ls. lookup key ls = lookup_raw key (list_t_v ls) + + [mk_i32_def] Definition + + ⊢ ∀n. mk_i32 n = + if i32_min ≤ n ∧ n ≤ i32_max then Return (int_to_i32 n) + else Fail Failure + + [mk_u32_def] Definition + + ⊢ ∀n. mk_u32 n = + if 0 ≤ n ∧ n ≤ u32_max then Return (int_to_u32 n) + else Fail Failure + + [nth_expand_def] Definition + + ⊢ ∀nth ls i. + nth_expand nth ls i = + case ls of + ListCons x tl => + if u32_to_int i = 0 then Return x + else do i0 <- u32_sub i (int_to_u32 1); nth tl i0 od + | ListNil => Fail Failure + + [nth_fuel_P_def] Definition + + ⊢ ∀ls i n. nth_fuel_P ls i n ⇔ ¬is_loop (nth_fuel n ls i) + + [result_TY_DEF] Definition + + ⊢ ∃rep. + TYPE_DEFINITION + (λa0. + ∀ $var$('result'). + (∀a0. + (∃a. a0 = + (λa. + ind_type$CONSTR 0 (a,ARB) + (λn. ind_type$BOTTOM)) a) ∨ + (∃a. a0 = + (λa. + ind_type$CONSTR (SUC 0) (ARB,a) + (λn. ind_type$BOTTOM)) a) ∨ + a0 = + ind_type$CONSTR (SUC (SUC 0)) (ARB,ARB) + (λn. ind_type$BOTTOM) ⇒ + $var$('result') a0) ⇒ + $var$('result') a0) rep + + [result_case_def] Definition + + ⊢ (∀a f f1 v. result_CASE (Return a) f f1 v = f a) ∧ + (∀a f f1 v. result_CASE (Fail a) f f1 v = f1 a) ∧ + ∀f f1 v. result_CASE Loop f f1 v = v + + [result_size_def] Definition + + ⊢ (∀f a. result_size f (Return a) = 1 + f a) ∧ + (∀f a. result_size f (Fail a) = 1 + error_size a) ∧ + ∀f. result_size f Loop = 0 + + [st_ex_bind_def] Definition + + ⊢ ∀x f. + monad_bind x f = + case x of Return y => f y | Fail e => Fail e | Loop => Loop + + [st_ex_return_def] Definition + + ⊢ ∀x. st_ex_return x = Return x + + [test1_def] Definition + + ⊢ ∀x. test1 x = Return x + + [test2_TY_DEF] Definition + + ⊢ ∃rep. + TYPE_DEFINITION + (λa0. + ∀ $var$('test2'). + (∀a0. + (∃a. a0 = + (λa. + ind_type$CONSTR 0 (a,ARB) + (λn. ind_type$BOTTOM)) a) ∨ + (∃a. a0 = + (λa. + ind_type$CONSTR (SUC 0) (ARB,a) + (λn. ind_type$BOTTOM)) a) ⇒ + $var$('test2') a0) ⇒ + $var$('test2') a0) rep + + [test2_case_def] Definition + + ⊢ (∀a f f1. test2_CASE (Variant1_2 a) f f1 = f a) ∧ + ∀a f f1. test2_CASE (Variant2_2 a) f f1 = f1 a + + [test2_size_def] Definition + + ⊢ (∀f f1 a. test2_size f f1 (Variant1_2 a) = 1 + f a) ∧ + ∀f f1 a. test2_size f f1 (Variant2_2 a) = 1 + f1 a + + [test_TY_DEF] Definition + + ⊢ ∃rep. + TYPE_DEFINITION + (λa0. + ∀ $var$('test'). + (∀a0. + (∃a. a0 = + (λa. + ind_type$CONSTR 0 (a,ARB) + (λn. ind_type$BOTTOM)) a) ∨ + (∃a. a0 = + (λa. + ind_type$CONSTR (SUC 0) (ARB,a) + (λn. ind_type$BOTTOM)) a) ⇒ + $var$('test') a0) ⇒ + $var$('test') a0) rep + + [test_case_def] Definition + + ⊢ (∀a f f1. test_CASE (Variant1 a) f f1 = f a) ∧ + ∀a f f1. test_CASE (Variant2 a) f f1 = f1 a + + [test_monad2_def] Definition + + ⊢ test_monad2 = do x <- Return T; Return x od + + [test_monad3_def] Definition + + ⊢ ∀x. test_monad3 x = monad_ignore_bind (is_true x) (Return x) + + [test_monad_def] Definition + + ⊢ ∀v. test_monad v = do x <- Return v; Return x od + + [test_size_def] Definition + + ⊢ (∀f f1 a. test_size f f1 (Variant1 a) = 1 + f1 a) ∧ + ∀f f1 a. test_size f f1 (Variant2 a) = 1 + f a + + [u32_add_def] Definition + + ⊢ ∀x y. u32_add x y = mk_u32 (u32_to_int x + u32_to_int y) + + [u32_max_def] Definition + + ⊢ u32_max = 4294967295 + + [u32_sub_def] Definition + + ⊢ ∀x y. u32_sub x y = mk_u32 (u32_to_int x − u32_to_int y) + + [usize_max_def] Definition + + ⊢ usize_max = 4294967295 + + [vec_len_def] Definition + + ⊢ ∀v. vec_len v = int_to_u32 (&LENGTH (vec_to_list v)) + + [I32_ADD_EQ] Theorem + + [oracles: DISK_THM] [axioms: int_to_i32_id] [] + ⊢ ∀x y. + i32_min ≤ i32_to_int x + i32_to_int y ⇒ + i32_to_int x + i32_to_int y ≤ i32_max ⇒ + ∃z. i32_add x y = Return z ∧ + i32_to_int z = i32_to_int x + i32_to_int y + + [INT_OF_NUM_INJ] Theorem + + ⊢ ∀n m. &n = &m ⇒ n = m + + [INT_THM1] Theorem + + ⊢ ∀x y. x > 0 ⇒ y > 0 ⇒ x + y > 0 + + [INT_THM2] Theorem + + ⊢ ∀x. T + + [MK_I32_SUCCESS] Theorem + + ⊢ ∀n. i32_min ≤ n ∧ n ≤ i32_max ⇒ mk_i32 n = Return (int_to_i32 n) + + [MK_U32_SUCCESS] Theorem + + ⊢ ∀n. 0 ≤ n ∧ n ≤ u32_max ⇒ mk_u32 n = Return (int_to_u32 n) + + [NAT_THM1] Theorem + + ⊢ ∀n. n < n + 1 + + [NAT_THM2] Theorem + + ⊢ ∀n. n < n + 1 + + [NUM_SUB_1_EQ] Theorem + + ⊢ ∀x y. x = y − 1 ⇒ 0 ≤ x ⇒ Num y = SUC (Num x) + + [NUM_SUB_1_EQ1] Theorem + + ⊢ ∀i. 0 ≤ i − 1 ⇒ Num i = SUC (Num (i − 1)) + + [NUM_SUB_EQ] Theorem + + ⊢ ∀x y z. x = y − z ⇒ 0 ≤ x ⇒ 0 ≤ z ⇒ Num y = Num z + Num x + + [U32_ADD_EQ] Theorem + + [oracles: DISK_THM] [axioms: int_to_u32_id, u32_to_int_bounds] [] + ⊢ ∀x y. + u32_to_int x + u32_to_int y ≤ u32_max ⇒ + ∃z. u32_add x y = Return z ∧ + u32_to_int z = u32_to_int x + u32_to_int y + + [U32_SUB_EQ] Theorem + + [oracles: DISK_THM] [axioms: int_to_u32_id, u32_to_int_bounds] [] + ⊢ ∀x y. + 0 ≤ u32_to_int x − u32_to_int y ⇒ + ∃z. u32_sub x y = Return z ∧ + u32_to_int z = u32_to_int x − u32_to_int y + + [VEC_TO_LIST_INT_BOUNDS] Theorem + + [oracles: DISK_THM] [axioms: VEC_TO_LIST_BOUNDS] [] + ⊢ ∀v. (let l = &LENGTH (vec_to_list v) in 0 ≤ l ∧ l ≤ u32_max) + + [datatype_error] Theorem + + ⊢ DATATYPE (error Failure) + + [datatype_list_t] Theorem + + ⊢ DATATYPE (list_t ListCons ListNil) + + [datatype_result] Theorem + + ⊢ DATATYPE (result Return Fail Loop) + + [datatype_test] Theorem + + ⊢ DATATYPE (test Variant1 Variant2) + + [datatype_test2] Theorem + + ⊢ DATATYPE (test2 Variant1_2 Variant2_2) + + [error2num_11] Theorem + + ⊢ ∀a a'. error2num a = error2num a' ⇔ a = a' + + [error2num_ONTO] Theorem + + ⊢ ∀r. r < 1 ⇔ ∃a. r = error2num a + + [error2num_num2error] Theorem + + ⊢ ∀r. r < 1 ⇔ error2num (num2error r) = r + + [error2num_thm] Theorem + + ⊢ error2num Failure = 0 + + [error_Axiom] Theorem + + ⊢ ∀x0. ∃f. f Failure = x0 + + [error_EQ_error] Theorem + + ⊢ ∀a a'. a = a' ⇔ error2num a = error2num a' + + [error_case_cong] Theorem + + ⊢ ∀M M' v0. + M = M' ∧ (M' = Failure ⇒ v0 = v0') ⇒ + (case M of Failure => v0) = case M' of Failure => v0' + + [error_case_def] Theorem + + ⊢ ∀v0. (case Failure of Failure => v0) = v0 + + [error_case_eq] Theorem + + ⊢ (case x of Failure => v0) = v ⇔ x = Failure ∧ v0 = v + + [error_induction] Theorem + + ⊢ ∀P. P Failure ⇒ ∀a. P a + + [error_nchotomy] Theorem + + ⊢ ∀a. a = Failure + + [insert_lem] Theorem + + [oracles: DISK_THM] [axioms: u32_to_int_bounds, insert_def] [] + ⊢ ∀ls key value. + distinct_keys (list_t_v ls) ⇒ + case insert key value ls of + Return ls1 => + lookup key ls1 = SOME value ∧ + ∀k. k ≠ key ⇒ lookup k ls = lookup k ls1 + | Fail v1 => F + | Loop => F + + [list_nth_mut_loop_loop_fwd_def] Theorem + + ⊢ ∀ls i. + list_nth_mut_loop_loop_fwd ls i = + case ls of + ListCons x tl => + if u32_to_int i = 0 then Return x + else + do + i0 <- u32_sub i (int_to_u32 1); + list_nth_mut_loop_loop_fwd tl i0 + od + | ListNil => Fail Failure + + [list_nth_mut_loop_loop_fwd_ind] Theorem + + ⊢ ∀P. (∀ls i. + (∀x tl i0. ls = ListCons x tl ∧ u32_to_int i ≠ 0 ⇒ P tl i0) ⇒ + P ls i) ⇒ + ∀v v1. P v v1 + + [list_t_11] Theorem + + ⊢ ∀a0 a1 a0' a1'. + ListCons a0 a1 = ListCons a0' a1' ⇔ a0 = a0' ∧ a1 = a1' + + [list_t_Axiom] Theorem + + ⊢ ∀f0 f1. ∃fn. + (∀a0 a1. fn (ListCons a0 a1) = f0 a0 a1 (fn a1)) ∧ + fn ListNil = f1 + + [list_t_case_cong] Theorem + + ⊢ ∀M M' f v. + M = M' ∧ (∀a0 a1. M' = ListCons a0 a1 ⇒ f a0 a1 = f' a0 a1) ∧ + (M' = ListNil ⇒ v = v') ⇒ + list_t_CASE M f v = list_t_CASE M' f' v' + + [list_t_case_eq] Theorem + + ⊢ list_t_CASE x f v = v' ⇔ + (∃t l. x = ListCons t l ∧ f t l = v') ∨ x = ListNil ∧ v = v' + + [list_t_distinct] Theorem + + ⊢ ∀a1 a0. ListCons a0 a1 ≠ ListNil + + [list_t_induction] Theorem + + ⊢ ∀P. (∀l. P l ⇒ ∀t. P (ListCons t l)) ∧ P ListNil ⇒ ∀l. P l + + [list_t_nchotomy] Theorem + + ⊢ ∀ll. (∃t l. ll = ListCons t l) ∨ ll = ListNil + + [lookup_raw_def] Theorem + + ⊢ (∀key. lookup_raw key [] = NONE) ∧ + ∀v ls key k. + lookup_raw key ((k,v)::ls) = + if k = key then SOME v else lookup_raw key ls + + [lookup_raw_ind] Theorem + + ⊢ ∀P. (∀key. P key []) ∧ + (∀key k v ls. (k ≠ key ⇒ P key ls) ⇒ P key ((k,v)::ls)) ⇒ + ∀v v1. P v v1 + + [nth_def] Theorem + + ⊢ ∀ls i. + nth ls i = + case ls of + ListCons x tl => + if u32_to_int i = 0 then Return x + else do i0 <- u32_sub i (int_to_u32 1); nth tl i0 od + | ListNil => Fail Failure + + [nth_def_loop] Theorem + + ⊢ ∀ls i. (∀n. ¬nth_fuel_P ls i n) ⇒ nth ls i = nth_expand nth ls i + + [nth_def_terminates] Theorem + + ⊢ ∀ls i. (∃n. nth_fuel_P ls i n) ⇒ nth ls i = nth_expand nth ls i + + [nth_fuel_P_mono] Theorem + + ⊢ ∀n m ls i. + n ≤ m ⇒ nth_fuel_P ls i n ⇒ nth_fuel n ls i = nth_fuel m ls i + + [nth_fuel_def] Theorem + + ⊢ ∀n ls i. + nth_fuel n ls i = + case n of + 0 => Loop + | SUC n' => + case ls of + ListCons x tl => + if u32_to_int i = 0 then Return x + else + do i0 <- u32_sub i (int_to_u32 1); nth_fuel n' tl i0 od + | ListNil => Fail Failure + + [nth_fuel_ind] Theorem + + ⊢ ∀P. (∀n ls i. + (∀n' x tl i0. + n = SUC n' ∧ ls = ListCons x tl ∧ u32_to_int i ≠ 0 ⇒ + P n' tl i0) ⇒ + P n ls i) ⇒ + ∀v v1 v2. P v v1 v2 + + [nth_fuel_least_fail_mono] Theorem + + ⊢ ∀n ls i. n < $LEAST (nth_fuel_P ls i) ⇒ nth_fuel n ls i = Loop + + [nth_fuel_least_success_mono] Theorem + + ⊢ ∀n ls i. + $LEAST (nth_fuel_P ls i) ≤ n ⇒ + nth_fuel n ls i = nth_fuel ($LEAST (nth_fuel_P ls i)) ls i + + [nth_fuel_mono] Theorem + + ⊢ ∀n m ls i. + n ≤ m ⇒ + if is_loop (nth_fuel n ls i) then T + else nth_fuel n ls i = nth_fuel m ls i + + [num2error_11] Theorem + + ⊢ ∀r r'. r < 1 ⇒ r' < 1 ⇒ (num2error r = num2error r' ⇔ r = r') + + [num2error_ONTO] Theorem + + ⊢ ∀a. ∃r. a = num2error r ∧ r < 1 + + [num2error_error2num] Theorem + + ⊢ ∀a. num2error (error2num a) = a + + [num2error_thm] Theorem + + ⊢ num2error 0 = Failure + + [result_11] Theorem + + ⊢ (∀a a'. Return a = Return a' ⇔ a = a') ∧ + ∀a a'. Fail a = Fail a' ⇔ a = a' + + [result_Axiom] Theorem + + ⊢ ∀f0 f1 f2. ∃fn. + (∀a. fn (Return a) = f0 a) ∧ (∀a. fn (Fail a) = f1 a) ∧ + fn Loop = f2 + + [result_case_cong] Theorem + + ⊢ ∀M M' f f1 v. + M = M' ∧ (∀a. M' = Return a ⇒ f a = f' a) ∧ + (∀a. M' = Fail a ⇒ f1 a = f1' a) ∧ (M' = Loop ⇒ v = v') ⇒ + result_CASE M f f1 v = result_CASE M' f' f1' v' + + [result_case_eq] Theorem + + ⊢ result_CASE x f f1 v = v' ⇔ + (∃a. x = Return a ∧ f a = v') ∨ (∃e. x = Fail e ∧ f1 e = v') ∨ + x = Loop ∧ v = v' + + [result_distinct] Theorem + + ⊢ (∀a' a. Return a ≠ Fail a') ∧ (∀a. Return a ≠ Loop) ∧ + ∀a. Fail a ≠ Loop + + [result_induction] Theorem + + ⊢ ∀P. (∀a. P (Return a)) ∧ (∀e. P (Fail e)) ∧ P Loop ⇒ ∀r. P r + + [result_nchotomy] Theorem + + ⊢ ∀rr. (∃a. rr = Return a) ∨ (∃e. rr = Fail e) ∨ rr = Loop + + [test2_11] Theorem + + ⊢ (∀a a'. Variant1_2 a = Variant1_2 a' ⇔ a = a') ∧ + ∀a a'. Variant2_2 a = Variant2_2 a' ⇔ a = a' + + [test2_Axiom] Theorem + + ⊢ ∀f0 f1. ∃fn. + (∀a. fn (Variant1_2 a) = f0 a) ∧ ∀a. fn (Variant2_2 a) = f1 a + + [test2_case_cong] Theorem + + ⊢ ∀M M' f f1. + M = M' ∧ (∀a. M' = Variant1_2 a ⇒ f a = f' a) ∧ + (∀a. M' = Variant2_2 a ⇒ f1 a = f1' a) ⇒ + test2_CASE M f f1 = test2_CASE M' f' f1' + + [test2_case_eq] Theorem + + ⊢ test2_CASE x f f1 = v ⇔ + (∃T'. x = Variant1_2 T' ∧ f T' = v) ∨ + ∃T'. x = Variant2_2 T' ∧ f1 T' = v + + [test2_distinct] Theorem + + ⊢ ∀a' a. Variant1_2 a ≠ Variant2_2 a' + + [test2_induction] Theorem + + ⊢ ∀P. (∀T. P (Variant1_2 T)) ∧ (∀T. P (Variant2_2 T)) ⇒ ∀t. P t + + [test2_nchotomy] Theorem + + ⊢ ∀tt. (∃T. tt = Variant1_2 T) ∨ ∃T. tt = Variant2_2 T + + [test_11] Theorem + + ⊢ (∀a a'. Variant1 a = Variant1 a' ⇔ a = a') ∧ + ∀a a'. Variant2 a = Variant2 a' ⇔ a = a' + + [test_Axiom] Theorem + + ⊢ ∀f0 f1. ∃fn. + (∀a. fn (Variant1 a) = f0 a) ∧ ∀a. fn (Variant2 a) = f1 a + + [test_case_cong] Theorem + + ⊢ ∀M M' f f1. + M = M' ∧ (∀a. M' = Variant1 a ⇒ f a = f' a) ∧ + (∀a. M' = Variant2 a ⇒ f1 a = f1' a) ⇒ + test_CASE M f f1 = test_CASE M' f' f1' + + [test_case_eq] Theorem + + ⊢ test_CASE x f f1 = v ⇔ + (∃b. x = Variant1 b ∧ f b = v) ∨ ∃a. x = Variant2 a ∧ f1 a = v + + [test_distinct] Theorem + + ⊢ ∀a' a. Variant1 a ≠ Variant2 a' + + [test_induction] Theorem + + ⊢ ∀P. (∀b. P (Variant1 b)) ∧ (∀a. P (Variant2 a)) ⇒ ∀t. P t + + [test_nchotomy] Theorem + + ⊢ ∀tt. (∃b. tt = Variant1 b) ∨ ∃a. tt = Variant2 a + + +*) +end -- cgit v1.2.3