diff --git a/src/interpretation.ml b/src/interpretation.ml index bcfb697b7420cae90de798ea2cb41b56ff76bf09..c1c96e49553f0343c78639a76b1a8744c93c7d06 100644 --- a/src/interpretation.ml +++ b/src/interpretation.ml @@ -20,13 +20,14 @@ (* *) (**************************************************************************) +module Caisar_reduction_engine = Reduction_engine open Why3 open Base let interpret_task env task = let f = Task.task_goal_fmla task in let engine = - Reduction_engine.create + Caisar_reduction_engine.create { compute_defs = false; compute_builtin = true; @@ -35,8 +36,11 @@ let interpret_task env task = } env Ident.Mid.empty in - let f = Reduction_engine.normalize ~limit:1000 engine Term.Mvs.empty f in - Fmt.pr "%a : %a@." Pretty.print_pr (Task.task_goal task) Pretty.print_term f + let f = + Caisar_reduction_engine.normalize ~limit:1000 engine Term.Mvs.empty f + in + Fmt.pr "%a : %a@.%a@." Pretty.print_pr (Task.task_goal task) Pretty.print_term + f Caisar_reduction_engine.print_caisar_op engine let interpret ?debug ?format ~loadpath s = let env, _config, mstr_theory = diff --git a/src/reduction_engine.ml b/src/reduction_engine.ml index e2f878308cddc93b9f7035a695abc5656b8ea466..e0c5c121f2255808700fe63a960852f4a74595cf 100644 --- a/src/reduction_engine.ml +++ b/src/reduction_engine.ml @@ -12,27 +12,88 @@ open Why3 open Term -[@@@ ocaml.warning "-9"] +[@@@ocaml.warning "-9"] (* {2 Values} *) +type dataset = { dataset : string } [@@deriving show] +type caisar_op = Dataset of dataset | Size of dataset [@@deriving show] + type value = - | Term of term (* invariant: is in normal form *) + | Term of term (* invariant: is in normal form *) | Int of BigInt.t | Real of Number.real_value +(** {2 Environment} *) + +type caisar_env = { + dataset_ty : Ty.ty; + caisar_op_of_ls : caisar_op Term.Hls.t; + ls_of_caisar_op : (caisar_op, Term.lsymbol) Hashtbl.t; +} + +type rule = Svs.t * term list * term + +type params = { + compute_defs : bool; + compute_builtin : bool; + compute_def_set : Term.Sls.t; + compute_max_quantifier_domain : int; +} + +type builtin = engine -> lsymbol -> value list -> Ty.ty option -> value + +and engine = { + env : Env.env; + known_map : Decl.decl Ident.Mid.t; + rules : rule list Mls.t; + params : params; + ls_lt : lsymbol; (* The lsymbol for [int.Int.(<)] *) + caisar_env : caisar_env; + builtins : builtin Hls.t; +} + +let ls_of_caisar_op env op = + if Hashtbl.mem env.caisar_env.ls_of_caisar_op op + then Hashtbl.find env.caisar_env.ls_of_caisar_op op + else + let id = Ident.id_fresh "caisar_op" in + let ty = + match op with + | Dataset _ -> env.caisar_env.dataset_ty + | Size _ -> Ty.ty_int + in + let ls = Term.create_fsymbol id [] ty in + Hashtbl.add env.caisar_env.ls_of_caisar_op op ls; + Term.Hls.add env.caisar_env.caisar_op_of_ls ls op; + ls + +let caisar_op_of_ls env ls = Term.Hls.find env.caisar_env.caisar_op_of_ls ls +let term_of_caisar_op env op = Term.t_app_infer (ls_of_caisar_op env op) [] + +let read_caisar_env env = + let th = Env.read_theory env [ "caisar" ] "Interpret" in + let dataset_ts = Theory.ns_find_ts th.Theory.th_export [ "dataset" ] in + { + dataset_ty = Ty.ty_app dataset_ts []; + ls_of_caisar_op = Hashtbl.create 10; + caisar_op_of_ls = Term.Hls.create 10; + } + +let print_caisar_op fmt engine = + Pp.print_iter2 Term.Hls.iter Pp.newline Pp.comma Pretty.print_ls pp_caisar_op + fmt engine.caisar_env.caisar_op_of_ls + let v_attr_copy orig v = - match v with - | Int _ -> v - | Real _ -> v - | Term t -> Term (t_attr_copy orig t) + match v with Int _ -> v | Real _ -> v | Term t -> Term (t_attr_copy orig t) let term_of_value v = let open Number in match v with | Term t -> t | Int n -> t_int_const n - | Real { rv_sig = s; rv_pow2 = pow2; rv_pow5 = pow5 } -> t_real_const ~pow2 ~pow5 s + | Real { rv_sig = s; rv_pow2 = pow2; rv_pow5 = pow5 } -> + t_real_const ~pow2 ~pow5 s exception NotNum @@ -64,98 +125,80 @@ let real_of_value v = (* {2 Builtin symbols} *) -let builtins = Hls.create 17 - (* all builtin functions *) exception Undetermined let to_bool b = if b then t_true else t_false -let _t_app_value ls l ty = - Term (t_app ls (List.map term_of_value l) ty) - let is_zero v = - try BigInt.eq (big_int_of_value v) BigInt.zero - with NotNum -> false + try BigInt.eq (big_int_of_value v) BigInt.zero with NotNum -> false let is_one v = - try BigInt.eq (big_int_of_value v) BigInt.one - with NotNum -> false + try BigInt.eq (big_int_of_value v) BigInt.one with NotNum -> false -let eval_int_op op simpl ls l ty = +let eval_int_op op simpl _ ls l ty = match l with - | [t1 ; t2] -> - begin - try - let n1 = big_int_of_value t1 in - let n2 = big_int_of_value t2 in - Int (op n1 n2) - with NotNum | Division_by_zero -> - simpl ls t1 t2 ty - end + | [ t1; t2 ] -> ( + try + let n1 = big_int_of_value t1 in + let n2 = big_int_of_value t2 in + Int (op n1 n2) + with NotNum | Division_by_zero -> simpl ls t1 t2 ty) | _ -> assert false let simpl_add _ls t1 t2 _ty = - if is_zero t1 then t2 else - if is_zero t2 then t1 else - raise Undetermined + if is_zero t1 then t2 else if is_zero t2 then t1 else raise Undetermined -let simpl_sub _ls t1 t2 _ty = - if is_zero t2 then t1 else - raise Undetermined +let simpl_sub _ls t1 t2 _ty = if is_zero t2 then t1 else raise Undetermined let simpl_mul _ls t1 t2 _ty = - if is_zero t1 then t1 else - if is_zero t2 then t2 else - if is_one t1 then t2 else - if is_one t2 then t1 else - raise Undetermined + if is_zero t1 + then t1 + else if is_zero t2 + then t2 + else if is_one t1 + then t2 + else if is_one t2 + then t1 + else raise Undetermined let simpl_div _ls t1 t2 _ty = if is_zero t2 then raise Undetermined; - if is_zero t1 then t1 else - if is_one t2 then t1 else - raise Undetermined + if is_zero t1 then t1 else if is_one t2 then t1 else raise Undetermined let simpl_mod _ls t1 t2 _ty = if is_zero t2 then raise Undetermined; - if is_zero t1 then t1 else - if is_one t2 then Int (BigInt.zero) else - raise Undetermined + if is_zero t1 + then t1 + else if is_one t2 + then Int BigInt.zero + else raise Undetermined let simpl_minmax _ls v1 v2 _ty = - match v1,v2 with - | Term t1, Term t2 -> - if t_equal t1 t2 then v1 else - raise Undetermined - | _ -> - raise Undetermined - -let eval_int_rel op _ls l _ty = + match (v1, v2) with + | Term t1, Term t2 -> if t_equal t1 t2 then v1 else raise Undetermined + | _ -> raise Undetermined + +let eval_int_rel op _ _ls l _ty = match l with - | [t1 ; t2] -> - begin - try - let n1 = big_int_of_value t1 in - let n2 = big_int_of_value t2 in - Term (to_bool (op n1 n2)) - with NotNum | Division_by_zero -> - raise Undetermined - (* t_app_value ls l ty *) - end + | [ t1; t2 ] -> ( + try + let n1 = big_int_of_value t1 in + let n2 = big_int_of_value t2 in + Term (to_bool (op n1 n2)) + with NotNum | Division_by_zero -> + raise Undetermined (* t_app_value ls l ty *)) | _ -> assert false -let eval_int_uop op _ls l _ty = +let eval_int_uop op _ _ls l _ty = match l with - | [t1] -> - begin - try - let n1 = big_int_of_value t1 in Int (op n1) - with NotNum | Division_by_zero -> - raise Undetermined - (* t_app_value ls l ty *) - end + | [ t1 ] -> ( + try + let n1 = big_int_of_value t1 in + Int (op n1) + with NotNum | Division_by_zero -> + raise Undetermined (* t_app_value ls l ty *)) | _ -> assert false let real_align ~pow2 ~pow5 r = @@ -165,62 +208,53 @@ let real_align ~pow2 ~pow5 r = let s = BigInt.mul s (BigInt.pow_int_pos_bigint 5 (BigInt.sub p5 pow5)) in s -let eval_real_op op simpl ls l ty = +let eval_real_op op simpl _ ls l ty = match l with - | [t1; t2] -> - begin - try - let n1 = real_of_value t1 in - let n2 = real_of_value t2 in - Real (op n1 n2) - with NotNum -> - simpl ls t1 t2 ty - end + | [ t1; t2 ] -> ( + try + let n1 = real_of_value t1 in + let n2 = real_of_value t2 in + Real (op n1 n2) + with NotNum -> simpl ls t1 t2 ty) | _ -> assert false -let eval_real_uop op _ls l _ty = +let eval_real_uop op _ _ls l _ty = match l with - | [t1] -> - begin - try - let n1 = real_of_value t1 in - Real (op n1) - with NotNum -> - raise Undetermined - end + | [ t1 ] -> ( + try + let n1 = real_of_value t1 in + Real (op n1) + with NotNum -> raise Undetermined) | _ -> assert false -let eval_real_rel op _ls l _ty = +let eval_real_rel op _ _ls l _ty = let open Number in match l with - | [t1 ; t2] -> - begin - try - let n1 = real_of_value t1 in - let n2 = real_of_value t2 in - let s1, s2 = - let { rv_sig = s1; rv_pow2 = p21; rv_pow5 = p51 } = n1 in - let { rv_sig = s2; rv_pow2 = p22; rv_pow5 = p52 } = n2 in - if BigInt.sign s1 <> BigInt.sign s2 then s1,s2 - else - let pow2 = BigInt.min p21 p22 in - let pow5 = BigInt.min p51 p52 in - let s1 = real_align ~pow2 ~pow5 n1 in - let s2 = real_align ~pow2 ~pow5 n2 in - s1, s2 in - Term (to_bool (op s1 s2)) - with NotNum -> - raise Undetermined - (* t_app_value ls l ty *) - end + | [ t1; t2 ] -> ( + try + let n1 = real_of_value t1 in + let n2 = real_of_value t2 in + let s1, s2 = + let { rv_sig = s1; rv_pow2 = p21; rv_pow5 = p51 } = n1 in + let { rv_sig = s2; rv_pow2 = p22; rv_pow5 = p52 } = n2 in + if BigInt.sign s1 <> BigInt.sign s2 + then (s1, s2) + else + let pow2 = BigInt.min p21 p22 in + let pow5 = BigInt.min p51 p52 in + let s1 = real_align ~pow2 ~pow5 n1 in + let s2 = real_align ~pow2 ~pow5 n2 in + (s1, s2) + in + Term (to_bool (op s1 s2)) + with NotNum -> raise Undetermined (* t_app_value ls l ty *)) | _ -> assert false let real_0 = Number.real_value BigInt.zero let real_1 = Number.real_value BigInt.one let is_real t r = - try Number.compare_real (real_of_value t) r = 0 - with NotNum -> false + try Number.compare_real (real_of_value t) r = 0 with NotNum -> false let real_opp r = let open Number in @@ -231,25 +265,31 @@ let real_add r1 r2 = let open Number in let { rv_sig = s1; rv_pow2 = p21; rv_pow5 = p51 } = r1 in let { rv_sig = s2; rv_pow2 = p22; rv_pow5 = p52 } = r2 in - if BigInt.eq s1 BigInt.zero then r2 else - if BigInt.eq s2 BigInt.zero then r1 else - let pow2 = BigInt.min p21 p22 in - let pow5 = BigInt.min p51 p52 in - let s1 = real_align ~pow2 ~pow5 r1 in - let s2 = real_align ~pow2 ~pow5 r2 in - real_value ~pow2 ~pow5 (BigInt.add s1 s2) + if BigInt.eq s1 BigInt.zero + then r2 + else if BigInt.eq s2 BigInt.zero + then r1 + else + let pow2 = BigInt.min p21 p22 in + let pow5 = BigInt.min p51 p52 in + let s1 = real_align ~pow2 ~pow5 r1 in + let s2 = real_align ~pow2 ~pow5 r2 in + real_value ~pow2 ~pow5 (BigInt.add s1 s2) let real_sub r1 r2 = let open Number in let { rv_sig = s1; rv_pow2 = p21; rv_pow5 = p51 } = r1 in let { rv_sig = s2; rv_pow2 = p22; rv_pow5 = p52 } = r2 in - if BigInt.eq s2 BigInt.zero then r1 else - if BigInt.eq s1 BigInt.zero then real_value ~pow2:p22 ~pow5:p52 (BigInt.minus s2) else - let pow2 = BigInt.min p21 p22 in - let pow5 = BigInt.min p51 p52 in - let s1 = real_align ~pow2 ~pow5 r1 in - let s2 = real_align ~pow2 ~pow5 r2 in - real_value ~pow2 ~pow5 (BigInt.sub s1 s2) + if BigInt.eq s2 BigInt.zero + then r1 + else if BigInt.eq s1 BigInt.zero + then real_value ~pow2:p22 ~pow5:p52 (BigInt.minus s2) + else + let pow2 = BigInt.min p21 p22 in + let pow5 = BigInt.min p51 p52 in + let s1 = real_align ~pow2 ~pow5 r1 in + let s2 = real_align ~pow2 ~pow5 r2 in + real_value ~pow2 ~pow5 (BigInt.sub s1 s2) let real_mul r1 r2 = let open Number in @@ -261,204 +301,222 @@ let real_mul r1 r2 = real_value ~pow2 ~pow5 s let simpl_real_add _ls t1 t2 _ty = - if is_real t1 real_0 then t2 else - if is_real t2 real_0 then t1 else - raise Undetermined + if is_real t1 real_0 + then t2 + else if is_real t2 real_0 + then t1 + else raise Undetermined let simpl_real_sub _ls t1 t2 _ty = - if is_real t2 real_0 then t1 else - raise Undetermined + if is_real t2 real_0 then t1 else raise Undetermined let simpl_real_mul _ls t1 t2 _ty = - if is_real t1 real_0 then t1 else - if is_real t2 real_0 then t2 else - if is_real t1 real_1 then t2 else - if is_real t2 real_1 then t1 else - raise Undetermined + if is_real t1 real_0 + then t1 + else if is_real t2 real_0 + then t2 + else if is_real t1 real_1 + then t2 + else if is_real t2 real_1 + then t1 + else raise Undetermined let real_pow r1 r2 = let open Number in let { rv_sig = s1; rv_pow2 = p21; rv_pow5 = p51 } = r1 in let { rv_sig = s2; rv_pow2 = p22; rv_pow5 = p52 } = r2 in - if BigInt.le s1 BigInt.zero then - raise Undetermined - else if BigInt.lt p22 BigInt.zero || BigInt.lt p52 BigInt.zero then - raise NotNum + if BigInt.le s1 BigInt.zero + then raise Undetermined + else if BigInt.lt p22 BigInt.zero || BigInt.lt p52 BigInt.zero + then raise NotNum else let s1 = try BigInt.to_int s1 with Failure _ -> raise NotNum in let s2 = BigInt.mul s2 (BigInt.pow_int_pos_bigint 2 p22) in let s2 = BigInt.mul s2 (BigInt.pow_int_pos_bigint 5 p52) in let s = - if s1 = 1 then BigInt.one - else if BigInt.lt s2 BigInt.zero then raise NotNum - else BigInt.pow_int_pos_bigint s1 s2 in + if s1 = 1 + then BigInt.one + else if BigInt.lt s2 BigInt.zero + then raise NotNum + else BigInt.pow_int_pos_bigint s1 s2 + in let pow2 = BigInt.mul p21 s2 in let pow5 = BigInt.mul p51 s2 in Number.real_value ~pow2 ~pow5 s let simpl_real_pow _ls t1 _t2 _ty = - if is_real t1 real_1 then t1 else - raise Undetermined + if is_real t1 real_1 then t1 else raise Undetermined -let real_from_int _ls l _ty = +let real_from_int _ _ls l _ty = match l with - | [t] -> - begin - try - let n = big_int_of_value t in - Real (Number.real_value n) - with NotNum -> - raise Undetermined - end + | [ t ] -> ( + try + let n = big_int_of_value t in + Real (Number.real_value n) + with NotNum -> raise Undetermined) | _ -> assert false -let built_in_theories = +type built_in_theories = + Env.pathname + * string + * (string * (Ty.tysymbol -> unit)) list + * (string * lsymbol ref option * builtin) list + +let built_in_theories : built_in_theories list = [ -(* - ["bool"],"Bool", [], - [ "True", None, eval_true ; - "False", None, eval_false ; - ] ; -*) - ["int"],"Int", [], - [ Ident.op_infix "+", None, eval_int_op BigInt.add simpl_add; - Ident.op_infix "-", None, eval_int_op BigInt.sub simpl_sub; - Ident.op_infix "*", None, eval_int_op BigInt.mul simpl_mul; - Ident.op_prefix "-", None, eval_int_uop BigInt.minus; - Ident.op_infix "<", None, eval_int_rel BigInt.lt; - Ident.op_infix "<=", None, eval_int_rel BigInt.le; - Ident.op_infix ">", None, eval_int_rel BigInt.gt; - Ident.op_infix ">=", None, eval_int_rel BigInt.ge; - ] ; - ["int"],"MinMax", [], - [ "min", None, eval_int_op BigInt.min simpl_minmax; - "max", None, eval_int_op BigInt.max simpl_minmax; - ] ; - ["int"],"ComputerDivision", [], - [ "div", None, eval_int_op BigInt.computer_div simpl_div; - "mod", None, eval_int_op BigInt.computer_mod simpl_mod; - ] ; - ["int"],"EuclideanDivision", [], - [ "div", None, eval_int_op BigInt.euclidean_div simpl_div; - "mod", None, eval_int_op BigInt.euclidean_mod simpl_mod; - ] ; - ["real"], "Real", [], - [ Ident.op_prefix "-", None, eval_real_uop real_opp; - Ident.op_infix "+", None, eval_real_op real_add simpl_real_add; - Ident.op_infix "-", None, eval_real_op real_sub simpl_real_sub; - Ident.op_infix "*", None, eval_real_op real_mul simpl_real_mul; - Ident.op_infix "<", None, eval_real_rel BigInt.lt; - Ident.op_infix "<=", None, eval_real_rel BigInt.le; - Ident.op_infix ">", None, eval_real_rel BigInt.gt; - Ident.op_infix ">=", None, eval_real_rel BigInt.ge ] ; - ["real"], "FromInt", [], - [ "from_int", None, real_from_int ] ; - ["real"], "PowerReal", [], - [ "pow", None, eval_real_op real_pow simpl_real_pow ] ; -(* - ["map"],"Map", ["map", builtin_map_type], - [ "const", Some ls_map_const, eval_map_const; - "get", Some ls_map_get, eval_map_get; - "set", Some ls_map_set, eval_map_set; - ] ; -*) + (* ["bool"],"Bool", [], [ "True", None, eval_true ; "False", None, + eval_false ; ] ; *) + ( [ "int" ], + "Int", + [], + [ + (Ident.op_infix "+", None, eval_int_op BigInt.add simpl_add); + (Ident.op_infix "-", None, eval_int_op BigInt.sub simpl_sub); + (Ident.op_infix "*", None, eval_int_op BigInt.mul simpl_mul); + (Ident.op_prefix "-", None, eval_int_uop BigInt.minus); + (Ident.op_infix "<", None, eval_int_rel BigInt.lt); + (Ident.op_infix "<=", None, eval_int_rel BigInt.le); + (Ident.op_infix ">", None, eval_int_rel BigInt.gt); + (Ident.op_infix ">=", None, eval_int_rel BigInt.ge); + ] ); + ( [ "int" ], + "MinMax", + [], + [ + ("min", None, eval_int_op BigInt.min simpl_minmax); + ("max", None, eval_int_op BigInt.max simpl_minmax); + ] ); + ( [ "int" ], + "ComputerDivision", + [], + [ + ("div", None, eval_int_op BigInt.computer_div simpl_div); + ("mod", None, eval_int_op BigInt.computer_mod simpl_mod); + ] ); + ( [ "int" ], + "EuclideanDivision", + [], + [ + ("div", None, eval_int_op BigInt.euclidean_div simpl_div); + ("mod", None, eval_int_op BigInt.euclidean_mod simpl_mod); + ] ); + ( [ "real" ], + "Real", + [], + [ + (Ident.op_prefix "-", None, eval_real_uop real_opp); + (Ident.op_infix "+", None, eval_real_op real_add simpl_real_add); + (Ident.op_infix "-", None, eval_real_op real_sub simpl_real_sub); + (Ident.op_infix "*", None, eval_real_op real_mul simpl_real_mul); + (Ident.op_infix "<", None, eval_real_rel BigInt.lt); + (Ident.op_infix "<=", None, eval_real_rel BigInt.le); + (Ident.op_infix ">", None, eval_real_rel BigInt.gt); + (Ident.op_infix ">=", None, eval_real_rel BigInt.ge); + ] ); + ([ "real" ], "FromInt", [], [ ("from_int", None, real_from_int) ]); + ( [ "real" ], + "PowerReal", + [], + [ ("pow", None, eval_real_op real_pow simpl_real_pow) ] ); + (* ["map"],"Map", ["map", builtin_map_type], [ "const", Some ls_map_const, + eval_map_const; "get", Some ls_map_get, eval_map_get; "set", Some + ls_map_set, eval_map_set; ] ; *) ] -let add_builtin_th env (l,n,t,d) = - let th = Env.read_theory env l n in +let add_builtin_th env ((l, n, t, d) : built_in_theories) = + let th = Env.read_theory env.env l n in List.iter - (fun (id,r) -> - let ts = Theory.ns_find_ts th.Theory.th_export [id] in + (fun (id, r) -> + let ts = Theory.ns_find_ts th.Theory.th_export [ id ] in r ts) t; List.iter - (fun (id,r,f) -> - let ls = Theory.ns_find_ls th.Theory.th_export [id] in - Hls.add builtins ls f; - match r with - | None -> () - | Some r -> r := ls) + (fun (id, r, f) -> + let ls = Theory.ns_find_ls th.Theory.th_export [ id ] in + Hls.add env.builtins ls f; + match r with None -> () | Some r -> r := ls) d -let get_builtins env = - Hls.clear builtins; - List.iter (add_builtin_th env) built_in_theories +let built_in_caisar : built_in_theories list = + let open_dataset : builtin = + fun engine _ l _ -> + match l with + | [ Term { t_node = Tconst (ConstStr dataset) } ] -> + Term (term_of_caisar_op engine (Dataset { dataset })) + | _ -> invalid_arg "We want a string! ;)" + in + let size : builtin = + fun engine _ l _ -> + match l with + | [ Term { t_node = Tapp (ls, []) } ] -> ( + match caisar_op_of_ls engine ls with + | Dataset dataset -> Term (term_of_caisar_op engine (Size dataset)) + | Size _ -> invalid_arg "We want a dataset! ;)") + | _ -> invalid_arg "We want a string! ;)" + in + [ + (* ["bool"],"Bool", [], [ "True", None, eval_true ; "False", None, + eval_false ; ] ; *) + ( [ "caisar" ], + "Interpret", + [], + [ ("open_dataset", None, open_dataset); ("size", None, size) ] ); + ] +let get_builtins env = + Hls.clear env.builtins; + List.iter (add_builtin_th env) built_in_theories; + List.iter (add_builtin_th env) built_in_caisar (* {2 the reduction machine} *) - -type rule = Svs.t * term list * term - -type params = - { compute_defs : bool; - compute_builtin : bool; - compute_def_set : Term.Sls.t; - compute_max_quantifier_domain : int; - } - -type engine = - { known_map : Decl.decl Ident.Mid.t; - rules : rule list Mls.t; - params : params; - ls_lt : lsymbol; (* The lsymbol for [int.Int.(<)] *) - } - - (* OBSOLETE COMMENT - A configuration is a pair (t,s) where t is a stack of terms and s is a - stack of function symbols. - - A configuration ([t1;..;tn],[f1;..;fk]) represents a whole term, its - model, as defined recursively by + A configuration is a pair (t,s) where t is a stack of terms and s is a stack + of function symbols. - model([t],[]) = t + A configuration ([t1;..;tn],[f1;..;fk]) represents a whole term, its model, + as defined recursively by - model(t1::..::tn::t,f::s) = model(f(t1,..,tn)::t,s) - where f is of arity n + model([t],[]) = t - A given term can be "exploded" into a configuration by reversing the - rules above + model(t1::..::tn::t,f::s) = model(f(t1,..,tn)::t,s) where f is of arity n - During reduction, the terms in the first stack are kept in normal - form (value). The normalization process can be defined as the repeated - application of the following rules. + A given term can be "exploded" into a configuration by reversing the rules + above - ([t],[]) --> t // t is in normal form + During reduction, the terms in the first stack are kept in normal form + (value). The normalization process can be defined as the repeated application + of the following rules. - if f(t1,..,tn) is not a redex then - (t1::..::tn::t,f::s) --> (f(t1,..,tn)::t,s) + ([t],[]) --> t // t is in normal form - if f(t1,..,tn) is a redex l sigma for a rule l -> r then - (t1::..::tn::t,f::s) --> (subst(sigma) @ t,explode(r) @ s) + if f(t1,..,tn) is not a redex then (t1::..::tn::t,f::s) --> + (f(t1,..,tn)::t,s) - - - -*) + if f(t1,..,tn) is a redex l sigma for a rule l -> r then (t1::..::tn::t,f::s) + --> (subst(sigma) @ t,explode(r) @ s) *) type substitution = term Mvs.t type cont = -| Kapp of lsymbol * Ty.ty option -| Kif of term * term * substitution -| Klet of vsymbol * term * substitution -| Kcase of term_branch list * substitution -| Keps of vsymbol -| Kquant of quant * vsymbol list * trigger -| Kbinop of binop -| Knot -| Keval of term * substitution + | Kapp of lsymbol * Ty.ty option + | Kif of term * term * substitution + | Klet of vsymbol * term * substitution + | Kcase of term_branch list * substitution + | Keps of vsymbol + | Kquant of quant * vsymbol list * trigger + | Kbinop of binop + | Knot + | Keval of term * substitution type config = { value_stack : value list; cont_stack : (cont * term) list; - (* second term is the original term, for attribute and loc copy *) + (* second term is the original term, for attribute and loc copy *) } - (* This global variable is used to approximate a count of the elementary simplifications that are done during normalization. This is used for transformation step. *) @@ -468,184 +526,149 @@ exception NoMatch of (term * term * term option) option exception NoMatchpat of (pattern * pattern) option let rec pattern_renaming (bound_vars, mt) p1 p2 = - match p1.pat_node, p2.pat_node with - | Pwild, Pwild -> + match (p1.pat_node, p2.pat_node) with + | Pwild, Pwild -> (bound_vars, mt) + | Pvar v1, Pvar v2 -> ( + try + let mt = Ty.ty_match mt v1.vs_ty v2.vs_ty in + let bound_vars = Mvs.add v2 v1 bound_vars in (bound_vars, mt) - | Pvar v1, Pvar v2 -> - begin - try - let mt = Ty.ty_match mt v1.vs_ty v2.vs_ty in - let bound_vars = Mvs.add v2 v1 bound_vars in - (bound_vars, mt) - with - | Ty.TypeMismatch _ -> - raise (NoMatchpat (Some (p1, p2))) - end + with Ty.TypeMismatch _ -> raise (NoMatchpat (Some (p1, p2)))) | Papp (ls1, tl1), Papp (ls2, tl2) when ls_equal ls1 ls2 -> - List.fold_left2 pattern_renaming (bound_vars, mt) tl1 tl2 + List.fold_left2 pattern_renaming (bound_vars, mt) tl1 tl2 | Por (p1a, p1b), Por (p2a, p2b) -> - let (bound_vars, mt) = - pattern_renaming (bound_vars, mt) p1a p2a in - pattern_renaming (bound_vars, mt) p1b p2b - | Pas (p1, v1), Pas (p2, v2) -> - begin - try - let mt = Ty.ty_match mt v1.vs_ty v2.vs_ty in - let bound_vars = Mvs.add v2 v1 bound_vars in - pattern_renaming (bound_vars, mt) p1 p2 - with - | Ty.TypeMismatch _ -> - raise (NoMatchpat (Some (p1, p2))) - end + let bound_vars, mt = pattern_renaming (bound_vars, mt) p1a p2a in + pattern_renaming (bound_vars, mt) p1b p2b + | Pas (p1, v1), Pas (p2, v2) -> ( + try + let mt = Ty.ty_match mt v1.vs_ty v2.vs_ty in + let bound_vars = Mvs.add v2 v1 bound_vars in + pattern_renaming (bound_vars, mt) p1 p2 + with Ty.TypeMismatch _ -> raise (NoMatchpat (Some (p1, p2)))) | _ -> raise (NoMatchpat (Some (p1, p2))) -let first_order_matching (vars : Svs.t) (largs : term list) - (args : term list) : Ty.ty Ty.Mtv.t * substitution = - let rec loop bound_vars ((mt,mv) as sigma) largs args = - match largs,args with - | [],[] -> sigma - | t1::r1, t2::r2 -> - begin -(* - Format.eprintf "matching terms %a and %a...@." - Pretty.print_term t1 Pretty.print_term t2; -*) - match t1.t_node with - | Tvar vs when Svs.mem vs vars -> - begin - try let t = Mvs.find vs mv in - if t_equal t t2 then - loop bound_vars sigma r1 r2 - else - raise (NoMatch (Some (t1, t2, Some t))) - with Not_found -> - try - let ts = Ty.ty_match mt vs.vs_ty (t_type t2) in - let fv2 = t_vars t2 in - if Mvs.is_empty (Mvs.set_inter bound_vars fv2) then - loop bound_vars (ts,Mvs.add vs t2 mv) r1 r2 - else - raise (NoMatch (Some (t1, t2, None))) - with Ty.TypeMismatch _ -> - raise (NoMatch (Some (t1, t2, None))) - end - | Tapp(ls1,args1) -> - begin - match t2.t_node with - | Tapp(ls2,args2) when ls_equal ls1 ls2 -> - let mt, mv = loop bound_vars sigma - (List.rev_append args1 r1) - (List.rev_append args2 r2) in - begin - try Ty.oty_match mt t1.t_ty t2.t_ty, mv - with Ty.TypeMismatch _ -> - raise (NoMatch (Some (t1, t2, None))) - end - | _ -> raise (NoMatch (Some (t1, t2, None))) - end - | Tquant (q1, bv1) -> - begin - match t2.t_node with - | Tquant (q2, bv2) when q1 = q2 -> - let (vl1, _tl1, term1) = t_open_quant bv1 in - let (vl2, _tl2, term2) = t_open_quant bv2 in - let (bound_vars, term1, mt) = - try List.fold_left2 (fun (bound_vars, term1, mt) e1 e2 -> - let mt = Ty.ty_match mt e1.vs_ty e2.vs_ty in - let bound_vars = Mvs.add e2 e1 bound_vars in - (bound_vars,term1, mt)) (bound_vars,term1, mt) vl1 vl2 - with Invalid_argument _ | Ty.TypeMismatch _ -> - raise (NoMatch (Some (t1,t2,None))) +let first_order_matching (vars : Svs.t) (largs : term list) (args : term list) : + Ty.ty Ty.Mtv.t * substitution = + let rec loop bound_vars ((mt, mv) as sigma) largs args = + match (largs, args) with + | [], [] -> sigma + | t1 :: r1, t2 :: r2 -> ( + (* Format.eprintf "matching terms %a and %a...@." Pretty.print_term t1 + Pretty.print_term t2; *) + match t1.t_node with + | Tvar vs when Svs.mem vs vars -> ( + try + let t = Mvs.find vs mv in + if t_equal t t2 + then loop bound_vars sigma r1 r2 + else raise (NoMatch (Some (t1, t2, Some t))) + with Not_found -> ( + try + let ts = Ty.ty_match mt vs.vs_ty (t_type t2) in + let fv2 = t_vars t2 in + if Mvs.is_empty (Mvs.set_inter bound_vars fv2) + then loop bound_vars (ts, Mvs.add vs t2 mv) r1 r2 + else raise (NoMatch (Some (t1, t2, None))) + with Ty.TypeMismatch _ -> raise (NoMatch (Some (t1, t2, None))))) + | Tapp (ls1, args1) -> ( + match t2.t_node with + | Tapp (ls2, args2) when ls_equal ls1 ls2 -> ( + let mt, mv = + loop bound_vars sigma (List.rev_append args1 r1) + (List.rev_append args2 r2) + in + try (Ty.oty_match mt t1.t_ty t2.t_ty, mv) + with Ty.TypeMismatch _ -> raise (NoMatch (Some (t1, t2, None)))) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | Tquant (q1, bv1) -> ( + match t2.t_node with + | Tquant (q2, bv2) when q1 = q2 -> + let vl1, _tl1, term1 = t_open_quant bv1 in + let vl2, _tl2, term2 = t_open_quant bv2 in + let bound_vars, term1, mt = + try + List.fold_left2 + (fun (bound_vars, term1, mt) e1 e2 -> + let mt = Ty.ty_match mt e1.vs_ty e2.vs_ty in + let bound_vars = Mvs.add e2 e1 bound_vars in + (bound_vars, term1, mt)) + (bound_vars, term1, mt) vl1 vl2 + with Invalid_argument _ | Ty.TypeMismatch _ -> + raise (NoMatch (Some (t1, t2, None))) + in + loop bound_vars (mt, mv) (term1 :: r1) (term2 :: r2) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | Tbinop (b1, t1_l, t1_r) -> ( + match t2.t_node with + | Tbinop (b2, t2_l, t2_r) when b1 = b2 -> + loop bound_vars (mt, mv) (t1_l :: t1_r :: r1) (t2_l :: t2_r :: r2) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | Tif (t11, t12, t13) -> ( + match t2.t_node with + | Tif (t21, t22, t23) -> + loop bound_vars (mt, mv) (t11 :: t12 :: t13 :: r1) + (t21 :: t22 :: t23 :: r2) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | Tlet (td1, tb1) -> ( + match t2.t_node with + | Tlet (td2, tb2) -> + let v1, tl1 = t_open_bound tb1 in + let v2, tl2 = t_open_bound tb2 in + let mt = + try Ty.ty_match mt v1.vs_ty v2.vs_ty + with Ty.TypeMismatch _ -> raise (NoMatch (Some (t1, t2, None))) + in + let bound_vars = Mvs.add v2 v1 bound_vars in + loop bound_vars (mt, mv) (td1 :: tl1 :: r1) (td2 :: tl2 :: r2) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | Tcase (ts1, tbl1) -> ( + match t2.t_node with + | Tcase (ts2, tbl2) -> ( + try + let bound_vars, mt, l1, l2 = + List.fold_left2 + (fun (bound_vars, mt, l1, l2) tb1 tb2 -> + let p1, tb1 = t_open_branch tb1 in + let p2, tb2 = t_open_branch tb2 in + let bound_vars, mt = + pattern_renaming (bound_vars, mt) p1 p2 in - loop bound_vars (mt, mv) (term1 :: r1) (term2 :: r2) - | _ -> raise (NoMatch (Some (t1, t2, None))) - end - | Tbinop (b1, t1_l, t1_r) -> - begin - match t2.t_node with - | Tbinop (b2, t2_l, t2_r) when b1 = b2 -> - loop bound_vars (mt, mv) (t1_l :: t1_r :: r1) (t2_l :: t2_r :: r2) - | _ -> raise (NoMatch (Some (t1, t2, None))) - end - | Tif (t11, t12, t13) -> - begin - match t2.t_node with - | Tif (t21, t22, t23) -> - loop bound_vars (mt, mv) (t11 :: t12 :: t13 :: r1) - (t21 :: t22 :: t23 :: r2) - | _ -> raise (NoMatch (Some (t1, t2, None))) - end - | Tlet (td1, tb1) -> - begin - match t2.t_node with - | Tlet (td2, tb2) -> - let (v1, tl1) = t_open_bound tb1 in - let (v2, tl2) = t_open_bound tb2 in - let mt = try Ty.ty_match mt v1.vs_ty v2.vs_ty - with Ty.TypeMismatch _ -> - raise (NoMatch (Some (t1,t2, None))) in - let bound_vars = Mvs.add v2 v1 bound_vars in - loop bound_vars (mt, mv) (td1 :: tl1 :: r1) (td2 :: tl2 :: r2) - | _ -> - raise (NoMatch (Some (t1, t2, None))) - end - | Tcase (ts1, tbl1) -> - begin - match t2.t_node with - | Tcase (ts2, tbl2) -> - begin try - let (bound_vars, mt, l1, l2) = - List.fold_left2 (fun (bound_vars, mt, l1, l2) tb1 tb2 -> - let (p1, tb1) = t_open_branch tb1 in - let (p2, tb2) = t_open_branch tb2 in - let bound_vars, mt = pattern_renaming (bound_vars, mt) p1 p2 in - (bound_vars,mt, tb1 :: l1, tb2 :: l2) - ) (bound_vars,mt, ts1 :: r1, ts2 :: r2) tbl1 tbl2 in - loop bound_vars (mt,mv) l1 l2 - with Invalid_argument _ -> - raise (NoMatch (Some (t1, t2, None))) - end - | _ -> raise (NoMatch (Some (t1, t2, None))) - end - | Teps tb1 -> - begin - match t2.t_node with - | Teps tb2 -> - let (v1, td1) = t_open_bound tb1 in - let (v2, td2) = t_open_bound tb2 in - let mt = try Ty.ty_match mt v1.vs_ty v2.vs_ty - with Ty.TypeMismatch _ -> - raise (NoMatch (Some (t1,t2,None))) in - let bound_vars = Mvs.add v2 v1 bound_vars in - loop bound_vars (mt, mv) (td1 :: r1) (td2 :: r2) - | _ -> raise (NoMatch (Some (t1, t2, None))) - end - - | Tnot t1 -> - begin - match t2.t_node with - | Tnot t2 -> - loop bound_vars sigma (t1 :: r1) (t2 :: r2) - | _ -> raise (NoMatch (Some (t1, t2, None))) - end - | Tvar v1 -> - begin match t2.t_node with - | Tvar v2 -> - begin try - if vs_equal v1 (Mvs.find v2 bound_vars) then - loop bound_vars sigma r1 r2 - else - raise (NoMatch (Some (t1, t2, None))) - with - Not_found -> assert false - end - | _ -> raise (NoMatch (Some (t1, t2, None))) - end - | (Tconst _ | Ttrue | Tfalse) when t_equal t1 t2 -> - loop bound_vars sigma r1 r2 - | Tconst _ | Ttrue | Tfalse -> raise (NoMatch (Some (t1, t2, None))) - end - | _ -> raise (NoMatch None) + (bound_vars, mt, tb1 :: l1, tb2 :: l2)) + (bound_vars, mt, ts1 :: r1, ts2 :: r2) + tbl1 tbl2 + in + loop bound_vars (mt, mv) l1 l2 + with Invalid_argument _ -> raise (NoMatch (Some (t1, t2, None)))) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | Teps tb1 -> ( + match t2.t_node with + | Teps tb2 -> + let v1, td1 = t_open_bound tb1 in + let v2, td2 = t_open_bound tb2 in + let mt = + try Ty.ty_match mt v1.vs_ty v2.vs_ty + with Ty.TypeMismatch _ -> raise (NoMatch (Some (t1, t2, None))) + in + let bound_vars = Mvs.add v2 v1 bound_vars in + loop bound_vars (mt, mv) (td1 :: r1) (td2 :: r2) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | Tnot t1 -> ( + match t2.t_node with + | Tnot t2 -> loop bound_vars sigma (t1 :: r1) (t2 :: r2) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | Tvar v1 -> ( + match t2.t_node with + | Tvar v2 -> ( + try + if vs_equal v1 (Mvs.find v2 bound_vars) + then loop bound_vars sigma r1 r2 + else raise (NoMatch (Some (t1, t2, None))) + with Not_found -> assert false) + | _ -> raise (NoMatch (Some (t1, t2, None)))) + | (Tconst _ | Ttrue | Tfalse) when t_equal t1 t2 -> + loop bound_vars sigma r1 r2 + | Tconst _ | Ttrue | Tfalse -> raise (NoMatch (Some (t1, t2, None)))) + | _ -> raise (NoMatch None) in loop Mvs.empty (Ty.Mtv.empty, Mvs.empty) largs args @@ -656,204 +679,223 @@ let one_step_reduce engine ls args = let rules = Mls.find ls engine.rules in let rec loop rules = match rules with - | [] -> raise Irreducible - | (vars,largs,rhs)::rem -> - begin - try - let sigma = first_order_matching vars largs args in - sigma,rhs - with NoMatch _ -> - loop rem - end - in loop rules - with Not_found -> - raise Irreducible - -let rec matching ((mt,mv) as sigma) t p = + | [] -> raise Irreducible + | (vars, largs, rhs) :: rem -> ( + try + let sigma = first_order_matching vars largs args in + (sigma, rhs) + with NoMatch _ -> loop rem) + in + loop rules + with Not_found -> raise Irreducible + +let rec matching ((mt, mv) as sigma) t p = match p.pat_node with | Pwild -> sigma - | Pvar v -> (mt,Mvs.add v t mv) - | Por(p1,p2) -> - begin - try matching sigma t p1 - with NoMatch _ -> matching sigma t p2 - end - | Pas(p,v) -> matching (mt,Mvs.add v t mv) t p - | Papp(ls1,pl) -> + | Pvar v -> (mt, Mvs.add v t mv) + | Por (p1, p2) -> ( + try matching sigma t p1 with NoMatch _ -> matching sigma t p2) + | Pas (p, v) -> matching (mt, Mvs.add v t mv) t p + | Papp (ls1, pl) -> ( match t.t_node with - | Tapp(ls2,tl) -> - if ls_equal ls1 ls2 then - List.fold_left2 matching sigma tl pl - else - if ls2.ls_constr > 0 then raise (NoMatch None) - else raise Undetermined - | _ -> raise Undetermined - + | Tapp (ls2, tl) -> + if ls_equal ls1 ls2 + then List.fold_left2 matching sigma tl pl + else if ls2.ls_constr > 0 + then raise (NoMatch None) + else raise Undetermined + | _ -> raise Undetermined) let rec extract_first n acc l = - if n = 0 then acc,l else + if n = 0 + then (acc, l) + else match l with - | x :: r -> - extract_first (n-1) (x::acc) r + | x :: r -> extract_first (n - 1) (x :: acc) r | [] -> assert false (** If [t1] matches [i1 < vs] or [i1 <= vs] and [t2] matches [vs < i2] or [vs <= i2], then return the bounds [i1(+1), vs, i2(-1)]. The +1/-1 shift the bounds for strict unequalities operators to obtain inclusive bounds. *) let bounds ls_lt t1 t2 = - let lt order = function (* match [i < vs] or [vs < i], return [i, vs] *) - | {t_node= Tapp (ls, [t1; t2])} when ls_equal ls ls_lt -> ( - assert Ty.(ty_equal (t_type t1) ty_int && ty_equal (t_type t2) ty_int); - match order t1 t2 with - | {t_node= Tconst (Constant.ConstInt {Number.il_int= i})}, - {t_node= Tvar vs} -> - i, vs - | _ -> raise Exit ) - | _ -> raise Exit in - let eq order = function (* match [i = vs] or [vs = i], return [i, vs] *) - | {t_node= Tapp (ls, [t1; t2])} + let lt order = function + (* match [i < vs] or [vs < i], return [i, vs] *) + | { t_node = Tapp (ls, [ t1; t2 ]) } when ls_equal ls ls_lt -> ( + assert (Ty.(ty_equal (t_type t1) ty_int && ty_equal (t_type t2) ty_int)); + match order t1 t2 with + | ( { t_node = Tconst (Constant.ConstInt { Number.il_int = i }) }, + { t_node = Tvar vs } ) -> + (i, vs) + | _ -> raise Exit) + | _ -> raise Exit + in + let eq order = function + (* match [i = vs] or [vs = i], return [i, vs] *) + | { t_node = Tapp (ls, [ t1; t2 ]) } when ls_equal ls Term.ps_equ - && Ty.ty_equal (t_type t1) Ty.ty_int - && Ty.ty_equal (t_type t2) Ty.ty_int -> ( - match order t1 t2 with - | {t_node= Tconst (Constant.ConstInt {Number.il_int= i})}, - {t_node= Tvar vs} when Ty.ty_equal vs.vs_ty Ty.ty_int -> - i, vs - | _ -> raise Exit ) - | _ -> raise Exit in - let le order = function (* match [i <= vs] or [vs <= i], return [i, vs] *) - | {t_node= Tbinop (Tor, t1, t2)} -> - let i, vs = lt order t1 in - let i', vs' = eq order t2 in - if not (BigInt.eq i i' && vs_equal vs vs') then raise Exit; - i, vs - | _ -> raise Exit in - let bound order shift t = (* match [i op vs] or [vs op i], op is [<] or [<=] *) - try le order t with Exit -> + && Ty.ty_equal (t_type t1) Ty.ty_int + && Ty.ty_equal (t_type t2) Ty.ty_int -> ( + match order t1 t2 with + | ( { t_node = Tconst (Constant.ConstInt { Number.il_int = i }) }, + { t_node = Tvar vs } ) + when Ty.ty_equal vs.vs_ty Ty.ty_int -> + (i, vs) + | _ -> raise Exit) + | _ -> raise Exit + in + let le order = function + (* match [i <= vs] or [vs <= i], return [i, vs] *) + | { t_node = Tbinop (Tor, t1, t2) } -> + let i, vs = lt order t1 in + let i', vs' = eq order t2 in + if not (BigInt.eq i i' && vs_equal vs vs') then raise Exit; + (i, vs) + | _ -> raise Exit + in + let bound order shift t = + (* match [i op vs] or [vs op i], op is [<] or [<=] *) + try le order t + with Exit -> let i, vs = lt order t in - shift i, vs in - let i1, vs = bound (fun t1 t2 -> t1, t2) BigInt.succ t1 in - let i2, vs' = bound (fun t1 t2 -> t2, t1) BigInt.pred t2 in + (shift i, vs) + in + let i1, vs = bound (fun t1 t2 -> (t1, t2)) BigInt.succ t1 in + let i2, vs' = bound (fun t1 t2 -> (t2, t1)) BigInt.pred t2 in if not (vs_equal vs vs') then raise Exit; - i1, vs, i2 + (i1, vs, i2) (** [reduce_bounded_quant ls_lt limit t sigma st rem] detects a bounded quantification and reduces it to conjunction: - forall v. a < v < b. t(v) - --> f(a+1) /\ ... /\ f(b-1) + forall v. a < v < b. t(v) --> f(a+1) /\ ... /\ f(b-1) @param ls_lt lsymbol for [int.Int.(<)] + @param limit + Reduce if the difference between upper and lower bound is at most + [limit]. - @param limit Reduce if the difference between upper and lower bound is at - most [limit]. + TODO: - TODO: - - expand to bounded quantifications on range values - - compatiblity with reverse direction (forall i. b > i > a -> t) - - detect SPARK-style [forall i. if a < i /\ i < b then t else true] *) + - expand to bounded quantifications on range values + - compatiblity with reverse direction (forall i. b > i > a -> t) + - detect SPARK-style [forall i. if a < i /\ i < b then t else true] *) let reduce_bounded_quant ls_lt limit t sigma st rem = - match st, rem with (* st = a < vs < b :: _; rem = -> :: forall vs :: _ *) - | Term {t_node= Tbinop (Tand, t1, t2)} :: st, - ((Kbinop Timplies, _) :: (Kquant (Tforall as quant, [vs], _), _) :: rem | - (Kbinop Tand, _) :: (Kquant (Texists as quant, [vs], _), _) :: rem) + match (st, rem) with + (* st = a < vs < b :: _; rem = -> :: forall vs :: _ *) + | ( Term { t_node = Tbinop (Tand, t1, t2) } :: st, + ( (Kbinop Timplies, _) + :: (Kquant ((Tforall as quant), [ vs ], _), _) + :: rem + | (Kbinop Tand, _) :: (Kquant ((Texists as quant), [ vs ], _), _) :: rem + ) ) when Ty.ty_equal vs.vs_ty Ty.ty_int -> - let t_empty, binop = match quant with - | Tforall -> t_true, Tand - | Texists -> t_false, Tor in - let a, vs', b = bounds ls_lt t1 t2 in - if not (vs_equal vs vs') then raise Exit; - if BigInt.(gt (sub b a) (of_int limit)) then raise Exit; - if BigInt.gt a b then (* empty range *) - {value_stack= Term t_empty :: st; cont_stack= rem} - else - let rec loop rem i = - if BigInt.lt i a then - rem - else - let t_i = t_const (Constant.int_const i) Ty.ty_int in - let rem = (* conjunction for all i > a *) - if BigInt.gt i a then (Kbinop binop, t_true) :: rem else rem in - let rem = (Keval (t, Mvs.add vs t_i sigma), t_true) :: rem in - loop rem (BigInt.pred i) in - {value_stack= st; cont_stack= loop rem b} + let t_empty, binop = + match quant with Tforall -> (t_true, Tand) | Texists -> (t_false, Tor) + in + let a, vs', b = bounds ls_lt t1 t2 in + if not (vs_equal vs vs') then raise Exit; + if BigInt.(gt (sub b a) (of_int limit)) then raise Exit; + if BigInt.gt a b + then (* empty range *) + { value_stack = Term t_empty :: st; cont_stack = rem } + else + let rec loop rem i = + if BigInt.lt i a + then rem + else + let t_i = t_const (Constant.int_const i) Ty.ty_int in + let rem = + (* conjunction for all i > a *) + if BigInt.gt i a then (Kbinop binop, t_true) :: rem else rem + in + let rem = (Keval (t, Mvs.add vs t_i sigma), t_true) :: rem in + loop rem (BigInt.pred i) + in + { value_stack = st; cont_stack = loop rem b } | _ -> raise Exit let rec reduce engine c = - match c.value_stack, c.cont_stack with + match (c.value_stack, c.cont_stack) with | _, [] -> assert false - | st, (Keval (t,sigma),orig) :: rem -> ( - let limit = engine.params.compute_max_quantifier_domain in - try reduce_bounded_quant engine.ls_lt limit t sigma st rem with Exit -> - reduce_eval engine st t ~orig sigma rem ) + | st, (Keval (t, sigma), orig) :: rem -> ( + let limit = engine.params.compute_max_quantifier_domain in + try reduce_bounded_quant engine.ls_lt limit t sigma st rem + with Exit -> reduce_eval engine st t ~orig sigma rem) | [], (Kif _, _) :: _ -> assert false - | v :: st, (Kif(t2,t3,sigma), orig) :: rem -> - begin - match v with - | Term { t_node = Ttrue } -> - incr(rec_step_limit); - { value_stack = st ; - cont_stack = (Keval(t2,sigma),t_attr_copy orig t2) :: rem } - | Term { t_node = Tfalse } -> - incr(rec_step_limit); - { value_stack = st ; - cont_stack = (Keval(t3,sigma),t_attr_copy orig t3) :: rem } - | Term t1 -> begin - match t1.t_node , t2.t_node , t3.t_node with - | Tapp (ls,[b0;{ t_node = Tapp (ls1,_) }]) , Tapp(ls2,_) , Tapp(ls3,_) - when ls_equal ls ps_equ && ls_equal ls1 fs_bool_true && - ls_equal ls2 fs_bool_true && ls_equal ls3 fs_bool_false -> - incr(rec_step_limit); - { value_stack = Term (t_attr_copy orig b0) :: st; - cont_stack = rem } - | _ -> - { value_stack = - Term - (t_attr_copy orig - (t_if t1 (t_subst sigma t2) (t_subst sigma t3))) :: st; - cont_stack = rem; - } - end - | (Int _ | Real _) -> assert false (* would be ill-typed *) - end + | v :: st, (Kif (t2, t3, sigma), orig) :: rem -> ( + match v with + | Term { t_node = Ttrue } -> + incr rec_step_limit; + { + value_stack = st; + cont_stack = (Keval (t2, sigma), t_attr_copy orig t2) :: rem; + } + | Term { t_node = Tfalse } -> + incr rec_step_limit; + { + value_stack = st; + cont_stack = (Keval (t3, sigma), t_attr_copy orig t3) :: rem; + } + | Term t1 -> ( + match (t1.t_node, t2.t_node, t3.t_node) with + | ( Tapp (ls, [ b0; { t_node = Tapp (ls1, _) } ]), + Tapp (ls2, _), + Tapp (ls3, _) ) + when ls_equal ls ps_equ && ls_equal ls1 fs_bool_true + && ls_equal ls2 fs_bool_true && ls_equal ls3 fs_bool_false -> + incr rec_step_limit; + { value_stack = Term (t_attr_copy orig b0) :: st; cont_stack = rem } + | _ -> + { + value_stack = + Term + (t_attr_copy orig (t_if t1 (t_subst sigma t2) (t_subst sigma t3))) + :: st; + cont_stack = rem; + }) + | Int _ | Real _ -> assert false (* would be ill-typed *)) | [], (Klet _, _) :: _ -> assert false - | t1 :: st, (Klet(v,t2,sigma), orig) :: rem -> - incr(rec_step_limit); + | t1 :: st, (Klet (v, t2, sigma), orig) :: rem -> + incr rec_step_limit; let t1 = term_of_value t1 in - { value_stack = st; - cont_stack = - (Keval(t2, Mvs.add v t1 sigma), t_attr_copy orig t2) :: rem; + { + value_stack = st; + cont_stack = (Keval (t2, Mvs.add v t1 sigma), t_attr_copy orig t2) :: rem; } | [], (Kcase _, _) :: _ -> assert false | (Int _ | Real _) :: _, (Kcase _, _) :: _ -> assert false - | (Term t1) :: st, (Kcase(tbl,sigma), orig) :: rem -> + | Term t1 :: st, (Kcase (tbl, sigma), orig) :: rem -> reduce_match st t1 ~orig tbl sigma rem - | ([] | [_] | (Int _ | Real _) :: _ | Term _ :: (Int _ | Real _) :: _), - (Kbinop _, _) :: _ -> assert false - | (Term t1) :: (Term t2) :: st, (Kbinop op, orig) :: rem -> - incr(rec_step_limit); - { value_stack = Term (t_attr_copy orig (t_binary_simp op t2 t1)) :: st; + | ( ([] | [ _ ] | (Int _ | Real _) :: _ | Term _ :: (Int _ | Real _) :: _), + (Kbinop _, _) :: _ ) -> + assert false + | Term t1 :: Term t2 :: st, (Kbinop op, orig) :: rem -> + incr rec_step_limit; + { + value_stack = Term (t_attr_copy orig (t_binary_simp op t2 t1)) :: st; cont_stack = rem; } - | [], (Knot,_) :: _ -> assert false - | (Int _ | Real _) :: _ , (Knot,_) :: _ -> assert false - | (Term t) :: st, (Knot, orig) :: rem -> - incr(rec_step_limit); - { value_stack = Term (t_attr_copy orig (t_not_simp t)) :: st; + | [], (Knot, _) :: _ -> assert false + | (Int _ | Real _) :: _, (Knot, _) :: _ -> assert false + | Term t :: st, (Knot, orig) :: rem -> + incr rec_step_limit; + { + value_stack = Term (t_attr_copy orig (t_not_simp t)) :: st; cont_stack = rem; } - | st, (Kapp(ls,ty), orig) :: rem -> - reduce_app engine st ~orig ls ty rem + | st, (Kapp (ls, ty), orig) :: rem -> reduce_app engine st ~orig ls ty rem | [], (Keps _, _) :: _ -> assert false - | (Int _ | Real _) :: _ , (Keps _, _) :: _ -> assert false + | (Int _ | Real _) :: _, (Keps _, _) :: _ -> assert false | Term t :: st, (Keps v, orig) :: rem -> - { value_stack = Term (t_attr_copy orig (t_eps_close v t)) :: st; + { + value_stack = Term (t_attr_copy orig (t_eps_close v t)) :: st; cont_stack = rem; } | [], (Kquant _, _) :: _ -> assert false | (Int _ | Real _) :: _, (Kquant _, _) :: _ -> assert false - | Term t :: st, (Kquant(q,vl,tr), orig) :: rem -> - { value_stack = Term (t_attr_copy orig (t_quant_close_simp q vl tr t)) :: st; + | Term t :: st, (Kquant (q, vl, tr), orig) :: rem -> + { + value_stack = Term (t_attr_copy orig (t_quant_close_simp q vl tr t)) :: st; cont_stack = rem; } @@ -861,310 +903,277 @@ and reduce_match st u ~orig tbl sigma cont = let rec iter tbl = match tbl with | [] -> assert false (* pattern matching not exhaustive *) - | b::rem -> - let p,t = t_open_branch b in + | b :: rem -> ( + let p, t = t_open_branch b in try - let (mt',mv') = matching (Ty.Mtv.empty,sigma) u p in -(* - Format.eprintf "Pattern-matching succeeded:@\nmt' = @["; - Ty.Mtv.iter - (fun tv ty -> Format.eprintf "%a -> %a," - Pretty.print_tv tv Pretty.print_ty ty) - mt'; - Format.eprintf "@]@\n"; - Format.eprintf "mv' = @["; - Mvs.iter - (fun v t -> Format.eprintf "%a -> %a," - Pretty.print_vs v Pretty.print_term t) - mv'; - Format.eprintf "@]@."; - Format.eprintf "branch before inst: %a@." Pretty.print_term t; -*) - let mv'',t = t_subst_types mt' mv' t in -(* - Format.eprintf "branch after types inst: %a@." Pretty.print_term t; - Format.eprintf "mv'' = @["; - Mvs.iter - (fun v t -> Format.eprintf "%a -> %a," - Pretty.print_vs v Pretty.print_term t) - mv''; - Format.eprintf "@]@."; -*) - incr(rec_step_limit); - { value_stack = st; - cont_stack = (Keval(t,mv''), t_attr_copy orig t) :: cont; + let mt', mv' = matching (Ty.Mtv.empty, sigma) u p in + (* Format.eprintf "Pattern-matching succeeded:@\nmt' = @["; Ty.Mtv.iter + (fun tv ty -> Format.eprintf "%a -> %a," Pretty.print_tv tv + Pretty.print_ty ty) mt'; Format.eprintf "@]@\n"; Format.eprintf "mv' + = @["; Mvs.iter (fun v t -> Format.eprintf "%a -> %a," + Pretty.print_vs v Pretty.print_term t) mv'; Format.eprintf "@]@."; + Format.eprintf "branch before inst: %a@." Pretty.print_term t; *) + let mv'', t = t_subst_types mt' mv' t in + (* Format.eprintf "branch after types inst: %a@." Pretty.print_term t; + Format.eprintf "mv'' = @["; Mvs.iter (fun v t -> Format.eprintf "%a + -> %a," Pretty.print_vs v Pretty.print_term t) mv''; Format.eprintf + "@]@."; *) + incr rec_step_limit; + { + value_stack = st; + cont_stack = (Keval (t, mv''), t_attr_copy orig t) :: cont; } - with NoMatch _ -> iter rem + with NoMatch _ -> iter rem) in - try iter tbl with Undetermined -> + try iter tbl + with Undetermined -> let dmy = t_var (create_vsymbol (Ident.id_fresh "__dmy") (t_type u)) in - let tbls = match t_subst sigma (t_case dmy tbl) with - | { t_node = Tcase (_,tbls) } -> tbls + let tbls = + match t_subst sigma (t_case dmy tbl) with + | { t_node = Tcase (_, tbls) } -> tbls | _ -> assert false in - { value_stack = - Term (t_attr_copy orig (t_case u tbls)) :: st; + { + value_stack = Term (t_attr_copy orig (t_case u tbls)) :: st; cont_stack = cont; } - and reduce_eval eng st t ~orig sigma rem = let orig = t_attr_copy orig t in match t.t_node with - | Tvar v -> - begin - match Ident.Mid.find v.vs_name eng.known_map with - | Decl.{d_node = Dlogic dl} -> - incr rec_step_limit ; - let _, ls_defn = List.find (fun (ls, _) -> String.equal ls.ls_name.Ident.id_string v.vs_name.Ident.id_string) dl in - let vs, t = Decl.open_ls_defn ls_defn in - let aux vs t = - (* Create ε fc. λ vs. fc @ vs = t to make the value from - known_map compatible to reduce_func_app *) - let ty = Opt.get t.t_ty in - let app_ty = Ty.ty_func vs.vs_ty ty in - let fc = create_vsymbol (Ident.id_fresh "fc") app_ty in - t_eps - (t_close_bound fc - (t_quant Tforall - (t_close_quant [vs] [] - (t_app ps_equ - [t_app fs_func_app [t_var fc; t_var vs] (Some ty); t] - None)))) in - let t = List.fold_right aux vs t in - {value_stack = Term t :: st; cont_stack = rem} - | _ -> assert false + | Tvar v -> ( + match Ident.Mid.find v.vs_name eng.known_map with + | Decl.{ d_node = Dlogic dl } -> + incr rec_step_limit; + let _, ls_defn = + List.find + (fun (ls, _) -> + String.equal ls.ls_name.Ident.id_string v.vs_name.Ident.id_string) + dl + in + let vs, t = Decl.open_ls_defn ls_defn in + let aux vs t = + (* Create ε fc. λ vs. fc @ vs = t to make the value from known_map + compatible to reduce_func_app *) + let ty = Opt.get t.t_ty in + let app_ty = Ty.ty_func vs.vs_ty ty in + let fc = create_vsymbol (Ident.id_fresh "fc") app_ty in + t_eps + (t_close_bound fc + (t_quant Tforall + (t_close_quant [ vs ] [] + (t_app ps_equ + [ t_app fs_func_app [ t_var fc; t_var vs ] (Some ty); t ] + None)))) + in + let t = List.fold_right aux vs t in + { value_stack = Term t :: st; cont_stack = rem } + | _ -> assert false + | exception Not_found -> ( + match Mvs.find v sigma with + | t -> + incr rec_step_limit; + { value_stack = Term (t_attr_copy orig t) :: st; cont_stack = rem } | exception Not_found -> - match Mvs.find v sigma with - | t -> - incr(rec_step_limit); - { value_stack = Term (t_attr_copy orig t) :: st ; - cont_stack = rem; - } - | exception Not_found -> - (* this may happen, e.g when computing below a quantified formula *) - (* Format.eprintf "Tvar not found: %a@." Pretty.print_vs v; - assert false *) - { value_stack = Term orig :: st ; - cont_stack = rem; - } - end - | Tif(t1,t2,t3) -> - { value_stack = st; - cont_stack = (Keval(t1,sigma),t1) :: (Kif(t2,t3,sigma),orig) :: rem; + (* this may happen, e.g when computing below a quantified formula *) + (* Format.eprintf "Tvar not found: %a@." Pretty.print_vs v; assert + false *) + { value_stack = Term orig :: st; cont_stack = rem })) + | Tif (t1, t2, t3) -> + { + value_stack = st; + cont_stack = (Keval (t1, sigma), t1) :: (Kif (t2, t3, sigma), orig) :: rem; + } + | Tlet (t1, tb) -> + let v, t2 = t_open_bound tb in + { + value_stack = st; + cont_stack = (Keval (t1, sigma), t1) :: (Klet (v, t2, sigma), orig) :: rem; + } + | Tcase (t1, tbl) -> + { + value_stack = st; + cont_stack = (Keval (t1, sigma), t1) :: (Kcase (tbl, sigma), orig) :: rem; } - | Tlet(t1,tb) -> - let v,t2 = t_open_bound tb in - { value_stack = st ; - cont_stack = (Keval(t1,sigma),t1) :: (Klet(v,t2,sigma),orig) :: rem } - | Tcase(t1,tbl) -> - { value_stack = st; - cont_stack = (Keval(t1,sigma),t1) :: (Kcase(tbl,sigma),orig) :: rem } - | Tbinop(op,t1,t2) -> - { value_stack = st; + | Tbinop (op, t1, t2) -> + { + value_stack = st; cont_stack = - (Keval(t1,sigma),t1) :: - (Keval(t2,sigma),t2) :: (Kbinop op, orig) :: rem; + (Keval (t1, sigma), t1) + :: (Keval (t2, sigma), t2) + :: (Kbinop op, orig) :: rem; } | Tnot t1 -> - { value_stack = st; - cont_stack = (Keval(t1,sigma),t1) :: (Knot,orig) :: rem; + { + value_stack = st; + cont_stack = (Keval (t1, sigma), t1) :: (Knot, orig) :: rem; } | Teps tb -> - let v,t1 = t_open_bound tb in - { value_stack = st ; - cont_stack = (Keval(t1,sigma),t1) :: (Keps v,orig) :: rem; + let v, t1 = t_open_bound tb in + { + value_stack = st; + cont_stack = (Keval (t1, sigma), t1) :: (Keps v, orig) :: rem; } - | Tquant(q,tq) -> - let vl,tr,t1 = t_open_quant tq in - { value_stack = st; - cont_stack = (Keval(t1,sigma),t1) :: (Kquant(q,vl,tr),orig) :: rem; + | Tquant (q, tq) -> + let vl, tr, t1 = t_open_quant tq in + { + value_stack = st; + cont_stack = (Keval (t1, sigma), t1) :: (Kquant (q, vl, tr), orig) :: rem; } - | Tapp(ls,tl) -> - let args = List.rev_map (fun t -> (Keval(t,sigma),t)) tl in - { value_stack = st; - cont_stack = List.rev_append args ((Kapp(ls,t.t_ty),orig) :: rem); + | Tapp (ls, tl) -> + let args = List.rev_map (fun t -> (Keval (t, sigma), t)) tl in + { + value_stack = st; + cont_stack = List.rev_append args ((Kapp (ls, t.t_ty), orig) :: rem); } | Ttrue | Tfalse | Tconst _ -> - { value_stack = Term orig :: st; - cont_stack = rem; - } + { value_stack = Term orig :: st; cont_stack = rem } and reduce_app engine st ls ~orig ty rem_cont = - if ls_equal ls ps_equ then + if ls_equal ls ps_equ + then match st with - | t2 :: t1 :: rem_st -> - begin - try - reduce_equ ~orig rem_st t1 t2 rem_cont - with Undetermined -> - reduce_app_no_equ engine st ls ~orig ty rem_cont - end + | t2 :: t1 :: rem_st -> ( + try reduce_equ ~orig rem_st t1 t2 rem_cont + with Undetermined -> reduce_app_no_equ engine st ls ~orig ty rem_cont) | _ -> assert false - else - if ls_equal ls fs_func_app then - match st with - | t2 :: t1 :: rem_st -> - begin - try - reduce_func_app ~orig ty rem_st t1 t2 rem_cont - with Undetermined -> - reduce_app_no_equ engine st ls ~orig ty rem_cont - end - | _ -> assert false - else - reduce_app_no_equ engine st ls ~orig ty rem_cont + else if ls_equal ls fs_func_app + then + match st with + | t2 :: t1 :: rem_st -> ( + try reduce_func_app ~orig ty rem_st t1 t2 rem_cont + with Undetermined -> reduce_app_no_equ engine st ls ~orig ty rem_cont) + | _ -> assert false + else reduce_app_no_equ engine st ls ~orig ty rem_cont and reduce_func_app ~orig _ty rem_st t1 t2 rem_cont = - (* attempt to decompile t1 under the form - (epsilon fc. forall x. fc @ x = body) - that is equivalent to \x.body *) - match t1 with - | Term { t_node = Teps tb } -> - let fc,t = Term.t_open_bound tb in - begin match t.t_node with - | Tquant(Tforall,tq) -> - let vl,trig,t = t_open_quant tq in - let process lhs body equ elim = - let rvl = List.rev vl in - let rec remove_var lhs rvh rvt = match lhs.t_node with - | Tapp (ls2,[lhs1;{t_node = Tvar v1} as arg]) - when ls_equal ls2 fs_func_app && vs_equal v1 rvh -> - begin - match rvt , lhs1 with - | rvh::rvt , _ -> - let lhs1 , fc2 = remove_var lhs1 rvh rvt in - let lhs2 = t_app ls2 [lhs1;arg] lhs.t_ty in - t_attr_copy lhs lhs2 , fc2 - | [] , { t_node = Tvar fc1 } when vs_equal fc1 fc -> - let fcn = fc.vs_name in - let fc2 = Ident.id_derive fcn.Ident.id_string fcn in - let fc2 = create_vsymbol fc2 (t_type lhs) in - t_attr_copy lhs (t_var fc2) , fc2 - | _ -> raise Undetermined - end - | _ -> raise Undetermined - in - begin - match rvl with - | rvh :: rvt -> let lhs , fc2 = remove_var lhs rvh rvt in - let (vh,vl) = match vl with - | [] -> assert false - | vh::vl -> (vh,vl) - in - let t2 = term_of_value t2 in - begin - match vl with - | [] -> elim body vh t2 - | _ -> - let eq = equ lhs body in - let tq = t_quant Tforall (t_close_quant vl trig eq) in - let body = t_attr_copy t (t_eps_close fc2 tq) in - { value_stack = rem_st; - cont_stack = - (Keval(body,Mvs.add vh t2 Mvs.empty), - t_attr_copy orig body) :: rem_cont; - } - end + (* attempt to decompile t1 under the form (epsilon fc. forall x. fc @ x = + body) that is equivalent to \x.body *) + match t1 with + | Term { t_node = Teps tb } -> ( + let fc, t = Term.t_open_bound tb in + match t.t_node with + | Tquant (Tforall, tq) -> ( + let vl, trig, t = t_open_quant tq in + let process lhs body equ elim = + let rvl = List.rev vl in + let rec remove_var lhs rvh rvt = + match lhs.t_node with + | Tapp (ls2, [ lhs1; ({ t_node = Tvar v1 } as arg) ]) + when ls_equal ls2 fs_func_app && vs_equal v1 rvh -> ( + match (rvt, lhs1) with + | rvh :: rvt, _ -> + let lhs1, fc2 = remove_var lhs1 rvh rvt in + let lhs2 = t_app ls2 [ lhs1; arg ] lhs.t_ty in + (t_attr_copy lhs lhs2, fc2) + | [], { t_node = Tvar fc1 } when vs_equal fc1 fc -> + let fcn = fc.vs_name in + let fc2 = Ident.id_derive fcn.Ident.id_string fcn in + let fc2 = create_vsymbol fc2 (t_type lhs) in + (t_attr_copy lhs (t_var fc2), fc2) + | _ -> raise Undetermined) | _ -> raise Undetermined - end in - begin - match t.t_node with - | Tapp (ls1,[lhs;body]) when ls_equal ls1 ps_equ -> - let equ lhs body = t_attr_copy t (t_app ps_equ [lhs;body] None) in - let elim body vh t2 = { + match rvl with + | rvh :: rvt -> ( + let lhs, fc2 = remove_var lhs rvh rvt in + let vh, vl = + match vl with [] -> assert false | vh :: vl -> (vh, vl) + in + let t2 = term_of_value t2 in + match vl with + | [] -> elim body vh t2 + | _ -> + let eq = equ lhs body in + let tq = t_quant Tforall (t_close_quant vl trig eq) in + let body = t_attr_copy t (t_eps_close fc2 tq) in + { value_stack = rem_st; cont_stack = - (Keval(body,Mvs.add vh t2 Mvs.empty), - t_attr_copy orig body) :: rem_cont; - } in - process lhs body equ elim - | Tbinop (Tiff, - ({t_node=Tapp (ls1,[lhs;tr])} as teq), - body) - when ls_equal ls1 ps_equ && t_equal tr t_bool_true -> - let equ lhs body = - let lhs = t_attr_copy teq (t_app ps_equ [lhs;tr] None) in - t_attr_copy t (t_binary Tiff lhs body) in - let elim body vh t2 = - let body = t_if body t_bool_true t_bool_false in - { value_stack = rem_st; - cont_stack = - (Keval(body,Mvs.add vh t2 Mvs.empty), - t_attr_copy orig body) :: rem_cont } in - process lhs body equ elim - | _ -> raise Undetermined - end - | _ -> raise Undetermined - end - | _ -> raise Undetermined + (Keval (body, Mvs.add vh t2 Mvs.empty), t_attr_copy orig body) + :: rem_cont; + }) + | _ -> raise Undetermined + in + match t.t_node with + | Tapp (ls1, [ lhs; body ]) when ls_equal ls1 ps_equ -> + let equ lhs body = t_attr_copy t (t_app ps_equ [ lhs; body ] None) in + let elim body vh t2 = + { + value_stack = rem_st; + cont_stack = + (Keval (body, Mvs.add vh t2 Mvs.empty), t_attr_copy orig body) + :: rem_cont; + } + in + process lhs body equ elim + | Tbinop (Tiff, ({ t_node = Tapp (ls1, [ lhs; tr ]) } as teq), body) + when ls_equal ls1 ps_equ && t_equal tr t_bool_true -> + let equ lhs body = + let lhs = t_attr_copy teq (t_app ps_equ [ lhs; tr ] None) in + t_attr_copy t (t_binary Tiff lhs body) + in + let elim body vh t2 = + let body = t_if body t_bool_true t_bool_false in + { + value_stack = rem_st; + cont_stack = + (Keval (body, Mvs.add vh t2 Mvs.empty), t_attr_copy orig body) + :: rem_cont; + } + in + process lhs body equ elim + | _ -> raise Undetermined) + | _ -> raise Undetermined) + | _ -> raise Undetermined and reduce_app_no_equ engine st ls ~orig ty rem_cont = let arity = List.length ls.ls_args in - let args,rem_st = extract_first arity [] st in + let args, rem_st = extract_first arity [] st in try - let f = Hls.find builtins ls in - let v = f ls args ty in - { value_stack = (v_attr_copy orig v) :: rem_st; - cont_stack = rem_cont; - } - with Not_found | Undetermined -> + let f = Hls.find engine.builtins ls in + let v = f engine ls args ty in + { value_stack = v_attr_copy orig v :: rem_st; cont_stack = rem_cont } + with Not_found | Undetermined -> ( let args = List.map term_of_value args in match Ident.Mid.find ls.ls_name engine.known_map with | exception Not_found -> Format.eprintf "Reduction engine, ident not found: %s@." - ls.ls_name.Ident.id_string ; - { value_stack = Term (t_attr_copy orig (t_app ls args ty)) :: rem_st; + ls.ls_name.Ident.id_string; + { + value_stack = Term (t_attr_copy orig (t_app ls args ty)) :: rem_st; cont_stack = rem_cont; } - | d -> + | d -> ( let rewrite () = - (* try a rewrite rule *) + (* try a rewrite rule *) try -(* - Format.eprintf "try a rewrite rule on %a@." Pretty.print_ls ls; -*) - let (mt,mv),rhs = one_step_reduce engine ls args in -(* - Format.eprintf "rhs = %a@." Pretty.print_term rhs; - Format.eprintf "sigma = "; - Mvs.iter - (fun v t -> Format.eprintf "%a -> %a," - Pretty.print_vs v Pretty.print_term t) - (snd sigma); - Format.eprintf "@."; - Format.eprintf "try a type match: %a and %a@." - (Pp.print_option Pretty.print_ty) ty - (Pp.print_option Pretty.print_ty) rhs.t_ty; -*) -(* - let type_subst = Ty.oty_match Ty.Mtv.empty rhs.t_ty ty in - Format.eprintf "subst of rhs: "; - Ty.Mtv.iter - (fun tv ty -> Format.eprintf "%a -> %a," - Pretty.print_tv tv Pretty.print_ty ty) - type_subst; - Format.eprintf "@."; - let rhs = t_ty_subst type_subst Mvs.empty rhs in - let sigma = - Mvs.map (t_ty_subst type_subst Mvs.empty) sigma - in - Format.eprintf "rhs = %a@." Pretty.print_term rhs; - Format.eprintf "sigma = "; - Mvs.iter - (fun v t -> Format.eprintf "%a -> %a," - Pretty.print_vs v Pretty.print_term t) - sigma; - Format.eprintf "@."; -*) - let mv,rhs = t_subst_types mt mv rhs in - incr(rec_step_limit); - { value_stack = rem_st; - cont_stack = (Keval(rhs,mv),orig) :: rem_cont; + (* Format.eprintf "try a rewrite rule on %a@." Pretty.print_ls ls; *) + let (mt, mv), rhs = one_step_reduce engine ls args in + (* Format.eprintf "rhs = %a@." Pretty.print_term rhs; Format.eprintf + "sigma = "; Mvs.iter (fun v t -> Format.eprintf "%a -> %a," + Pretty.print_vs v Pretty.print_term t) (snd sigma); Format.eprintf + "@."; Format.eprintf "try a type match: %a and %a@." + (Pp.print_option Pretty.print_ty) ty (Pp.print_option + Pretty.print_ty) rhs.t_ty; *) + (* let type_subst = Ty.oty_match Ty.Mtv.empty rhs.t_ty ty in + Format.eprintf "subst of rhs: "; Ty.Mtv.iter (fun tv ty -> + Format.eprintf "%a -> %a," Pretty.print_tv tv Pretty.print_ty ty) + type_subst; Format.eprintf "@."; let rhs = t_ty_subst type_subst + Mvs.empty rhs in let sigma = Mvs.map (t_ty_subst type_subst + Mvs.empty) sigma in Format.eprintf "rhs = %a@." Pretty.print_term + rhs; Format.eprintf "sigma = "; Mvs.iter (fun v t -> Format.eprintf + "%a -> %a," Pretty.print_vs v Pretty.print_term t) sigma; + Format.eprintf "@."; *) + let mv, rhs = t_subst_types mt mv rhs in + incr rec_step_limit; + { + value_stack = rem_st; + cont_stack = (Keval (rhs, mv), orig) :: rem_cont; } with Irreducible -> - { value_stack = Term (t_attr_copy orig (t_app ls args ty)) :: rem_st; + { + value_stack = Term (t_attr_copy orig (t_app ls args ty)) :: rem_st; cont_stack = rem_cont; } in @@ -1173,273 +1182,238 @@ and reduce_app_no_equ engine st ls ~orig ty rem_cont = | Decl.Dlogic dl -> (* regular definition *) let d = List.assq ls dl in - if engine.params.compute_defs || - Term.Sls.mem ls engine.params.compute_def_set - then begin - let vl,e = Decl.open_ls_defn d in - let add (mt,mv) x y = - Ty.ty_match mt x.vs_ty (t_type y), Mvs.add x y mv + if engine.params.compute_defs + || Term.Sls.mem ls engine.params.compute_def_set + then + let vl, e = Decl.open_ls_defn d in + let add (mt, mv) x y = + (Ty.ty_match mt x.vs_ty (t_type y), Mvs.add x y mv) in - let (mt,mv) = List.fold_left2 add (Ty.Mtv.empty, Mvs.empty) vl args in + let mt, mv = List.fold_left2 add (Ty.Mtv.empty, Mvs.empty) vl args in let mt = Ty.oty_match mt e.t_ty ty in - let mv,e = t_subst_types mt mv e in - { value_stack = rem_st; - cont_stack = (Keval(e,mv),orig) :: rem_cont; + let mv, e = t_subst_types mt mv e in + { + value_stack = rem_st; + cont_stack = (Keval (e, mv), orig) :: rem_cont; } - end else rewrite () - | Decl.Dparam _ | Decl.Dind _ -> - rewrite () - | Decl.Ddata dl -> + else rewrite () + | Decl.Dparam _ | Decl.Dind _ -> rewrite () + | Decl.Ddata dl -> ( (* constructor or projection *) - begin try match args with - | [ { t_node = Tapp(ls1,tl1) } ] -> - (* if ls is a projection and ls1 is a constructor, - we should compute that projection *) - let rec iter dl = - match dl with - | [] -> raise Exit - | (_,csl) :: rem -> - let rec iter2 csl = - match csl with - | [] -> iter rem - | (cs,prs) :: rem2 -> - if ls_equal cs ls1 - then - (* we found the right constructor *) - let rec iter3 prs tl1 = - match prs,tl1 with - | (Some pr)::prs, t::tl1 -> - if ls_equal ls pr - then (* projection found! *) - { value_stack = - (Term (t_attr_copy orig t)) :: rem_st; - cont_stack = rem_cont; - } - else - iter3 prs tl1 - | None::prs, _::tl1 -> - iter3 prs tl1 - | _ -> raise Exit - in iter3 prs tl1 - else iter2 rem2 - in iter2 csl - in iter dl - | _ -> raise Exit - with Exit -> rewrite () end - - -and reduce_equ (* engine *) ~orig st v1 v2 cont = -(* - try -*) - match v1,v2 with - | Int n1, Int n2 -> - let b = to_bool (BigInt.eq n1 n2) in - incr(rec_step_limit); - { value_stack = Term (t_attr_copy orig b) :: st; - cont_stack = cont; - } - | Real r1, Real r2 -> - let b = to_bool (Number.compare_real r1 r2 = 0) in - incr rec_step_limit; - { value_stack = Term (t_attr_copy orig b) :: st; - cont_stack = cont; - } - | Int n, Term {t_node = Tconst c} | Term {t_node = Tconst c}, Int n -> - begin - try - let n' = big_int_of_const c in - let b = to_bool (BigInt.eq n n') in - incr(rec_step_limit); - { value_stack = Term (t_attr_copy orig b) :: st; - cont_stack = cont; - } - with NotNum -> raise Undetermined - end - | Real r, Term {t_node = Tconst c} | Term {t_node = Tconst c}, Real r -> - begin try - let r' = real_of_const c in - let b = to_bool (Number.compare_real r r' = 0) in - incr rec_step_limit; - { value_stack = Term (t_attr_copy orig b) :: st; - cont_stack = cont; - } - with NotNum -> raise Undetermined - end - | Real _, Term _ | Term _, Real _ -> raise Undetermined - | Int _, Term _ | Term _, Int _ -> raise Undetermined - | Int _, Real _ | Real _, Int _ -> assert false - | Term t1, Term t2 -> reduce_term_equ ~orig st t1 t2 cont -(* - with Undetermined -> - { value_stack = Term (t_equ (term_of_value v1) (term_of_value v2)) :: st; - cont_stack = cont; - } -*) + match args with + | [ { t_node = Tapp (ls1, tl1) } ] -> + (* if ls is a projection and ls1 is a constructor, we should compute + that projection *) + let rec iter dl = + match dl with + | [] -> raise Exit + | (_, csl) :: rem -> + let rec iter2 csl = + match csl with + | [] -> iter rem + | (cs, prs) :: rem2 -> + if ls_equal cs ls1 + then + (* we found the right constructor *) + let rec iter3 prs tl1 = + match (prs, tl1) with + | Some pr :: prs, t :: tl1 -> + if ls_equal ls pr + then + (* projection found! *) + { + value_stack = Term (t_attr_copy orig t) :: rem_st; + cont_stack = rem_cont; + } + else iter3 prs tl1 + | None :: prs, _ :: tl1 -> iter3 prs tl1 + | _ -> raise Exit + in + iter3 prs tl1 + else iter2 rem2 + in + iter2 csl + in + iter dl + | _ -> raise Exit + with Exit -> rewrite ()))) + +and reduce_equ ~(* engine *) orig st v1 v2 cont = + (* try *) + match (v1, v2) with + | Int n1, Int n2 -> + let b = to_bool (BigInt.eq n1 n2) in + incr rec_step_limit; + { value_stack = Term (t_attr_copy orig b) :: st; cont_stack = cont } + | Real r1, Real r2 -> + let b = to_bool (Number.compare_real r1 r2 = 0) in + incr rec_step_limit; + { value_stack = Term (t_attr_copy orig b) :: st; cont_stack = cont } + | Int n, Term { t_node = Tconst c } | Term { t_node = Tconst c }, Int n -> ( + try + let n' = big_int_of_const c in + let b = to_bool (BigInt.eq n n') in + incr rec_step_limit; + { value_stack = Term (t_attr_copy orig b) :: st; cont_stack = cont } + with NotNum -> raise Undetermined) + | Real r, Term { t_node = Tconst c } | Term { t_node = Tconst c }, Real r -> ( + try + let r' = real_of_const c in + let b = to_bool (Number.compare_real r r' = 0) in + incr rec_step_limit; + { value_stack = Term (t_attr_copy orig b) :: st; cont_stack = cont } + with NotNum -> raise Undetermined) + | Real _, Term _ | Term _, Real _ -> raise Undetermined + | Int _, Term _ | Term _, Int _ -> raise Undetermined + | Int _, Real _ | Real _, Int _ -> assert false + | Term t1, Term t2 -> reduce_term_equ ~orig st t1 t2 cont +(* with Undetermined -> { value_stack = Term (t_equ (term_of_value v1) + (term_of_value v2)) :: st; cont_stack = cont; } *) and reduce_term_equ ~orig st t1 t2 cont = - if t_equal t1 t2 then - let () = incr(rec_step_limit) in - { value_stack = Term (t_attr_copy orig t_true) :: st; - cont_stack = cont; - } + if t_equal t1 t2 + then + let () = incr rec_step_limit in + { value_stack = Term (t_attr_copy orig t_true) :: st; cont_stack = cont } else - match (t1.t_node,t2.t_node) with - | Tconst c1, Tconst c2 -> - begin - match c1,c2 with + match (t1.t_node, t2.t_node) with + | Tconst c1, Tconst c2 -> ( + match (c1, c2) with | Constant.ConstInt i1, Constant.ConstInt i2 -> - let b = - BigInt.eq i1.Number.il_int i2.Number.il_int + let b = BigInt.eq i1.Number.il_int i2.Number.il_int in + incr rec_step_limit; + { + value_stack = Term (t_attr_copy orig (to_bool b)) :: st; + cont_stack = cont; + } + | _ -> raise Undetermined) + | Tapp (ls1, tl1), Tapp (ls2, tl2) + when ls1.ls_constr > 0 && ls2.ls_constr > 0 -> + if ls_equal ls1 ls2 + then + let rec aux sigma t tyl l1 l2 = + match (tyl, l1, l2) with + | [], [], [] -> (sigma, t) + | ty :: tyl, t1 :: tl1, t2 :: tl2 -> + let v1 = create_vsymbol (Ident.id_fresh "") ty in + let v2 = create_vsymbol (Ident.id_fresh "") ty in + aux + (Mvs.add v1 t1 (Mvs.add v2 t2 sigma)) + (t_and_simp (t_equ (t_var v1) (t_var v2)) t) + tyl tl1 tl2 + | _ -> assert false in - incr(rec_step_limit); - { value_stack = Term (t_attr_copy orig (to_bool b)) :: st; + let sigma, t = aux Mvs.empty t_true ls1.ls_args tl1 tl2 in + let () = incr rec_step_limit in + { value_stack = st; cont_stack = (Keval (t, sigma), orig) :: cont } + else + { + value_stack = Term (t_attr_copy orig t_false) :: st; cont_stack = cont; } - | _ -> raise Undetermined - end - | Tapp(ls1,tl1), Tapp(ls2,tl2) when ls1.ls_constr > 0 && ls2.ls_constr > 0 -> - if ls_equal ls1 ls2 then - let rec aux sigma t tyl l1 l2 = - match tyl,l1,l2 with - | [],[],[] -> sigma,t - | ty::tyl, t1::tl1, t2::tl2 -> - let v1 = create_vsymbol (Ident.id_fresh "") ty in - let v2 = create_vsymbol (Ident.id_fresh "") ty in - aux - (Mvs.add v1 t1 (Mvs.add v2 t2 sigma)) - (t_and_simp (t_equ (t_var v1) (t_var v2)) t) - tyl tl1 tl2 - | _ -> assert false - in - let sigma,t = - aux Mvs.empty t_true ls1.ls_args tl1 tl2 - in - let () = incr(rec_step_limit) in - { value_stack = st; - cont_stack = (Keval(t,sigma),orig) :: cont; - } - else - { value_stack = Term (t_attr_copy orig t_false) :: st; - cont_stack = cont; - } - | Tif (b,{ t_node = Tapp(ls1,_) },{ t_node = Tapp(ls2,_) }) , Tapp(ls3,_) - when ls_equal ls3 fs_bool_true && ls_equal ls1 fs_bool_true && - ls_equal ls2 fs_bool_false -> - incr(rec_step_limit); - { value_stack = Term (t_attr_copy orig b) :: st; - cont_stack = cont } - | _ -> raise Undetermined - - + | ( Tif (b, { t_node = Tapp (ls1, _) }, { t_node = Tapp (ls2, _) }), + Tapp (ls3, _) ) + when ls_equal ls3 fs_bool_true && ls_equal ls1 fs_bool_true + && ls_equal ls2 fs_bool_false -> + incr rec_step_limit; + { value_stack = Term (t_attr_copy orig b) :: st; cont_stack = cont } + | _ -> raise Undetermined let rec reconstruct c = - match c.value_stack, c.cont_stack with - | [Term t], [] -> t + match (c.value_stack, c.cont_stack) with + | [ Term t ], [] -> t | _, [] -> assert false - | _, (k,orig) :: rem -> + | _, (k, orig) :: rem -> let t, st = - match c.value_stack, k with - | st, Keval (t,sigma) -> (t_subst sigma t), st + match (c.value_stack, k) with + | st, Keval (t, sigma) -> (t_subst sigma t, st) | [], Kif _ -> assert false - | v :: st, Kif(t2,t3,sigma) -> - (t_if (term_of_value v) (t_subst sigma t2) (t_subst sigma t3)), st + | v :: st, Kif (t2, t3, sigma) -> + (t_if (term_of_value v) (t_subst sigma t2) (t_subst sigma t3), st) | [], Klet _ -> assert false - | t1 :: st, Klet(v,t2,sigma) -> - (t_let_close v (term_of_value t1) (t_subst sigma t2)), st + | t1 :: st, Klet (v, t2, sigma) -> + (t_let_close v (term_of_value t1) (t_subst sigma t2), st) | [], Kcase _ -> assert false - | v :: st, Kcase(tbl,sigma) -> - (t_subst sigma (t_case (term_of_value v) tbl)), st - | ([] | [_]), Kbinop _ -> assert false + | v :: st, Kcase (tbl, sigma) -> + (t_subst sigma (t_case (term_of_value v) tbl), st) + | ([] | [ _ ]), Kbinop _ -> assert false | t1 :: t2 :: st, Kbinop op -> - (t_binary_simp op (term_of_value t2) (term_of_value t1)), st + (t_binary_simp op (term_of_value t2) (term_of_value t1), st) | [], Knot -> assert false - | t :: st, Knot -> (t_not (term_of_value t)), st - | st, Kapp(ls,ty) -> - let args,rem_st = extract_first (List.length ls.ls_args) [] st in + | t :: st, Knot -> (t_not (term_of_value t), st) + | st, Kapp (ls, ty) -> + let args, rem_st = extract_first (List.length ls.ls_args) [] st in let args = List.map term_of_value args in - (t_app ls args ty), rem_st + (t_app ls args ty, rem_st) | [], Keps _ -> assert false - | t :: st, Keps v -> (t_eps_close v (term_of_value t)), st + | t :: st, Keps v -> (t_eps_close v (term_of_value t), st) | [], Kquant _ -> assert false - | t :: st, Kquant(q,vl,tr) -> - (t_quant_close_simp q vl tr (term_of_value t)), st + | t :: st, Kquant (q, vl, tr) -> + (t_quant_close_simp q vl tr (term_of_value t), st) in - reconstruct { - value_stack = (Term (t_attr_copy orig t)) :: st; - cont_stack = rem; - } - + reconstruct + { value_stack = Term (t_attr_copy orig t) :: st; cont_stack = rem } (** iterated reductions *) let normalize ?step_limit ~limit engine sigma t0 = rec_step_limit := 0; let rec many_steps c n = - match c.value_stack, c.cont_stack with - | [Term t], [] -> t + match (c.value_stack, c.cont_stack) with + | [ Term t ], [] -> t | _, [] -> assert false - | _ -> - if n = limit then - begin - let t1 = reconstruct c in - (* Loc.warning "reduction of term %a takes more than %d steps, aborted at %a.@." - * Pretty.print_term t0 limit Pretty.print_term t1; *) - t1 - end - else begin + | _ -> ( + if n = limit + then + let t1 = reconstruct c in + (* Loc.warning "reduction of term %a takes more than %d steps, aborted at %a.@." + * Pretty.print_term t0 limit Pretty.print_term t1; *) + t1 + else match step_limit with | None -> - let c = reduce engine c in - many_steps c (n+1) + let c = reduce engine c in + many_steps c (n + 1) | Some step_limit -> - if !rec_step_limit >= step_limit then - reconstruct c - else - let c = reduce engine c in - many_steps c (n+1) - end - in - let c = { value_stack = []; - cont_stack = [Keval(t0,sigma),t0] ; - } + if !rec_step_limit >= step_limit + then reconstruct c + else + let c = reduce engine c in + many_steps c (n + 1)) in + let c = { value_stack = []; cont_stack = [ (Keval (t0, sigma), t0) ] } in many_steps c 0 (* the rewrite engine *) let create p env km = - if p.compute_builtin - then get_builtins env - else Hls.clear builtins; - let th = Env.read_theory env ["int"] "Int" in - let ls_lt = Theory.ns_find_ls th.Theory.th_export [Ident.op_infix "<"] in - { known_map = km ; - rules = Mls.empty; - params = p; - ls_lt; - } + let th = Env.read_theory env [ "int" ] "Int" in + let ls_lt = Theory.ns_find_ls th.Theory.th_export [ Ident.op_infix "<" ] in + let env = + { + env; + known_map = km; + rules = Mls.empty; + params = p; + ls_lt; + builtins = Hls.create 17; + caisar_env = read_caisar_env env; + } + in + if p.compute_builtin then get_builtins env; + env exception NotARewriteRule of string let extract_rule _km t = -(* - let check_ls ls = - try let _ = Hls.find builtins ls in - raise (NotARewriteRule "root of lhs of rule must not be a built-in symbol") - with Not_found -> - let d = Ident.Mid.find ls.ls_name km in - match d.Decl.d_node with - | Decl.Dtype _ | Decl.Dprop _ -> assert false - | Decl.Dlogic _ -> - raise (NotARewriteRule "root of lhs of rule must not be defined symbol") - | Decl.Ddata _ -> - raise (NotARewriteRule "root of lhs of rule must not be a constructor nor a projection") - | Decl.Dparam _ | Decl.Dind _ -> () - in -*) - + (* let check_ls ls = try let _ = Hls.find builtins ls in raise + (NotARewriteRule "root of lhs of rule must not be a built-in symbol") with + Not_found -> let d = Ident.Mid.find ls.ls_name km in match d.Decl.d_node + with | Decl.Dtype _ | Decl.Dprop _ -> assert false | Decl.Dlogic _ -> raise + (NotARewriteRule "root of lhs of rule must not be defined symbol") | + Decl.Ddata _ -> raise (NotARewriteRule "root of lhs of rule must not be a + constructor nor a projection") | Decl.Dparam _ | Decl.Dind _ -> () in *) let check_vars acc t1 t2 = (* check that quantified variables all appear in the lefthand side (quantified variables not appearing could be removed and those appearing @@ -1450,46 +1424,38 @@ let extract_rule _km t = (* check the same with type variables *) if not (Ty.Stv.subset - (t_ty_freevars Ty.Stv.empty t2) (t_ty_freevars Ty.Stv.empty t2)) + (t_ty_freevars Ty.Stv.empty t2) + (t_ty_freevars Ty.Stv.empty t2)) then raise (NotARewriteRule "lhs should contain all type variables") - in + let rec aux acc t = match t.t_node with - | Tquant(Tforall,q) -> - let vs,_,t = t_open_quant q in - aux (List.fold_left (fun acc v -> Svs.add v acc) acc vs) t - | Tbinop(Tiff,t1,t2) -> - begin - match t1.t_node with - | Tapp(ls,args) -> - (* check_ls ls; *) - check_vars acc t1 t2; - acc,ls,args,t2 - | _ -> raise - (NotARewriteRule "lhs of <-> should be a predicate symbol") - end - | Tapp(ls,[t1;t2]) when ls == ps_equ -> - begin - match t1.t_node with - | Tapp(ls,args) -> - (* check_ls ls; *) - check_vars acc t1 t2; - acc,ls,args,t2 - | _ -> raise - (NotARewriteRule "lhs of = should be a function symbol") - end - | _ -> raise - (NotARewriteRule "rule should be of the form forall ... t1 = t2 or f1 <-> f2") + | Tquant (Tforall, q) -> + let vs, _, t = t_open_quant q in + aux (List.fold_left (fun acc v -> Svs.add v acc) acc vs) t + | Tbinop (Tiff, t1, t2) -> ( + match t1.t_node with + | Tapp (ls, args) -> + (* check_ls ls; *) + check_vars acc t1 t2; + (acc, ls, args, t2) + | _ -> raise (NotARewriteRule "lhs of <-> should be a predicate symbol")) + | Tapp (ls, [ t1; t2 ]) when ls == ps_equ -> ( + match t1.t_node with + | Tapp (ls, args) -> + (* check_ls ls; *) + check_vars acc t1 t2; + (acc, ls, args, t2) + | _ -> raise (NotARewriteRule "lhs of = should be a function symbol")) + | _ -> + raise + (NotARewriteRule + "rule should be of the form forall ... t1 = t2 or f1 <-> f2") in aux Svs.empty t - let add_rule t e = - let vars,ls,args,r = extract_rule e.known_map t in - let rules = - try Mls.find ls e.rules - with Not_found -> [] - in - {e with rules = - Mls.add ls ((vars,args,r)::rules) e.rules} + let vars, ls, args, r = extract_rule e.known_map t in + let rules = try Mls.find ls e.rules with Not_found -> [] in + { e with rules = Mls.add ls ((vars, args, r) :: rules) e.rules } diff --git a/src/reduction_engine.mli b/src/reduction_engine.mli index 282ee55a69e8deaf540a05cc206bf3c7693507e1..da1f53c62c412f2273f7f44f5c679598bd042922 100644 --- a/src/reduction_engine.mli +++ b/src/reduction_engine.mli @@ -9,116 +9,109 @@ (* *) (********************************************************************) - (** A reduction engine for Why3 terms *) -(* -terms are normalized with respect to +(* terms are normalized with respect to -1) built-in computation rules + 1) built-in computation rules - a) on propositional connectives, e.g. + a) on propositional connectives, e.g. f /\ true -> f - b) on integers, e.g. + b) on integers, e.g. 35 + 7 -> 42 - c) on projections of pairs and of other ADTs, e.g - - fst (x,y) -> x - - cdr (Cons x y) -> y + c) on projections of pairs and of other ADTs, e.g - d) on defined function symbols, e.g. + fst (x,y) -> x - function sqr (x:int) = x * x + cdr (Cons x y) -> y - sqr 4 -> 4 * 4 -> 16 + d) on defined function symbols, e.g. - sqr x -> x * x + function sqr (x:int) = x * x - e) (TODO?) on booleans, e.g. + sqr 4 -> 4 * 4 -> 16 - True xor False -> True + sqr x -> x * x - f) (TODO?) on reals, e.g. + e) (TODO?) on booleans, e.g. - 1.0 + 2.5 -> 3.5 + True xor False -> True -2) axioms declared as rewrite rules, thanks to the "rewrite" metas, e.g. if + f) (TODO?) on reals, e.g. - function dot : t -> t -> t - axiom assoc: forall x y z, dot (dot x y) z = dot x (dot y z) - meta "rewrite" assoc + 1.0 + 2.5 -> 3.5 - then + 2) axioms declared as rewrite rules, thanks to the "rewrite" metas, e.g. if - dot (dot a b) (dot c d) -> dot a (dot b (dot c d)) + function dot : t -> t -> t axiom assoc: forall x y z, dot (dot x y) z = dot x + (dot y z) meta "rewrite" assoc - axioms used as rewrite rules must be either of the form + then - forall ... t1 = t2 + dot (dot a b) (dot c d) -> dot a (dot b (dot c d)) - or + axioms used as rewrite rules must be either of the form - forall ... f1 <-> f2 + forall ... t1 = t2 - where the root symbol of t1 (resp. f1) is a non-interpreted function - symbol (resp. non-interpreted predicate symbol) + or - rewriting is done from left to right + forall ... f1 <-> f2 + where the root symbol of t1 (resp. f1) is a non-interpreted function symbol + (resp. non-interpreted predicate symbol) -*) + rewriting is done from left to right *) open Why3 type engine (** abstract type for reduction engines *) +val print_caisar_op : engine Fmt.t + type params = { compute_defs : bool; compute_builtin : bool; compute_def_set : Term.Sls.t; compute_max_quantifier_domain : int; } -(** Configuration of the engine. - . [compute_defs]: if set to true, automatically compute symbols using - known definitions. Otherwise, only symbols in [compute_def_set] - will be computed. - . [compute_builtin]: if set to true, compute builtin functions. - . [compute_max_quantifier_domain]: maximum domain size for the reduction of - bounded quantifications *) +(** Configuration of the engine. . [compute_defs]: if set to true, automatically + compute symbols using known definitions. Otherwise, only symbols in + [compute_def_set] will be computed. . [compute_builtin]: if set to true, + compute builtin functions. . [compute_max_quantifier_domain]: maximum domain + size for the reduction of bounded quantifications *) val create : params -> Env.env -> Decl.decl Ident.Mid.t -> engine -(** [create env known_map] creates a reduction engine with - . builtins theories (int.Int, etc.) extracted from [env] - . known declarations from [known_map] - . empty set of rewrite rules -*) +(** [create env known_map] creates a reduction engine with . builtins theories + (int.Int, etc.) extracted from [env] . known declarations from [known_map] . + empty set of rewrite rules *) exception NotARewriteRule of string val add_rule : Term.term -> engine -> engine -(** [add_rule t e] turns [t] into a new rewrite rule and returns the - new engine. - - raise NotARewriteRule if [t] cannot be seen as a rewrite rule - according to the general rules given above. -*) - - -val normalize : ?step_limit:int -> limit:int -> engine -> Term.term Term.Mvs.t -> Term.term -> Term.term -(** [normalize e sigma t] normalizes the term [t] with respect to the engine - [e] with an initial variable environment [sigma]. - - parameter [limit] provides a maximum number of steps for execution. - When limit is reached, the partially reduced term is returned. - parameter [step_limit] provides a maximum number of steps on reductions - that would change the term even after reconstruction. -*) - +(** [add_rule t e] turns [t] into a new rewrite rule and returns the new engine. + + raise NotARewriteRule if [t] cannot be seen as a rewrite rule according to + the general rules given above. *) + +val normalize : + ?step_limit:int -> + limit:int -> + engine -> + Term.term Term.Mvs.t -> + Term.term -> + Term.term +(** [normalize e sigma t] normalizes the term [t] with respect to the engine [e] + with an initial variable environment [sigma]. + + parameter [limit] provides a maximum number of steps for execution. When + limit is reached, the partially reduced term is returned. parameter + [step_limit] provides a maximum number of steps on reductions that would + change the term even after reconstruction. *) open Term @@ -130,4 +123,5 @@ exception NoMatchpat of (pattern * pattern) option type substitution = term Mvs.t -val first_order_matching: Svs.t -> term list -> term list -> Ty.ty Ty.Mtv.t * substitution +val first_order_matching : + Svs.t -> term list -> term list -> Ty.ty Ty.Mtv.t * substitution diff --git a/stdlib/caisar.mlw b/stdlib/caisar.mlw index aeea7093ede433c836821d58fd184d9c7097a2e4..b26ab6d5bbbbe90f36e7ee4bd3a20a14f669dfc1 100644 --- a/stdlib/caisar.mlw +++ b/stdlib/caisar.mlw @@ -80,3 +80,13 @@ theory NN function relu (a: t): t = if a .> (0.0:t) then a else (0.0:t) end + +theory Interpret + + type dataset + + function open_dataset string: dataset + + function size dataset: int + +end diff --git a/tests/datasets/a/a001.png b/tests/datasets/a/a001.png new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/datasets/a/a002.png b/tests/datasets/a/a002.png new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/interpretation.t b/tests/interpretation.t index 0b75c826af7a22cc00c6e072224bc1f34b221616..133dd62f4e0ffda3d35c58bbd27b0462e8a371cf 100644 --- a/tests/interpretation.t +++ b/tests/interpretation.t @@ -1,13 +1,35 @@ Test verify $ caisar interpret -L . --format whyml - 2>&1 <<EOF | ./filter_tmpdir.sh > theory T + > use caisar.Interpret > use int.Int > > goal G1: 1+1=2 > > goal G2: 1+1=3 > + > goal G3: size (open_dataset "datasets/a") = 2 + > + > goal G4: + > let dataset = open_dataset "datasets/a" in + > size dataset = 2 + > + > > end > EOF G1 : true + G2 : false + + Reduction engine, ident not found: infix = + G3 : caisar_op = 2 + caisar_op1, + (Reduction_engine.Dataset { Reduction_engine.dataset = "datasets/a" }) + caisar_op, + (Reduction_engine.Size { Reduction_engine.dataset = "datasets/a" }) + Reduction engine, ident not found: infix = + G4 : caisar_op2 = 2 + caisar_op3, + (Reduction_engine.Dataset { Reduction_engine.dataset = "datasets/a" }) + caisar_op2, + (Reduction_engine.Size { Reduction_engine.dataset = "datasets/a" })