diff --git a/src/bin/dune b/src/bin/dune deleted file mode 100644 index a168a58d3c216ebc6891f3301118b3937547d219..0000000000000000000000000000000000000000 --- a/src/bin/dune +++ /dev/null @@ -1,13 +0,0 @@ -; main binary - -(executable - (modes byte exe) - (name witan) - (public_name witan) - (libraries containers gen dolmen cmdliner spelll witan.core - witan.solver witan.theories.bool witan.theories.LRA) - (preprocess - (pps ppx_optcomp)) - (flags :standard -w +a-4-42-44-48-50-58-32-60@8 -color always) - (ocamlopt_flags :standard -O3 -color always -unbox-closures - -unbox-closures-factor 20)) diff --git a/src/bin/options.ml b/src/bin/options.ml deleted file mode 100644 index 45c3f932c68652c8af2966163eacf3219f61b24d..0000000000000000000000000000000000000000 --- a/src/bin/options.ml +++ /dev/null @@ -1,212 +0,0 @@ -(*************************************************************************) -(* This file is part of Colibrics. *) -(* *) -(* Copyright (C) 2017 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(*************************************************************************) - -(* Option types *) -(* ************************************************************************ *) - -type language = Witan_solver.Input.language - -type input_options = { - dir : string; - file : string; - language : language option; -} - -type t = { - - input : input_options; - - (* typing *) - type_only : bool; - - (* Time/Memory options *) - time_limit : float; - size_limit : float; - - (* Step options *) - step_limit : int; - - (* seed for shuffling *) - seed_shuffle : int option; - - (* debug flags *) - debug_flags : Witan_popop_lib.Debug.flag list; -} - -(* Creating option records *) -(* ************************************************************************ *) - -let mk_input_options f language = - let dir = Filename.dirname f in - let file = Filename.basename f in - { dir; file; language; } - -let mk input time_limit size_limit step_limit type_only seed_shuffle debug_flags = - { input; time_limit; size_limit; step_limit; type_only; seed_shuffle; debug_flags } - -(* Argument converters *) -(* ************************************************************************ *) - -let input = Cmdliner.Arg.enum Witan_solver.Input.enum - -(* Argument converter for integer with multiplier suffix *) -(* ************************************************************************ *) - -let nb_sec_minute = 60 -let nb_sec_hour = 60 * nb_sec_minute -let nb_sec_day = 24 * nb_sec_hour - -let print_aux suffix fmt n = - if n = 0 then () - else Format.fprintf fmt "%d%s" n suffix - -let print_time fmt f = - let n = int_of_float f in - let aux n div = n / div, n mod div in - let n_day, n = aux n nb_sec_day in - let n_hour, n = aux n nb_sec_hour in - let n_min, n = aux n nb_sec_minute in - Format.fprintf fmt "%a%a%a%a" - (print_aux "d") n_day - (print_aux "h") n_hour - (print_aux "m") n_min - (print_aux "s") n - -let parse_time arg = - let l = String.length arg in - let multiplier m = - let arg1 = String.sub arg 0 (l-1) in - `Ok (m *. (float_of_string arg1)) - in - assert (l > 0); - try - match arg.[l-1] with - | 's' -> multiplier 1. - | 'm' -> multiplier 60. - | 'h' -> multiplier 3600. - | 'd' -> multiplier 86400. - | '0'..'9' -> `Ok (float_of_string arg) - | _ -> `Error "bad numeric argument" - with Failure _ -> `Error "bad numeric argument" - -let print_size fmt f = - let n = int_of_float f in - let aux n div = n / div, n mod div in - let n_tera, n = aux n 1_000_000_000_000 in - let n_giga, n = aux n 1_000_000_000 in - let n_mega, n = aux n 1_000_000 in - let n_kilo, n = aux n 1_000 in - Format.fprintf fmt "%a%a%a%a%a" - (print_aux "To") n_tera - (print_aux "Go") n_giga - (print_aux "Mo") n_mega - (print_aux "ko") n_kilo - (print_aux "") n - -let parse_size arg = - let l = String.length arg in - let multiplier m = - let arg1 = String.sub arg 0 (l-1) in - `Ok (m *. (float_of_string arg1)) - in - assert (l > 0); - try - match arg.[l-1] with - | 'k' -> multiplier 1e3 - | 'M' -> multiplier 1e6 - | 'G' -> multiplier 1e9 - | 'T' -> multiplier 1e12 - | '0'..'9' -> `Ok (float_of_string arg) - | _ -> `Error "bad numeric argument" - with Failure _ -> `Error "bad numeric argument" - -let c_time = parse_time, print_time -let c_size = parse_size, print_size - -(* Debug option *) -let debug_flags_options = "DEBUG FLAGS" - -let debug = - let list_flags = - List.map (fun (name,flag,_,desc) -> - let doc = Format.asprintf "%a" Witan_popop_lib.Pp.formatted desc in - let info = Cmdliner.Arg.info ["debug-"^name] ~doc ~docs:debug_flags_options in - flag, info - ) - (Witan_popop_lib.Debug.list_flags ()) - - in - Cmdliner.Arg.(value & vflag_all [] list_flags) - - -(* Command terms *) -(* ************************************************************************ *) - -let common_options = "COMMON OPTIONS" - -let man = [ - `S common_options; - `P "Common options for the prover"; - `S debug_flags_options; -] - -let info = Cmdliner.Term.(info ~man ~sdocs:common_options ~version:"0.1" "witan") - -let input_options = - let docs = common_options in - let fd = - let doc = "Input problem file" in - Cmdliner.Arg.(required & pos 0 (some non_dir_file) None & info [] ~docv:"FILE" ~doc) - in - let language = - let doc = Format.asprintf - "Set the format for the input file to $(docv) (%s)." - (Cmdliner.Arg.doc_alts_enum ~quoted:false Witan_solver.Input.enum) in - Cmdliner.Arg.(value & opt (some input) None & info ["i"; "input"] ~docs ~docv:"INPUT" ~doc) - in - Cmdliner.Term.(const mk_input_options $ fd $ language) - -let all = - let docs = common_options in - let time = - let doc = {|Stop the program after a time lapse of $(docv). - Accepts usual suffixes for durations : s,m,h,d. - Without suffix, default to a time in seconds.|} in - Cmdliner.Arg.(value & opt c_time 300. & info ["t"; "time"] ~docs ~docv:"TIME" ~doc) - in - let size = - let doc = {|Stop the program if it tries and use more the $(docv) memory space. - Accepts usual suffixes for sizes : k,M,G,T. - Without suffix, default to a size in octet.|} in - Cmdliner.Arg.(value & opt c_size 1_000_000_000. & info ["s"; "size"] ~docs ~docv:"SIZE" ~doc) - in - let step = - let doc = {|Stop the program if it tries and use more the $(docv) steps.|} in - Cmdliner.Arg.(value & opt int (-1) & info ["steps"] ~docs ~docv:"STEPS" ~doc) - in - let seed = - let doc = {|Give a seed for the randomness used in the search (default fixed).|} in - Cmdliner.Arg.(value & opt (some int) None & info ["seed"] ~docs ~docv:"STEPS" ~doc) - in - let type_only = - let doc = {|Stop the program after parsing and typing.|} in - Cmdliner.Arg.(value & flag & info ["type-only"] ~doc) - in - Cmdliner.Term.(const mk $ input_options $ time $ size $ step $ type_only $ seed $ debug) diff --git a/src/bin/options.mli b/src/bin/options.mli deleted file mode 100644 index 20224552e273d928764227df1db1201f0bef56da..0000000000000000000000000000000000000000 --- a/src/bin/options.mli +++ /dev/null @@ -1,66 +0,0 @@ -(*************************************************************************) -(* This file is part of Colibrics. *) -(* *) -(* Copyright (C) 2017 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(*************************************************************************) - -(** Command line options *) - - -(** {2 Type definitions} *) - -type language = Witan_solver.Input.language -(** Type of format input (taken from dolmen). *) - -type input_options = { - dir : string; - file : string; - language : language option; -} -(** The various input options. *) - -type t = { - - input : input_options; - - (* typing *) - type_only : bool; - - (* Time/Memory options *) - time_limit : float; - size_limit : float; - - (* Step options *) - step_limit : int; - - (* seed for shuffling *) - seed_shuffle : int option; - - (* debug flags *) - debug_flags : Witan_popop_lib.Debug.flag list; -} -(** The aggregate type for all command line options *) - - -(** {2 Parsing command line} *) - -val all : t Cmdliner.Term.t -(** The cdmliner term for parsing all command line options. *) - -val info : Cmdliner.Term.info -(** The cmdliner info for parsing command line (includes bin name, version, etc..) *) - diff --git a/src/bin/typecheck.ml b/src/bin/typecheck.ml deleted file mode 100644 index 179c03c98120a3046637810c3d31316c3c2ba983..0000000000000000000000000000000000000000 --- a/src/bin/typecheck.ml +++ /dev/null @@ -1,936 +0,0 @@ -(*************************************************************************) -(* This file is part of Witan. *) -(* *) -(* Copyright (C) 2017 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* INRIA (Institut National de Recherche en Informatique et en *) -(* Automatique) *) -(* CNRS (Centre national de la recherche scientifique) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(*************************************************************************) - -(* Log&Module Init *) -(* ************************************************************************ *) - -module Id = Dolmen.Id -module Ast = Dolmen.Term - -module I = Witan_core.Id -module Term = Witan_core.Term - -let get_loc = - let default_loc = Dolmen.ParseLocation.mk "<?>" 0 0 0 0 in - (fun t -> CCOpt.get_or ~default:default_loc t.Ast.loc) - -module E = Map.Make(Term.Id) -module R = Hashtbl.Make(Term.Id) - -(* Fuzzy search maps *) -(* ************************************************************************ *) - -module M = struct - - module S = Spelll - module I = S.Index - - (** We use fuzzy maps in order to give suggestions in case of typos. - Since such maps are not trivial to extend to Dolmen identifiers, - we map strings (identifier names) to list of associations. *) - type 'a t = (Id.t * 'a) list I.t - - let eq = Id.equal - - let empty = I.empty - - let get t id = - let s = Id.(id.name) in - match S.klist_to_list (I.retrieve ~limit:0 t s) with - | [l] -> l - | [] -> [] - | _ -> assert false - - let mem id t = - CCList.Assoc.mem ~eq id (get t id) - - let find id t = - CCList.Assoc.get_exn ~eq id (get t id) - - let add id v t = - let l = get t id in - let l' = CCList.Assoc.set ~eq id v l in - I.add t Dolmen.Id.(id.name) l' - - let iter f t = - I.iter (fun _ l -> List.iter (fun (id, v) -> f id v) l) t - - (** Return a list of suggestions for an identifier. *) - let suggest ~limit id t = - let s = Id.(id.name) in - let l = S.klist_to_list (I.retrieve ~limit t s) in - CCList.flat_map (List.map fst) l - -end - -(* Fuzzy search hashtables *) -(* ************************************************************************ *) - -module H = struct - - (** Fuzzy hashtables are just references to fuzzy maps. - The reference is registered on the stack to allow backtracking. *) - let create () = - let r = ref M.empty in - r - - let mem r id = M.mem id !r - - let find r id = M.find id !r - - let suggest r id = M.suggest id !r - - let add r id v = - r := M.add id v !r - -end - -(* Types *) -(* ************************************************************************ *) - -(* The type of reasons for constant typing *) -type reason = - | Inferred of Dolmen.ParseLocation.t - | Declared of Dolmen.ParseLocation.t - -(* The local environments used for type-checking. *) -type env = { - - (* Map from term identifiers to the reason of their type - (either definition location, or inference location) *) - locs : reason E.t; - - (* Bound variables, either let-bound, or quantified. *) - vars : Term.t M.t; - - (* The current builtin symbols *) - builtins : builtin_symbols; - - (* Additional typing info *) - expect : Term.t option; (** Expected type of the term to parse *) - explain : [ `No | `Yes | `Full ]; -} - -(* Builtin symbols, i.e symbols understood by some theories, - but which do not have specific syntax, so end up as special - cases of application. *) -and builtin_symbols = env -> Dolmen.Term.t -> Dolmen.Id.t -> Ast.t list -> Term.t option - -(* Global Environment *) -(* ************************************************************************ *) - -(* Global identifier table; stores declared types and aliases. - global locations : stores reason for typing of identifiers *) -let global_env = H.create () -let global_locs = R.create 4013 - -let find_global name = - try H.find global_env name - with Not_found -> `Not_found - -(* Symbol declarations *) -let decl_id id c reason = - (* TODO: uncomment - if H.mem global_env id then - Util.warn ~section - "Symbol '%a' has already been defined, overwriting previous definition" - Id.print id; - *) - H.add global_env id (`Id c); - R.add global_locs c reason - -(* Symbol definitions *) -let def_id id args body = - (* TODO: uncomment - if H.mem global_env id then - Util.warn ~section - "Symbol '%a' has already been defined, overwriting previous definition" - Id.print id; - *) - H.add global_env id (`Alias (args, body)) - - -(* Local Environment *) -(* ************************************************************************ *) - -(* Make a new empty environment *) -let empty_env - ?(expect=None) - ?(explain=`No) - builtins = { - locs = E.empty; - vars = M.empty; - builtins; expect; explain; -} - -let expect ?(force=false) env expect = - if env.expect = None && not force then env - else { env with expect = expect } - -(* Generate new fresh names for shadowed variables *) -let new_name pre = - let i = ref 0 in - (fun () -> incr i; pre ^ (string_of_int !i)) - -let new_term_name = new_name "t#" - -(* Add local bound variables to env *) -let add_let_term env id t = - { env with vars = M.add id t env.vars } - -(* Add local variables to environment *) -let add_term_var env id v loc = - let v' = - if M.mem id env.vars then - I.mk (new_term_name ()) (I.ty v) - else - v - in - let t = Term.const v' in - v', { env with - vars = M.add id t env.vars; - locs = E.add v' (Declared loc) env.locs; - } - -let find_var env name = - try Some (M.find name env.vars) - with Not_found -> None - -(* Printing *) -let print_expect fmt = function - | None -> Format.fprintf fmt "<>" - | Some ty -> Term.print fmt ty - -let print_map print fmt map = - let aux k v = - Format.fprintf fmt "%a ->@ @[<hov>%a@];@ " Id.print k print v - in - M.iter aux map - -let pp_env fmt env = - Format.fprintf fmt "@[<hov 2>(%a) %a%a%a%a@]" - print_expect env.expect (print_map Term.print) env.vars - -(* Typo suggestion *) -(* ************************************************************************ *) - -let suggest ~limit env fmt id = - let l = - M.suggest ~limit id env.vars @ - H.suggest ~limit global_env id - in - if l = [] then - Format.fprintf fmt "coming up empty, sorry, ^^" - else - CCFormat.list Id.print fmt l - -(* Typing explanation *) -(* ************************************************************************ *) - -let get_reason_loc = function Inferred l | Declared l -> l - -let pp_reason fmt = function - | Inferred loc -> Format.fprintf fmt "inferred at %a" Dolmen.ParseLocation.fmt loc - | Declared loc -> Format.fprintf fmt "declared at %a" Dolmen.ParseLocation.fmt loc - -let find_reason env v = - try E.find v env.locs - with Not_found -> R.find global_locs v - -let rec explain ~full env fmt t = - try - begin match t with - | { Term.term = Term.Type; _ } -> - Format.fprintf fmt "Type: Type" - | { Term.term = Term.Id v; _ } -> - let reason = find_reason env v in - Format.fprintf fmt "%a: %a was %a@\n" I.print v Term.print (I.ty v) pp_reason reason - | { Term.term = Term.App (f, t); _ } -> - explain ~full env fmt f; - if full then explain ~full env fmt t - | { Term.term = Term.Let (v, e, body); _ } -> - Format.fprintf fmt "Term let-bound to %a was typed %a@\n" - I.print v Term.print e.Term.ty - | { Term.term = Term.Binder (_, _, t); _ } -> - explain ~full env fmt t - end with - | Not_found -> - Format.fprintf fmt "Couldn't find a typing reason (that's a bug !)" - -(* Exceptions *) -(* ************************************************************************ *) - -(* Internal exception *) -exception Found of Ast.t * Term.t option - -(* Exception for typing errors *) -exception Typing_error of string * env * Ast.t - -(* Creating explanations *) -let mk_expl preface env fmt t = - match env.explain with - | `No -> () - | `Yes -> - Format.fprintf fmt "%s\n%a" preface (explain ~full:false env) t - | `Full -> - Format.fprintf fmt "%s\n%a" preface (explain ~full:true env) t - -(* Convenience functions *) -let _infer_var env t = - let msg = Format.asprintf - "Inferring type for a variable, please check the scope of your quantifications" - in - raise (Typing_error (msg, env, t)) - -let _expected env s t res = - let msg = match res with - | None -> "the expression doesn't match what was expected" - | Some r -> - let ty = r.Term.ty in - let tmp = - match r with - | { Term.term = Term.Type; _} -> "the Ttype constant" - | _ when Term.equal ty Term._Type -> "a type" - | _ when Term.equal ty Term._Prop -> "a first-order formula" - | _ -> "a first-order term" - in - Format.sprintf "got %s" tmp - in - let msg = Format.asprintf "Expected a %s, but %s" s msg in - raise (Typing_error (msg, env, t)) - -let _bad_op_arity env s n t = - let msg = Format.asprintf "Bad arity for operator '%s' (expected %d arguments)" s n in - raise (Typing_error (msg, env, t)) - -let _bad_id_arity env id n t = - let msg = Format.asprintf - "Bad arity for identifier '%a' (expected %d arguments)" Id.print id n - in - raise (Typing_error (msg, env, t)) - -let _bad_term_arity env f n t = - let msg = Format.asprintf - "Bad arity for function '%a' (expected %d arguments)" I.print f n - in - raise (Typing_error (msg, env, t)) - -let _fo_let env s t = - let msg = Format.asprintf "Let-bound variable '%a' is applied to terms" Id.print s in - raise (Typing_error (msg, env, t)) - -let _fo_formula env f ast = - let msg = Format.asprintf "Cannot apply formula '%a' to arguments" Term.print f in - raise (Typing_error (msg, env, ast)) - -let _type_mismatch env t ty ty' ast = - let msg = Format.asprintf - "Type Mismatch: an expression of type %a was expected, but '%a' has type %a%a" - Term.print ty' Term.print t Term.print ty (mk_expl ", because:" env) t - in - raise (Typing_error (msg, env, ast)) - -let _cannot_unify env ast ty t = - let msg = Format.asprintf - "A term of type '%a'@ was expected, but could not unify it with@ %a:@ %a" - Term.print ty Term.print t Term.print t.Term.ty - in - raise (Typing_error (msg, env, ast)) - -let _cannot_infer_quant_var env t = - raise (Typing_error ("Cannot infer the type of a quantified variable", env, t)) - -(* Wrappers for expression building *) -(* ************************************************************************ *) - -(* Generate fresh variables for wildcards in types. *) -let gen_wildcard = - let i = ref 0 in - (function () -> (* TODO: add location information? *) - incr i; I.mk (Format.sprintf "?%d" !i) Term._Type) - -let wildcard = - (fun env ast id l -> - match l with - | [] -> - let v = gen_wildcard () in - Term.const v - | _ -> _bad_id_arity env id 0 ast - ) - -(* Wrapper around term application. Since wildcards are allowed in types, - there may be some variables in [ty_args], so we have to find an appropriate - substitution for these variables. To do that, we try and unify the expected type - and the actual argument types. *) -let term_apply env ast f ty_args t_args = - if List.length Expr.(f.id_type.fun_vars) <> List.length ty_args || - List.length Expr.(f.id_type.fun_args) <> List.length t_args then - _bad_term_arity env f (arity f) ast - else - let map = - List.fold_left2 - Mapping.Var.bind_ty Mapping.empty - Expr.(f.id_type.fun_vars) ty_args - in - let expected_types = - List.map (Mapping.apply_ty map) Expr.(f.id_type.fun_args) - in - let subst = - List.fold_left2 (fun subst expected term -> - try - Unif.Robinson.ty subst expected Expr.(term.t_type) - with - | Unif.Robinson.Impossible_ty _ -> - _cannot_unify env ast expected term - ) map expected_types t_args - in - let actual_ty_args = List.map (Mapping.apply_ty subst) ty_args in - try - Expr.Term.apply ~status:env.status f actual_ty_args t_args - with - | Expr.Bad_arity _ | Expr.Type_mismatch _ -> - Util.debug ~section "%a, typing:@\n %a :: %a :: %a@\nsubst: %a" - Dolmen.ParseLocation.fmt (get_loc ast) Expr.Print.const_ty f - (CCFormat.list Expr.Print.ty) ty_args - (CCFormat.list Expr.Print.term) t_args - Mapping.print subst; - assert false - -let ty_subst env ast_term id args f_args body = - match List.fold_left2 Expr.Subst.Id.bind Expr.Subst.empty f_args args with - | subst -> - Expr.Ty.subst subst Expr.Subst.empty body - | exception Invalid_argument _ -> - _bad_id_arity env id (List.length f_args) ast_term - -let term_subst env ast_term id ty_args t_args f_ty_args f_t_args body = - match List.fold_left2 Expr.Subst.Id.bind Expr.Subst.empty f_ty_args ty_args with - | ty_subst -> - begin - match List.fold_left2 Expr.Subst.Id.bind Expr.Subst.empty f_t_args t_args with - | t_subst -> - Expr.Term.subst ty_subst Expr.Subst.empty t_subst Expr.Subst.empty body - | exception Invalid_argument _ -> - _bad_id_arity env id (List.length f_ty_args + List.length f_t_args) ast_term - end - | exception Invalid_argument _ -> - _bad_id_arity env id (List.length f_ty_args + List.length f_t_args) ast_term - -let make_eq env ast_term a b = - try - Expr.Formula.eq a b - with Expr.Type_mismatch (t, ty, ty') -> - _type_mismatch env t ty ty' ast_term - -let make_pred env ast_term p = - try - Expr.Formula.pred p - with Expr.Type_mismatch (t, ty, ty') -> - _type_mismatch env t ty ty' ast_term - -let mk_quant_ty env mk vars body = - (* Check that all quantified variables are actually used *) - let fv_ty, fv_t = Expr.Formula.fv body in - let unused = List.filter (fun v -> not @@ CCList.mem ~eq:Expr.Id.equal v fv_ty) vars in - List.iter (fun v -> - Util.warn "%a:@\nQuantified variables unused: %a" - Dolmen.ParseLocation.fmt (get_reason_loc (E.find v env.type_locs)) - Expr.Print.id v) unused; - mk vars body - -let mk_quant_term env mk vars body = - (* Check that all quantified variables are actually used *) - let fv_ty, fv_t = Expr.Formula.fv body in - let unused = List.filter (fun v -> not @@ CCList.mem ~eq:Expr.Id.equal v fv_t) vars in - List.iter (fun v -> - Util.warn "%a:@\nQuantified variables unused: %a" - Dolmen.ParseLocation.fmt (get_reason_loc (F.find v env.term_locs)) - Expr.Print.id v) unused; - mk vars body - -let promote env ast t = - match t with - | Term t when Expr.(Ty.equal Ty.prop t.t_type) -> - Formula (make_pred env ast t) - | _ -> t - -let infer env ast s args loc = - if Dolmen.Id.(s.ns = Var) then _infer_var env ast; - match env.expect with - | Nothing -> None - | Type -> - let n = List.length args in - let ret = Expr.Id.ty_fun (Id.full_name s) n in - let res = Ty_fun ret in - env.infer_hook env res; - decl_ty_cstr s ret (Inferred loc); - Some res - | Typed ty -> - let n = List.length args in - let ret = Expr.Id.term_fun (Id.full_name s) [] (CCList.replicate n Expr.Ty.base) ty in - let res = Term_fun ret in - env.infer_hook env res; - decl_term s ret (Inferred loc); - Some res - - -(* Tag application *) -(* ************************************************************************ *) - -let apply_tag env ast tag v = function - | Ttype -> raise (Typing_error ("Cannot tag Ttype", env, ast)) - | Tags _ -> raise (Typing_error ("Cannot tag a tag list", env, ast)) - | Ty ty -> Expr.Ty.tag ty tag v - | Term t -> Expr.Term.tag t tag v - | Formula f -> Expr.Formula.tag f tag v - -(* Expression parsing *) -(* ************************************************************************ *) - -let rec parse_expr (env : env) t = - Util.debug ~section - "parsing: @[<hov>%a@]@\nin env: @[<hov>%a@]" - Ast.print t pp_env env; - let res = match t with - - (* Ttype & builtin types *) - | { Ast.term = Ast.Builtin Ast.Ttype } -> - Ttype - | { Ast.term = Ast.Builtin Ast.Prop } -> - Ty Expr.Ty.prop - - (* Wildcards (only allowed in types *) - | { Ast.term = Ast.Builtin Ast.Wildcard } -> - Ty (Expr.Ty.of_id (gen_wildcard ())) - - (* Basic formulas *) - | { Ast.term = Ast.App ({ Ast.term = Ast.Builtin Ast.True }, []) } - | { Ast.term = Ast.Builtin Ast.True } -> - Formula Expr.Formula.f_true - - | { Ast.term = Ast.App ({ Ast.term = Ast.Builtin Ast.False }, []) } - | { Ast.term = Ast.Builtin Ast.False } -> - Formula Expr.Formula.f_false - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.And}, l) } -> - Formula (Expr.Formula.f_and (List.map (parse_formula env) l)) - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Or}, l) } -> - Formula (Expr.Formula.f_or (List.map (parse_formula env) l)) - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Xor}, l) } as t -> - begin match l with - | [p; q] -> - let f = parse_formula env p in - let g = parse_formula env q in - Formula (Expr.Formula.neg (Expr.Formula.equiv f g)) - | _ -> _bad_op_arity env "xor" 2 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Imply}, l) } as t -> - begin match l with - | [p; q] -> - let f = parse_formula env p in - let g = parse_formula env q in - Formula (Expr.Formula.imply f g) - | _ -> _bad_op_arity env "=>" 2 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Equiv}, l) } as t -> - begin match l with - | [p; q] -> - let f = parse_formula env p in - let g = parse_formula env q in - Formula (Expr.Formula.equiv f g) - | _ -> _bad_op_arity env "<=>" 2 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Not}, l) } as t -> - begin match l with - | [p] -> - Formula (Expr.Formula.neg (parse_formula env p)) - | _ -> _bad_op_arity env "not" 1 t - end - - (* Binders *) - | { Ast.term = Ast.Binder (Ast.All, vars, f) } -> - let ttype_vars, ty_vars, env' = - parse_quant_vars (expect env (Typed Expr.Ty.base)) vars in - Formula ( - mk_quant_ty env' Expr.Formula.allty ttype_vars - (mk_quant_term env' Expr.Formula.all ty_vars - (parse_formula env' f))) - - | { Ast.term = Ast.Binder (Ast.Ex, vars, f) } -> - let ttype_vars, ty_vars, env' = - parse_quant_vars (expect env (Typed Expr.Ty.base)) vars in - Formula ( - mk_quant_ty env' Expr.Formula.exty ttype_vars - (mk_quant_term env' Expr.Formula.ex ty_vars - (parse_formula env' f))) - - (* (Dis)Equality *) - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Eq}, l) } as t -> - begin match l with - | [a; b] -> - begin match promote env t @@ parse_expr env a, - promote env t @@ parse_expr env b with - | Term t1, Term t2 -> - Formula (make_eq env t t1 t2) - | Formula f1, Formula f2 -> - Formula (Expr.Formula.equiv f1 f2) - | _ -> - _expected env "either two terms or two formulas" t None - end - | _ -> _bad_op_arity env "=" 2 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Distinct}, args) } as t -> - let l' = List.map (parse_term env) args in - let l'' = CCList.diagonal l' in - let l''' = List.map (fun (a, b) -> Expr.Formula.neg (make_eq env t a b)) l'' in - let f = match l''' with - | [f] -> f - | _ -> Expr.Formula.f_and l''' - in - Formula f - - (* General case: application *) - | { Ast.term = Ast.Symbol s } as ast -> - parse_app env ast s [] - | { Ast.term = Ast.App ({ Ast.term = Ast.Symbol s }, l) } as ast -> - parse_app env ast s l - - (* Local bindings *) - | { Ast.term = Ast.Binder (Ast.Let, vars, f) } -> - parse_let env f vars - - (* Other cases *) - | ast -> raise (Typing_error ("Unexpected construction", env, ast)) - in - apply_attr env res t t.Ast.attr - -and apply_attr env res ast l = - let () = List.iter (function - | Any (tag, v) -> - apply_tag env ast tag v res; - ) (parse_attrs env ast [] l) in - res - -and parse_attr_and env ast = - match ast with - | { Ast.term = Ast.App ({ Ast.term = Ast.Builtin Ast.And}, l) } -> - parse_attrs env ast [] l - | _ -> parse_attrs env ast [] [ast] - -and parse_attrs env ast acc = function - | [] -> acc - | a :: r -> - begin match parse_expr (expect env Nothing) a with - | Tags l -> - parse_attrs env ast (l @ acc) r - | res -> - _expected env "tag" a (Some res) - | exception (Typing_error (msg, _, t)) -> - Util.warn ~section "%a while parsing an attribute:@\n%s" - Dolmen.ParseLocation.fmt (get_loc t) msg; - parse_attrs env ast acc r - end - -and parse_var env = function - | { Ast.term = Ast.Colon ({ Ast.term = Ast.Symbol s }, e) } -> - begin match parse_expr env e with - | Ttype -> `Ty (s, Expr.Id.ttype (Id.full_name s)) - | Ty ty -> `Term (s, Expr.Id.ty (Id.full_name s) ty) - | res -> _expected env "type (or Ttype)" e (Some res) - end - | { Ast.term = Ast.Symbol s } as t -> - begin match env.expect with - | Nothing -> _cannot_infer_quant_var env t - | Type -> `Ty (s, Expr.Id.ttype (Id.full_name s)) - | Typed ty -> `Term (s, Expr.Id.ty (Id.full_name s) ty) - end - | t -> _expected env "(typed) variable" t None - -and parse_quant_vars env l = - let ttype_vars, typed_vars, env' = List.fold_left ( - fun (l1, l2, acc) v -> - match parse_var acc v with - | `Ty (id, v') -> - let v'', acc' = add_type_var acc id v' (get_loc v) in - (v'' :: l1, l2, acc') - | `Term (id, v') -> - let v'', acc' = add_term_var acc id v' (get_loc v) in - (l1, v'' :: l2, acc') - ) ([], [], env) l in - List.rev ttype_vars, List.rev typed_vars, env' - -and parse_let env f = function - | [] -> parse_expr env f - | x :: r -> - begin match x with - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Eq}, [ - { Ast.term = Ast.Symbol s }; e]) } -> - let t = parse_term env e in - let env' = add_let_term env s t in - parse_let env' f r - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Equiv}, [ - { Ast.term = Ast.Symbol s }; e]) } -> - let t = parse_formula env e in - let env' = add_let_prop env s t in - parse_let env' f r - | { Ast.term = Ast.Colon ({ Ast.term = Ast.Symbol s }, e) } -> - begin match parse_expr env e with - | Term t -> - let env' = add_let_term env s t in - parse_let env' f r - | Formula t -> - let env' = add_let_prop env s t in - parse_let env' f r - | res -> _expected env "term or formula" e (Some res) - end - | t -> _expected env "let-binding" t None - end - -and parse_app env ast s args = - match find_let env s with - | `Term t -> - if args = [] then Term t - else _fo_let env s ast - | `Prop p -> - if args = [] then Formula p - else _fo_let env s ast - | `Not_found -> - begin match find_var env s with - | `Ty f -> - if args = [] then Ty (Expr.Ty.of_id f) - else _fo_let env s ast - | `Term f -> - if args = [] then Term (Expr.Term.of_id f) - else _fo_let env s ast - | `Not_found -> - begin match find_global s with - | `Ty f -> - parse_app_ty env ast f args - | `Term f -> - parse_app_term env ast f args - | `Ty_alias (f_args, body) -> - parse_app_subst_ty env ast s args f_args body - | `Term_alias (f_ty_args, f_t_args, body) -> - parse_app_subst_term env ast s args f_ty_args f_t_args body - | `Not_found -> - begin match env.builtins env ast s args with - | Some res -> res - | None -> - begin match infer env ast s args (get_loc ast) with - | Some Ty_fun f -> parse_app_ty env ast f args - | Some Term_fun f -> parse_app_term env ast f args - | None -> - Util.error ~section - "Looking up '%a' failed, possibilities were:@ @[<hov>%a@]" - Id.print s (suggest ~limit:1 env) s; - raise (Typing_error ( - Format.asprintf "Scoping error: '%a' not found" Id.print s, env, ast)) - end - end - end - end - -and parse_app_ty env ast f args = - let l = List.map (parse_ty env) args in - Ty (ty_apply env ast f l) - -and parse_app_term env ast f args = - let n_args = List.length args in - let n_ty = List.length Expr.(f.id_type.fun_vars) in - let n_t = List.length Expr.(f.id_type.fun_args) in - let ty_l, t_l = - if n_args = n_ty + n_t then - CCList.take_drop n_ty args - else if n_args = n_t then - (CCList.replicate n_ty Dolmen.Term.wildcard, args) - else - _bad_term_arity env f (n_ty + n_t) ast - in - let ty_args = List.map (parse_ty env) ty_l in - let t_args = List.map (parse_term env) t_l in - Term (term_apply env ast f ty_args t_args) - -and parse_app_formula env ast f args = - if args = [] then Formula f - else _fo_formula env f ast - -and parse_app_subst_ty env ast id args f_args body = - let l = List.map (parse_ty env) args in - Ty (ty_subst env ast id l f_args body) - -and parse_app_subst_term env ast id args f_ty_args f_t_args body = - let n = List.length f_ty_args in - let ty_l, t_l = CCList.take_drop n args in - let ty_args = List.map (parse_ty env) ty_l in - let t_args = List.map (parse_term env) t_l in - Term (term_subst env ast id ty_args t_args f_ty_args f_t_args body) - -and parse_ty env ast = - match parse_expr (expect env Type) ast with - | Ty ty -> ty - | res -> _expected env "type" ast (Some res) - -and parse_term env ast = - match parse_expr (expect env (Typed Expr.Ty.base)) ast with - | Term t -> t - | res -> _expected env "term" ast (Some res) - -and parse_formula env ast = - match promote env ast @@ parse_expr (expect env (Typed Expr.Ty.prop)) ast with - | Formula p -> p - | res -> _expected env "formula" ast (Some res) - -let parse_ttype_var env t = - match parse_var (expect ~force:true env Type) t with - | `Ty (id, v) -> (id, v, get_loc t) - | `Term (_, v) -> - _expected env "type variable" t (Some (Term (Expr.Term.of_id v))) - -let rec parse_sig_quant env = function - | { Ast.term = Ast.Binder (Ast.Pi, vars, t) } -> - let ttype_vars = List.map (parse_ttype_var env) vars in - let ttype_vars', env' = add_type_vars env ttype_vars in - let l = List.combine vars ttype_vars' in - parse_sig_arrow l [] env' t - | t -> - parse_sig_arrow [] [] env t - -and parse_sig_arrow ttype_vars (ty_args: (Ast.t * res) list) env = function - | { Ast.term = Ast.Binder (Ast.Arrow, args, ret) } -> - let t_args = parse_sig_args env args in - parse_sig_arrow ttype_vars (ty_args @ t_args) env ret - | t -> - begin match parse_expr env t with - | Ttype -> - begin match ttype_vars with - | (h, _) :: _ -> - raise (Typing_error ( - "Type constructor signatures cannot have quantified type variables", env, h)) - | [] -> - let aux n = function - | (_, Ttype) -> n + 1 - | (ast, res) -> raise (Found (ast, res)) - in - begin - match List.fold_left aux 0 ty_args with - | n -> `Ty_cstr n - | exception Found (err, _) -> - raise (Typing_error ( - Format.asprintf - "Type constructor signatures cannot have non-ttype arguments,", env, err)) - end - end - | Ty ret -> - let aux acc = function - | (_, Ty t) -> t :: acc - | (ast, res) -> raise (Found (ast, res)) - in - begin - match List.fold_left aux [] ty_args with - | exception Found (err, res) -> _expected env "type" err (Some res) - | l -> `Fun_ty (List.map snd ttype_vars, List.rev l, ret) - end - | res -> _expected env "Ttype of type" t (Some res) - end - -and parse_sig_args env l = - CCList.flat_map (parse_sig_arg env) l - -and parse_sig_arg env = function - | { Ast.term = Ast.App ({ Ast.term = Ast.Builtin Ast.Product}, l) } -> - List.map (fun x -> x, parse_expr env x) l - | t -> - [t, parse_expr env t] - -let parse_sig = parse_sig_quant - -let rec parse_fun ty_args t_args env = function - | { Ast.term = Ast.Binder (Ast.Fun, l, ret) } -> - let ty_args', t_args', env' = parse_quant_vars env l in - parse_fun (ty_args @ ty_args') (t_args @ t_args') env' ret - | ast -> - begin match parse_expr env ast with - | (Ty body) as res -> - if t_args = [] then `Ty (ty_args, body) - else _expected env "non_dependant type (or a term)" ast (Some res) - | Term body -> `Term (ty_args, t_args, body) - | res -> _expected env "term or a type" ast (Some res) - end - -(* High-level parsing functions *) -(* ************************************************************************ *) - -let new_decl env t ?attr id = - Util.enter_prof section; - Util.debug ~section "Typing declaration:@ @[<hov>%a :@ %a@]" - Id.print id Ast.print t; - let aux acc (Any (tag, v)) = Tag.add acc tag v in - let tags = - CCOpt.map (fun a -> - Util.debug ~section "Typing attribute:@ @[<hov>%a@]" Ast.print a; - let l = parse_attr_and env a in - List.fold_left aux Tag.empty l) attr - in - let res = - match parse_sig env t with - | `Ty_cstr n -> - let c = Expr.Id.ty_fun ?tags (Id.full_name id) n in - decl_ty_cstr id c (Declared (get_loc t)); - `Type_decl c - | `Fun_ty (vars, args, ret) -> - let f = Expr.Id.term_fun ?tags (Id.full_name id) vars args ret in - decl_term id f (Declared (get_loc t)); - `Term_decl f - in - Util.exit_prof section; - res - -let new_def env t ?attr id = - Util.enter_prof section; - Util.debug ~section "Typing definition:@ @[<hov>%a =@ %a@]" - Id.print id Ast.print t; - let res = - match parse_fun [] [] env t with - | `Ty (ty_args, body) -> - def_ty id ty_args body; - `Type_def (id, ty_args, body) - | `Term (ty_args, t_args, body) -> - def_term id ty_args t_args body; - `Term_def (id, ty_args, t_args, body) - in - Util.exit_prof section; - res - -let new_formula env t = - Util.enter_prof section; - Util.debug ~section "Typing top-level formula:@ %a" Ast.print t; - let res = parse_formula env t in - Util.exit_prof section; - res - diff --git a/src/bin/witan.ml b/src/bin/witan.ml deleted file mode 100644 index f250b7564479bc6cd1418458320aa6f163627d0d..0000000000000000000000000000000000000000 --- a/src/bin/witan.ml +++ /dev/null @@ -1,61 +0,0 @@ -(*************************************************************************) -(* This file is part of Colibrics. *) -(* *) -(* Copyright (C) 2017 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(*************************************************************************) - -let theories = Witan_theories_bool.[Boolean.th_register; Equality.th_register; Uninterp.th_register ] - - -let () = - if not Witan_core.(Egraph.check_initialization () && - Conflict.check_initialization ()) then - exit 1 - - -let one_file opts file = - (* Parse input *) - let statements = Witan_solver.Input.read - ?language:Options.(opts.input.language) - ~dir:Options.(opts.input.dir) - file - in - if opts.Options.type_only then exit 0; - let res = - Witan_solver.Notypecheck.run - ?limit:(if opts.Options.step_limit < 0 then None else Some opts.Options.step_limit) - ~theories statements in - match res with - | `Unsat -> Printf.printf "unsat\n" - | `Sat -> Printf.printf "sat\n" - -let () = - (* Parse command line options *) - let opts = match Cmdliner.Term.eval (Options.all, Options.info) with - | `Version | `Help -> exit 0 - | `Error `Parse - | `Error `Term - | `Error `Exn -> exit 1 - | `Ok opts -> opts - in - List.iter (fun f -> Witan_popop_lib.Debug.set_flag f) opts.Options.debug_flags; - Witan_popop_lib.Debug.(if test_flag stack_trace then Printexc.record_backtrace true); - begin match opts.Options.seed_shuffle with - | None -> Witan_stdlib.Shuffle.set_shuffle None; - | Some i -> Witan_stdlib.Shuffle.set_shuffle (Some [|i|]); - end; - one_file opts Options.(opts.input.file) diff --git a/src/core/egraph.ml b/src/core/egraph.ml index a17c16ddf0ee9b890fa271bdfb6f73a40cf8e191..67698331927f24484207b0b7d94ce6f7852ddae6 100644 --- a/src/core/egraph.ml +++ b/src/core/egraph.ml @@ -22,7 +22,7 @@ open Witan_popop_lib open Popop_stdlib open Nodes -exception Contradiction of Trail.Pexp.t +exception Contradiction let debug = Debug.register_info_flag ~desc:"for the core solver" @@ -88,7 +88,6 @@ module Def = struct sem : semtable VSemTable.t; value : unit VValueTable.t; envs : Env.VectorH.t; - trail : Trail.t; mutable current_delayed : delayed_t; (** For assert-check *) history : saved Context.history; } @@ -98,11 +97,11 @@ module Def = struct env : t; todo_immediate_dem : action_immediate_dem Queue.t; todo_merge_dom : action_merge_dom Queue.t; - mutable todo_delayed_merge : (Trail.Pexp.t * Node.t * Node.t * bool) option; + mutable todo_delayed_merge : (Node.t * Node.t * bool) option; todo_merge : action_merge Queue.t; todo_ext_action : action_ext Queue.t; sched_daemon : Events.Wait.daemon_key -> unit; - sched_decision : Trail.chogen -> unit; + sched_decision : choice -> unit; } and action_immediate_dem = @@ -110,17 +109,36 @@ module Def = struct and action_merge_dom = | SetMergeDomNode : - Trail.Pexp.t * 'a DomKind.t * Node.t * Node.t * bool -> action_merge_dom + 'a DomKind.t * Node.t * Node.t * bool -> action_merge_dom and action_merge = - | Merge of Trail.Pexp.t * Node.t * Node.t + | Merge of Node.t * Node.t and action_ext = | ExtDem : Events.Wait.daemon_key -> action_ext + and choice_state = + | DecNo + | DecTodo of (delayed_t -> unit) + + and choice = { + choice: delayed_t -> choice_state; + prio: int; + } + end open Def + + +type choice = Def.choice = { + choice: delayed_t -> choice_state; + prio: int; +} +type choice_state = Def.choice_state = + | DecNo + | DecTodo of (delayed_t -> unit) + (** {2 Define events} *) module WaitDef = struct @@ -135,7 +153,7 @@ module Wait : Events.Wait.S with type delayed = delayed_t and type delayed_ro = Events.Wait.Make(WaitDef) (** {2 Define domain registration} *) -module VDom = DomKind.Make(struct type delayed = delayed_t type pexp = Trail.Pexp.t end) +module VDom = DomKind.Make(struct type delayed = delayed_t end) include VDom let mk_dumb_delayed () = { env = Obj.magic 0; @@ -312,10 +330,6 @@ let output_graph filename t = ValueKind.pp value (escape_for_dot (print_value value) s); with Not_found -> () in - let print_ty fmt node = - if is_repr t node - then Format.fprintf fmt ": %a" Ty.pp (Node.ty node) - in let print_sem fmt node = match Only_for_solver.thterm node with | None -> () @@ -326,9 +340,8 @@ let output_graph filename t = Format.fprintf fmt "| {%a | %s}" ThTermKind.pp sem (escape_for_dot S.pp v) in - Format.fprintf fmt "{%a %a %a %a %a}" (* "{%a | %a | %a}" *) + Format.fprintf fmt "{%a %a %a %a}" (* "{%a | %a | %a}" *) Node.pp node - print_ty node print_sem node (if is_repr t node then VDomTable.pp Format.silent Format.silent @@ -436,15 +449,14 @@ module Delayed = struct let events = Node.M.find_opt node t.env.event_value in Wait.wakeup_events_bag Events.Wait.translate_value t events (node,value) - let add_pending_merge (t : t) pexp node node' = + let add_pending_merge (t : t) node node' = Debug.dprintf4 debug "[Egraph] @[add_pending_merge for %a and %a@]" Node.pp node Node.pp node'; assert (is_registered t node); assert (is_registered t node'); assert (not (Node.equal (find t node) (find t node'))); - assert (Ty.equal (Node.ty node) (Node.ty node')); (* Add the actual merge for later *) - Queue.add (Merge (pexp,node,node')) t.todo_merge + Queue.add (Merge (node,node')) t.todo_merge let check_no_dom t node = let foldi acc _dom (domtable: _ domtable) = @@ -493,9 +505,8 @@ module Delayed = struct end end - let set_semvalue_pending t pexp node0 node0' = + let set_semvalue_pending t node0 node0' = let node = find t node0 in - assert (Ty.equal (Node.ty node) (Node.ty node0')); begin if not (is_registered t node0') then begin register t node0'; @@ -505,15 +516,6 @@ module Delayed = struct termination. *) t.env.repr <- Node.M.add node0' node t.env.repr; - let pexp = pexp () in - Trail.add_merge_start t.env.trail pexp - ~node1:node0 ~node2:node0' - ~node1_repr:node ~node2_repr:node0' - ~new_repr:node; - Trail.add_merge_finish t.env.trail pexp - ~node1:node0 ~node2:node0' - ~node1_repr:node ~node2_repr:node0' - ~new_repr:node; (** wakeup the daemons register_node *) let event, other_event = Node.M.find_remove node0' t.env.event_repr in Wait.wakeup_events_bag Events.Wait.translate_change t other_event node0'; @@ -532,23 +534,16 @@ module Delayed = struct () else (** merge node and node0' *) - let pexp = pexp () in - add_pending_merge t pexp node0 node0' + add_pending_merge t node0 node0' end - let set_sem_pending t pexp node0 thterm = + let set_sem_pending t node0 thterm = let node0' = ThTerm.node thterm in - let pexp () = - Trail.mk_pexp t.env.trail Trail.exp_same_sem - (ExpSameSem(pexp,node0,thterm)) in - set_semvalue_pending t pexp node0 node0' + set_semvalue_pending t node0 node0' - let set_value_pending t pexp node0 nodevalue = + let set_value_pending t node0 nodevalue = let node0' = Value.node nodevalue in - let pexp () = - Trail.mk_pexp t.env.trail Trail.exp_same_sem - (ExpSameValue(pexp,node0,nodevalue)) in - set_semvalue_pending t pexp node0 node0' + set_semvalue_pending t node0 node0' let set_dom_pending (type a) t (dom : a DomKind.t) node0 new_v = Debug.incr stats_set_dom; @@ -597,7 +592,7 @@ module Delayed = struct else heuristic () - let merge_dom_pending (type a) t pexp (dom : a DomKind.t) node1_0 node2_0 inv = + let merge_dom_pending (type a) t (dom : a DomKind.t) node1_0 node2_0 inv = let node1 = find t node1_0 in let node2 = find t node2_0 in let domtable = (get_table_dom t.env dom) in @@ -613,13 +608,13 @@ module Delayed = struct match old_other_s, old_repr_s with | None, None -> () | _ -> - Dom.merge t pexp + Dom.merge t (old_other_s,node1_0) (old_repr_s,node2_0) inv - let merge_dom ?(dry_run=false) t pexp node1_0 node2_0 inv = + let merge_dom ?(dry_run=false) t node1_0 node2_0 inv = let node1 = find t node1_0 in let node2 = find t node2_0 in let dom_not_done = ref false in @@ -632,13 +627,13 @@ module Delayed = struct dom_not_done := true; if not dry_run then Queue.push - (SetMergeDomNode(pexp,dom,node1_0,node2_0,inv)) t.todo_merge_dom + (SetMergeDomNode(dom,node1_0,node2_0,inv)) t.todo_merge_dom end in VDomTable.iter_initializedi {VDomTable.iteri} t.env.dom; !dom_not_done - let merge_values t pexp node0 node0' = + let merge_values t node0 node0' = let node = find t node0 in let node' = find t node0' in let iteri (type a) (value:a ValueKind.t) (valuetable:a valuetable) = @@ -664,29 +659,20 @@ module Delayed = struct (* already same value. Does that really happen? *) () else - let ty = Node.ty node in - let v = Value.index value v ty in - let v' = Value.index value v' ty in - let pexp = Trail.mk_pexp t.env.trail Trail.exp_diff_value (v,node0,node0',v',pexp) in - raise (Contradiction pexp) + raise Contradiction in VValueTable.iter_initializedi {VValueTable.iteri} t.env.value - let finalize_merge t pexp node1_0 node2_0 inv = + let finalize_merge t node1_0 node2_0 inv = let node1 = find t node1_0 in let node2 = find t node2_0 in let other_node0,other_node,repr_node0,repr_node = if inv then node2_0,node2, node1_0, node1 else node1_0, node1, node2_0, node2 in - merge_values t pexp node1_0 node2_0; + merge_values t node1_0 node2_0; t.env.repr <- Node.M.add other_node repr_node t.env.repr; - Trail.add_merge_finish t.env.trail pexp - ~node1:node1_0 ~node2:node2_0 - ~node1_repr:node1 ~node2_repr:node2 - ~new_repr:repr_node; - Debug.dprintf10 debug_few "[Egraph.few] [%a] merge %a(%a) -> %a(%a)" - Trail.print_current_age t.env.trail + Debug.dprintf8 debug_few "[Egraph.few] merge %a(%a) -> %a(%a)" Node.pp other_node Node.pp other_node0 Node.pp repr_node Node.pp repr_node0; let event, other_event = Node.M.find_remove other_node t.env.event_repr in @@ -730,30 +716,26 @@ module Delayed = struct Wait.wakeup_events_bag Events.Wait.translate_change t other_event other_node - let do_delayed_merge t pexp node1_0 node2_0 inv = - let dom_not_done = merge_dom t pexp node1_0 node2_0 inv in + let do_delayed_merge t node1_0 node2_0 inv = + let dom_not_done = merge_dom t node1_0 node2_0 inv in if dom_not_done then begin Debug.dprintf4 debug "[Egraph] @[merge %a %a dom not done@]" Node.pp node1_0 Node.pp node2_0; - t.todo_delayed_merge <- Some (pexp,node1_0,node2_0,inv) + t.todo_delayed_merge <- Some (node1_0,node2_0,inv) end else - finalize_merge t pexp node1_0 node2_0 inv + finalize_merge t node1_0 node2_0 inv (** merge two pending actions *) - let merge_pending t pexp node1_0 node2_0 = + let merge_pending t node1_0 node2_0 = let node1 = find t node1_0 in let node2 = find t node2_0 in if not (Node.equal node1 node2) then begin - let ((other_node0,_),(_,repr_node)) = + let ((other_node0,_),(_,_)) = choose_repr t.env (node1_0,node1) (node2_0,node2) in let inv = not (Node.equal node1_0 other_node0) in - Trail.add_merge_start t.env.trail pexp - ~node1:node1_0 ~node2:node2_0 - ~node1_repr:node1 ~node2_repr:node2 - ~new_repr:repr_node; - do_delayed_merge t pexp node1_0 node2_0 inv + do_delayed_merge t node1_0 node2_0 inv end (** {2 Internal scheduler} *) @@ -790,26 +772,26 @@ module Delayed = struct do_pending t else if not (Queue.is_empty t.todo_merge_dom) then match Queue.pop t.todo_merge_dom with - | SetMergeDomNode(pexp,dom,node1,node2,inv) -> + | SetMergeDomNode(dom,node1,node2,inv) -> Debug.dprintf6 debug "[Egraph] @[do_pending SetDomNode %a %a %a@]" DomKind.pp dom Node.pp node1 Node.pp node2; - merge_dom_pending t pexp dom node1 node2 inv; + merge_dom_pending t dom node1 node2 inv; do_pending t else match t.todo_delayed_merge with - | Some(pexp,node1_0,node2_0,inv) -> + | Some(node1_0,node2_0,inv) -> t.todo_delayed_merge <- None; - assert (not (merge_dom ~dry_run:true t pexp node1_0 node2_0 inv)); + assert (not (merge_dom ~dry_run:true t node1_0 node2_0 inv)); (** understand why that happend. Is it really needed to do a fixpoint? *) - do_delayed_merge t pexp node1_0 node2_0 inv; + do_delayed_merge t node1_0 node2_0 inv; do_pending t | None -> if not (Queue.is_empty t.todo_merge) then match Queue.pop t.todo_merge with - | Merge (pexp,node1,node2) -> + | Merge (node1,node2) -> Debug.dprintf4 debug "[Egraph] @[do_pending Merge %a %a@]" Node.pp node1 Node.pp node2; - merge_pending t pexp node1 node2; + merge_pending t node1 node2; do_pending t else if not (Queue.is_empty t.todo_ext_action) then (begin match Queue.pop t.todo_ext_action with @@ -845,29 +827,29 @@ module Delayed = struct (** {2 API} *) - let merge t pexp node1_0 node2_0 = + let merge t node1_0 node2_0 = assert (is_current_env t); if not (Node.equal (find t node1_0) (find t node2_0)) then - add_pending_merge t pexp node1_0 node2_0 + add_pending_merge t node1_0 node2_0 let check d node = assert (Equal.physical d.env.current_delayed d); assert (is_registered d node) - let set_thterm d pexp node thterm = + let set_thterm d node thterm = Debug.dprintf4 debug "[Egraph] @[add_pending_set_thterm for %a and %a@]" Node.pp node ThTerm.pp thterm; check d node; - set_sem_pending d pexp node thterm + set_sem_pending d node thterm - let set_value d pexp node nodevalue = + let set_value d node nodevalue = Debug.dprintf4 debug_few "[Egraph] @[set_value for %a with %a@]" Node.pp node Value.pp nodevalue; check d node; - set_value_pending d pexp node nodevalue + set_value_pending d node nodevalue let set_dom d dom node v = Debug.dprintf4 debug_few @@ -882,8 +864,8 @@ module Delayed = struct Node.pp node (print_dom dom) v; check d node; let node' = match d.todo_delayed_merge with - | Some(_,node1,node2,_) when Node.equal node1 node -> node2 - | Some(_,node1,node2,_) when Node.equal node2 node -> node1 + | Some(node1,node2,_) when Node.equal node1 node -> node2 + | Some(node1,node2,_) when Node.equal node2 node -> node1 | _ -> raise (BrokenInvariant( "set_dom_premerge should be used only on the \ nodeasses currently merged")) in @@ -899,13 +881,9 @@ module Delayed = struct let register_decision t chogen = t.sched_decision chogen - let mk_pexp t ?age kexp exp = Trail.mk_pexp ?age t.env.trail kexp exp - let current_age t = Trail.current_age t.env.trail - let add_pexp t pexp = Trail.add_pexp t.env.trail pexp - - let contradiction d pexp = + let contradiction d = d.env.current_delayed <- unsat_delayed; - raise (Contradiction pexp) + raise Contradiction (** {2 API for attaching event} *) @@ -1007,7 +985,6 @@ module Backtrackable = struct sem = VSemTable.create 5; value = VValueTable.create 5; envs = Env.VectorH.create 5; - trail = Trail.create context; current_delayed = dumb_delayed; history = Hidden.create context; } @@ -1107,27 +1084,10 @@ module Backtrackable = struct assert (check_disabled_delayed t); T.find_def t node - let get_trail t = - let t = Hidden.ro t in - (* assert (check_disabled_delayed t); *) - t.trail - let get_getter t = (* assert (check_disabled_delayed t); *) t - let new_dec t = - let t = Hidden.ro t in - assert (check_disabled_delayed t); - Trail.new_dec t.trail - - let current_age (t:t) = - let t = Hidden.ro t in - Trail.current_age t.trail - let current_nbdec (t:t) = - let t = Hidden.ro t in - Trail.nbdec t.trail - let get_direct_dom t dom node = assert (check_disabled_delayed t); get_direct_dom t dom node @@ -1184,3 +1144,5 @@ let () = Exn_printer.register (fun fmt exn -> Format.fprintf fmt "The environnement of %s is not initialized." env | exn -> raise exn ) + +let print_decision = Witan_popop_lib.Debug.register_flag ~desc:"Print@ information@ about@ the@ decisions@ made" "decision" diff --git a/src/core/egraph.mli b/src/core/egraph.mli index afadd49b668921eaf4a7a3a5b65a4d4e565008f1..b140de46f1c69bbc83e9eccdd4ad62623344eaa5 100644 --- a/src/core/egraph.mli +++ b/src/core/egraph.mli @@ -24,14 +24,13 @@ equivalence classes, values. It take care to schedule event that happened. *) -open Trail open Nodes exception NotRegistered exception UninitializedEnv of string -exception Contradiction of Trail.Pexp.t +exception Contradiction module type Getter = sig type t @@ -82,13 +81,13 @@ val unset_dom : t -> 'a DomKind.t -> Node.t -> unit (** {3 Delayed modifications} *) -val set_thterm : t -> Trail.Pexp.t -> Node.t -> ThTerm.t -> unit +val set_thterm : t -> Node.t -> ThTerm.t -> unit (** attach a theory term to an equivalence class *) -val set_value: t -> Trail.Pexp.t -> Node.t -> Value.t -> unit +val set_value: t -> Node.t -> Value.t -> unit (** attach value to an equivalence class *) -val merge : t -> Trail.Pexp.t -> Node.t -> Node.t -> unit +val merge : t -> Node.t -> Node.t -> unit (** {3 Attach Event} *) @@ -107,16 +106,21 @@ val attach_reg_value: t -> 'a ValueKind.t -> ('event,'r) Events.Dem.t -> 'event val attach_node: t -> Node.t -> ('event,'r) Events.Dem.t -> 'event -> unit (** wakeup when it is not anymore the representative class *) -val register_decision: t -> Trail.chogen -> unit +type choice_state = + | DecNo + | DecTodo of (t -> unit) + +type choice = { + choice: t -> choice_state; + prio: int; +} + +val register_decision: t -> choice -> unit (** register a decision that would be scheduled later. The [choose_decision] of the [Cho] will be called at that time to know if the decision is still needed. *) -(** {3 Trails} *) -val mk_pexp: t -> ?age:age -> 'a Exp.t -> 'a -> Trail.Pexp.t -val current_age: t -> age -val add_pexp: t -> Trail.Pexp.t -> unit -val contradiction: t -> Trail.Pexp.t -> 'b +val contradiction: t -> 'b (** {3 Low level} *) val flush_internal: t -> unit @@ -129,7 +133,7 @@ module Wait : Events.Wait.S with type delayed = t and type delayed_ro = Ro.t (** {2 Domains and Semantic Values key creation} *) -module type Dom = DomKind.Dom_partial with type delayed := t and type pexp := Trail.Pexp.t +module type Dom = DomKind.Dom_partial with type delayed := t val register_dom : (module Dom with type t = 'a) -> unit @@ -150,7 +154,7 @@ module Backtrackable: sig val new_delayed : sched_daemon:(Events.Wait.daemon_key -> unit) -> - sched_decision:(chogen -> unit) -> + sched_decision:(choice -> unit) -> t -> delayed (** The solver shouldn't be used anymore before calling flush. (flushd doesn't count) @@ -171,13 +175,11 @@ module Backtrackable: sig (* val make_decisions : delayed -> attached_daemons -> unit *) - val get_trail : t -> Trail.t val get_getter : t -> Getter.t - val new_dec : t -> Trail.dec - val current_age : t -> Trail.Age.t - val current_nbdec : t -> int (** Debug *) val draw_graph: ?force:bool -> t -> unit val output_graph : string -> t -> unit end + +val print_decision: Witan_popop_lib.Debug.flag diff --git a/src/core/interp.ml b/src/core/interp.ml index ebc5b6da1e2005f135c300b1076dfbd195d6991e..e2733450db5c75283ee889fb1bd1cf1ebadce5ba 100644 --- a/src/core/interp.ml +++ b/src/core/interp.ml @@ -20,10 +20,10 @@ open Witan_popop_lib open Std - -module Register = struct - let ids : (Term.id -> Nodes.Value.t list -> Nodes.Value.t option) list ref = ref [] +module Register = struct + type interp_term = Dolmen_std.Expr.Term.t -> Nodes.Value.t + let ids : (interp_term -> Dolmen_std.Expr.Term.t -> Nodes.Value.t option) list ref = ref [] let id f = ids := f::!ids module ThInterp = Nodes.ThTermKind.MkVector(struct @@ -42,42 +42,25 @@ module Register = struct end -exception NoInterpretation of Term.id -exception CantInterpretTerm of Term.t +exception CantInterpretTerm of Dolmen_std.Expr.Term.t exception CantInterpretThTerm of Nodes.ThTerm.t -type leaf = Term.t -> Nodes.Value.t option +type leaf = Dolmen_std.Expr.Term.t -> Nodes.Value.t option (** No cache currently because there is no guaranty that the variable in the let is unique *) let term ?(leaf=(fun _ -> None)) t = - let rec interp leaf t = - match leaf t with - | Some v -> v - | None -> - let rec aux leaf args = function - | { Term.term = App (f, arg); _ } -> - aux leaf ((interp leaf arg) :: args) f - | { Term.term = Let (v,e,t); _ } -> - let v' = interp leaf e in - let leaf t = match t.Term.term with - | Id id when Term.Id.equal v id -> Some v' - | _ -> leaf t in - aux leaf args t - | { Term.term = Id id; _ } -> - let rec find = function - | [] -> raise (NoInterpretation id) - | f::l -> - match f id args with - | None -> find l - | Some v -> v - in - find !Register.ids - | t -> raise (CantInterpretTerm t) + let rec interp regl t = + let rec aux t = function + | [] -> raise (CantInterpretTerm t) + | a::l -> + match a (interp regl) t with + | Some v -> v + | None -> aux t l in - aux leaf [] t + aux t regl in - interp leaf t + interp ((fun _ -> leaf)::!Register.ids) t let rec node ?(leaf=(fun _ -> None)) n = match Nodes.Only_for_solver.open_node n with @@ -89,25 +72,22 @@ and thterm ?(leaf=(fun _ -> None)) t = | Nodes.Only_for_solver.ThTerm (sem,v) -> (** check if it is not a synterm *) match Nodes.ThTermKind.Eq.eq_type sem SynTerm.key with - | Poly.Eq -> term ~leaf (v:Term.t) + | Poly.Eq -> term ~leaf (v:Expr.Term.t) | Poly.Neq -> if Register.ThInterp.is_uninitialized Register.thterms sem then raise (CantInterpretThTerm t); (Register.ThInterp.get Register.thterms sem) ~interp:(node ~leaf) v -let model d n = - match Ty.H.find_opt Register.models (Nodes.Node.ty n) with - | None -> invalid_arg "Uninterpreted type" - | Some f -> f d n +(* let model d n = + * match Ty.H.find_opt Register.models (Nodes.Node.ty n) with + * | None -> invalid_arg "Uninterpreted type" + * | Some f -> f d n *) let () = Exn_printer.register (fun fmt exn -> match exn with - | NoInterpretation id -> - Format.fprintf fmt "Can't interpret the id %a." - Term.Id.pp id | CantInterpretTerm t -> Format.fprintf fmt "Can't interpret the term %a." - Term.pp t + Dolmen_std.Expr.Term.print t | CantInterpretThTerm th -> Format.fprintf fmt "Can't interpret the thterm %a." Nodes.ThTerm.pp th diff --git a/src/core/interp.mli b/src/core/interp.mli index a56c00757224dc4a0c2ac5c2c485add6558eff49..76a77f9ef46424eac781c493c312ba4d7b4fa215 100644 --- a/src/core/interp.mli +++ b/src/core/interp.mli @@ -20,18 +20,18 @@ module Register: sig - val id: (Term.id -> Nodes.Value.t list -> Nodes.Value.t option) -> unit + val id: ((Dolmen_std.Expr.Term.t -> Nodes.Value.t) -> (Dolmen_std.Expr.Term.t -> Nodes.Value.t option)) -> unit val thterm: 'a Nodes.ThTermKind.t -> (interp:(Nodes.Node.t -> Nodes.Value.t) -> 'a -> Nodes.Value.t) -> unit - val model: Ty.t -> (Egraph.t -> Nodes.Node.t -> Nodes.Value.t) -> unit + (* val model: Ty.t -> (Egraph.t -> Nodes.Node.t -> Nodes.Value.t) -> unit *) end -type leaf = Term.t -> Nodes.Value.t option +type leaf = Dolmen_std.Expr.Term.t -> Nodes.Value.t option -val term : ?leaf:leaf -> Term.t -> Nodes.Value.t +val term : ?leaf:leaf -> Dolmen_std.Expr.Term.t -> Nodes.Value.t val thterm : ?leaf:leaf -> Nodes.ThTerm.t -> Nodes.Value.t val node : ?leaf:leaf -> Nodes.Node.t -> Nodes.Value.t -val model : Egraph.t -> Nodes.Node.t -> Nodes.Value.t +(* val model : Egraph.t -> Nodes.Node.t -> Nodes.Value.t *) diff --git a/src/core/structures/domKind.ml b/src/core/structures/domKind.ml index 92625cce8eee9936c21d758fbf51160a9074ff1e..554a113678a95bede22c5abcd3c3a4f450c69cbb 100644 --- a/src/core/structures/domKind.ml +++ b/src/core/structures/domKind.ml @@ -31,21 +31,20 @@ type 'a dom = 'a t module type Dom_partial = sig type delayed - type pexp type t val merged: t option -> t option -> bool val merge: delayed -> - pexp -> t option * Node.t -> t option * Node.t -> + t option * Node.t -> t option * Node.t -> bool -> unit val pp: Format.formatter -> t -> unit val key: t Dom.t end -module Make(S:sig type delayed type pexp end) = struct +module Make(S:sig type delayed end) = struct - module type Dom = Dom_partial with type delayed := S.delayed and type pexp := S.pexp + module type Dom = Dom_partial with type delayed := S.delayed include Dom.Make_Registry(struct type 'a data = (module Dom with type t = 'a) diff --git a/src/core/structures/domKind.mli b/src/core/structures/domKind.mli index 165c3f5e17a80457bff321b2e58ba6db00911e56..07abe1cf62749a9bec986110b47b7435bd38c3ed 100644 --- a/src/core/structures/domKind.mli +++ b/src/core/structures/domKind.mli @@ -29,21 +29,20 @@ type 'a dom = 'a t (** delayed and pexp are instanciated in Egraph *) module type Dom_partial = sig type delayed - type pexp type t val merged: t option -> t option -> bool val merge: delayed -> - pexp -> t option * Node.t -> t option * Node.t -> + t option * Node.t -> t option * Node.t -> bool -> unit val pp: Format.formatter -> t -> unit val key: t dom end -module Make (S:sig type delayed type pexp end) : sig +module Make (S:sig type delayed end) : sig - module type Dom = Dom_partial with type delayed := S.delayed and type pexp := S.pexp + module type Dom = Dom_partial with type delayed := S.delayed val register_dom: (module Dom with type t = 'a) -> unit val check_is_registered : 'a dom -> unit diff --git a/src/core/structures/expr.ml b/src/core/structures/expr.ml new file mode 100644 index 0000000000000000000000000000000000000000..35ec88fcc9e12b0de3aca3924cc69fc7de589b8d --- /dev/null +++ b/src/core/structures/expr.ml @@ -0,0 +1,36 @@ +include Dolmen_std.Expr + +module Ty = struct + include Dolmen_std.Expr.Ty + + let pp = print + let hash_fold_t state t = Base.Hash.fold_int state (hash t) + + include Witan_popop_lib.Popop_stdlib.MkDatatype(struct + type nonrec t = t + let equal = equal + let compare = compare + let hash = hash + let pp = pp + end) + +end + +module Term = struct + include Dolmen_std.Expr.Term + let pp = print + + include Witan_popop_lib.Popop_stdlib.MkDatatype(struct + type nonrec t = t + let equal = equal + let compare = compare + let hash = hash + let pp = pp + end) + + module Const = struct + include Dolmen_std.Expr.Term.Const + let pp fmt (t:t) = Dolmen_std.Expr.Id.print fmt t + let hash_fold_t state t = Base.Hash.fold_int state (hash t) + end +end diff --git a/src/core/structures/nodes.ml b/src/core/structures/nodes.ml index 361481a42a76bfaa17ca33dbb5aa0a3880ee1961..34954cb3beb7ddd66b6a0cde728404ca6978b46e 100644 --- a/src/core/structures/nodes.ml +++ b/src/core/structures/nodes.ml @@ -67,16 +67,16 @@ let get_value = ValueRegistry.get module Node = struct type 'a r = - | ThTerm : int * Ty.t * 'a ThTermKind.t * 'a -> [`ThTerm] r - | Value : int * Ty.t * 'a ValueKind.t * 'a -> [`Value] r + | ThTerm : int * 'a ThTermKind.t * 'a -> [`ThTerm] r + | Value : int * 'a ValueKind.t * 'a -> [`Value] r type t' = All : _ r -> t' [@@unboxed] type thterm = [`ThTerm] r type nodevalue = [`Value] r let tag: t' -> int = function - | All(ThTerm(tag,_,_,_)) -> tag - | All(Value(tag,_,_,_)) -> tag + | All(ThTerm(tag,_,_)) -> tag + | All(Value(tag,_,_)) -> tag let names = Simple_vector.create 100 let used_names : (* next id to use *) int DStr.H.t = DStr.H.create 100 @@ -101,33 +101,29 @@ module Node = struct let s = Strings.find_new_name used_names s in Simple_vector.set names (tag node) s - let ty = function - | All(ThTerm(_,ty,_,_)) -> ty - | All(Value(_,ty,_,_)) -> ty - module ThTermIndex = ThTermKind.MkVector - (struct type ('a,_) t = 'a -> Ty.t -> thterm end) + (struct type ('a,_) t = 'a -> thterm end) let semindex : unit ThTermIndex.t = ThTermIndex.create 8 - let thterm sem v ty : thterm = + let thterm sem v : thterm = ThTermRegistry.check_is_registered sem; - ThTermIndex.get semindex sem v ty + ThTermIndex.get semindex sem v module ValueIndex = ValueKind.MkVector - (struct type ('a,'unedeed) t = 'a -> Ty.t -> nodevalue end) + (struct type ('a,'unedeed) t = 'a -> nodevalue end) let valueindex : unit ValueIndex.t = ValueIndex.create 8 - let nodevalue value v ty : nodevalue = + let nodevalue value v : nodevalue = ValueRegistry.check_is_registered value; - ValueIndex.get valueindex value v ty + ValueIndex.get valueindex value v let of_thterm : thterm -> t = fun t -> All t let of_nodevalue : nodevalue -> t = fun t -> All t - let index_sem sem v ty = of_thterm (thterm sem v ty) - let index_value sem v ty = of_nodevalue (nodevalue sem v ty) + let index_sem sem v = of_thterm (thterm sem v) + let index_value sem v = of_nodevalue (nodevalue sem v) end @@ -135,16 +131,13 @@ module ThTerm = struct include Popop_stdlib.MakeMSH(struct type t = Node.thterm let tag: t -> int = function - | Node.ThTerm(tag,_,_,_) -> tag + | Node.ThTerm(tag,_,_) -> tag let pp fmt : t -> unit = function - | Node.ThTerm(_,_,sem,v) -> print_thterm sem fmt v + | Node.ThTerm(_,sem,v) -> print_thterm sem fmt v end) let index = Node.thterm let node = Node.of_thterm - let ty : t -> Ty.t = function - | Node.ThTerm(_,ty,_,_) -> ty - end @@ -154,15 +147,12 @@ module type RegisteredThTerm = sig (** thterm *) include Datatype - val index: s -> Ty.t -> t + val index: s -> t (** Return a thterm from a semantical value *) val node: t -> Node.t (** Return a node from a thterm *) - val ty: t -> Ty.t - (** Return the type from a thterm *) - val sem: t -> s (** Return the sem from a thterm *) @@ -186,21 +176,21 @@ module RegisterThTerm (D:ThTerm) : RegisteredThTerm with type s = D.t = struct let equal: t -> t -> bool = fun a b -> match a, b with - | ThTerm(_,tya,sema,va), ThTerm(_,tyb,semb,vb) -> + | ThTerm(_,sema,va), ThTerm(_,semb,vb) -> match ThTermKind.Eq.coerce_type sema D.key, ThTermKind.Eq.coerce_type semb D.key with - | Poly.Eq, Poly.Eq -> Ty.equal tya tyb && D.equal va vb + | Poly.Eq, Poly.Eq -> D.equal va vb let hash: t -> int = fun a -> match a with - | ThTerm(_,tya,sema,va) -> + | ThTerm(_,sema,va) -> let Poly.Eq = ThTermKind.Eq.coerce_type sema D.key in - Hashcons.combine (Ty.hash tya) (D.hash va) + (D.hash va) let set_tag: int -> t -> t = - fun tag (ThTerm(_,ty,sem,v)) -> ThTerm(tag,ty,sem,v) + fun tag (ThTerm(_,sem,v)) -> ThTerm(tag,sem,v) - let tag: t -> int = fun (ThTerm(tag,_,_,_)) -> tag + let tag: t -> int = fun (ThTerm(tag,_,_)) -> tag let pp fmt x = Format.pp_print_char fmt '@'; @@ -213,13 +203,13 @@ module RegisterThTerm (D:ThTerm) : RegisteredThTerm with type s = D.t = struct let key = D.key let tag: t -> int = function - | Node.ThTerm(tag,_,_,_) -> tag + | Node.ThTerm(tag,_,_) -> tag - let index v ty = + let index v = let node = - HC.hashcons3 - (fun tag sem v ty -> Node.ThTerm(tag,ty,sem,v)) - D.key v ty in + HC.hashcons2 + (fun tag sem v -> Node.ThTerm(tag,sem,v)) + D.key v in let i = tag node in Simple_vector.inc_size (i+1) Node.names; begin @@ -235,19 +225,17 @@ module RegisterThTerm (D:ThTerm) : RegisteredThTerm with type s = D.t = struct let node = Node.of_thterm let sem : t -> D.t = - fun (Node.ThTerm(_,_,sem,v)) -> + fun (Node.ThTerm(_,sem,v)) -> let Poly.Eq = ThTermKind.Eq.coerce_type sem D.key in v - let ty = ThTerm.ty - let thterm: t -> ThTerm.t = fun x -> x let of_thterm: ThTerm.t -> t option = function - | Node.ThTerm(_,_,sem',_) as v when ThTermKind.equal sem' D.key -> Some v + | Node.ThTerm(_,sem',_) as v when ThTermKind.equal sem' D.key -> Some v | _ -> None let coerce_thterm: ThTerm.t -> t = - fun (Node.ThTerm(_,_,sem',_) as v) -> assert (ThTermKind.equal sem' D.key); v + fun (Node.ThTerm(_,sem',_) as v) -> assert (ThTermKind.equal sem' D.key); v let () = ThTermRegistry.register (module D: ThTerm with type t = D.t); @@ -259,25 +247,23 @@ module Value = struct include Popop_stdlib.MakeMSH(struct type t = Node.nodevalue let tag: t -> int = function - | Node.Value(tag,_,_,_) -> tag + | Node.Value(tag,_,_) -> tag let pp fmt : t -> unit = function - | Node.Value(_,_,value,v) -> print_value value fmt v + | Node.Value(_,value,v) -> print_value value fmt v end) let index = Node.nodevalue let node = Node.of_nodevalue - let ty : t -> Ty.t = function - | Node.Value(_,ty,_,_) -> ty let value : type a. a ValueKind.t -> t -> a option = - fun value (Node.Value(_,_,value',v)) -> + fun value (Node.Value(_,value',v)) -> match ValueKind.Eq.eq_type value value' with | Poly.Neq -> None | Poly.Eq -> Some v let semantic_equal (x:t) (y:t) : [ `Uncomparable | `Equal | `Disequal ] = match x, y with - | Node.Value(_,_,xk,_), Node.Value(_,_,yk,_) when not (ValueKind.equal xk yk) -> + | Node.Value(_,xk,_), Node.Value(_,yk,_) when not (ValueKind.equal xk yk) -> `Uncomparable | _ -> if equal x y then `Equal else `Disequal @@ -290,15 +276,12 @@ module type RegisteredValue = sig (** nodevalue *) include Datatype - val index: ?basename:string -> s -> Ty.t -> t + val index: ?basename:string -> s -> t (** Return a nodevalue from a valueantical value *) val node: t -> Node.t (** Return a class from a nodevalue *) - val ty: t -> Ty.t - (** Return the type from a nodevalue *) - val value: t -> s (** Return the value from a nodevalue *) @@ -337,23 +320,23 @@ module RegisterValue (D:Value) : RegisteredValue with type s = D.t = struct let equal: t -> t -> bool = fun a b -> match a, b with - | Value(_,tya,valuea,va), Value(_,tyb,valueb,vb) -> + | Value(_,valuea,va), Value(_,valueb,vb) -> match ValueKind.Eq.coerce_type valuea D.key, ValueKind.Eq.coerce_type valueb D.key with - | Poly.Eq, Poly.Eq -> Ty.equal tya tyb && D.equal va vb + | Poly.Eq, Poly.Eq -> D.equal va vb let hash: t -> int = fun a -> match a with - | Value(_,tya,valuea,va) -> + | Value(_,valuea,va) -> let Poly.Eq = ValueKind.Eq.coerce_type valuea D.key in - Hashcons.combine (Ty.hash tya) (D.hash va) + (D.hash va) let set_tag: int -> t -> t = fun tag x -> match x with - | Value(_,ty,value,v) -> Value(tag,ty,value,v) + | Value(_,value,v) -> Value(tag,value,v) let tag: t -> int = function - | Value(tag,_,_,_) -> tag + | Value(tag,_,_) -> tag let pp fmt x = Format.pp_print_char fmt '@'; @@ -366,13 +349,13 @@ module RegisterValue (D:Value) : RegisteredValue with type s = D.t = struct let key = D.key let tag: t -> int = function - | Node.Value(tag,_,_,_) -> tag + | Node.Value(tag,_,_) -> tag - let index ?(basename="") v ty = + let index ?(basename="") v = let node = - HC.hashcons3 - (fun tag value v ty -> Node.Value(tag,ty,value,v)) - D.key v ty in + HC.hashcons2 + (fun tag value v -> Node.Value(tag,value,v)) + D.key v in let i = tag node in Simple_vector.inc_size (i+1) Node.names; begin @@ -387,19 +370,17 @@ module RegisterValue (D:Value) : RegisteredValue with type s = D.t = struct let node = Node.of_nodevalue let value : t -> D.t = function - | Node.Value(_,_,value,v) -> + | Node.Value(_,value,v) -> let Poly.Eq = ValueKind.Eq.coerce_type value D.key in v - let ty = Value.ty - let nodevalue: t -> Value.t = fun x -> x let of_nodevalue: Value.t -> t option = function - | Node.Value(_,_,value',_) as v when ValueKind.equal value' D.key -> Some v + | Node.Value(_,value',_) as v when ValueKind.equal value' D.key -> Some v | _ -> None let coerce_nodevalue: Value.t -> t = function - | Node.Value(_,_,value',_) as v -> assert (ValueKind.equal value' D.key); v + | Node.Value(_,value',_) as v -> assert (ValueKind.equal value' D.key); v end @@ -407,7 +388,7 @@ module RegisterValue (D:Value) : RegisteredValue with type s = D.t = struct let () = ValueRegistry.register (module D: Value with type t = D.t); RegisteredValueRegistry.register (module All: RegisteredValue with type s = D.t); - Node.ValueIndex.set Node.valueindex D.key (fun v ty -> index v ty) + Node.ValueIndex.set Node.valueindex D.key index end @@ -420,7 +401,7 @@ module Only_for_solver = struct | Node.All (Node.ThTerm _ as x) -> Some x let sem_of_node: ThTerm.t -> sem_of_node = function - | Node.ThTerm (_,_,sem,v) -> ThTerm(sem,v) + | Node.ThTerm (_,sem,v) -> ThTerm(sem,v) type value_of_node = | Value: 'a ValueKind.t * 'a -> value_of_node @@ -430,7 +411,7 @@ module Only_for_solver = struct | Node.All (Node.Value _ as x) -> Some x let value_of_node: Value.t -> value_of_node = function - | Node.Value (_,_,value,v) -> Value(value,v) + | Node.Value (_,value,v) -> Value(value,v) let node_of_thterm : ThTerm.t -> Node.t = ThTerm.node let node_of_nodevalue : Value.t -> Node.t = Value.node diff --git a/src/core/structures/nodes.mli b/src/core/structures/nodes.mli index f906f88ce7400aa8bd8eb2af7f3a4ed9777b9d2c..149bf12ec291afd5fa0fc948400e04ea34cd3c12 100644 --- a/src/core/structures/nodes.mli +++ b/src/core/structures/nodes.mli @@ -44,13 +44,10 @@ module Node : sig (** Change the pretty printed string for this node, to use with care preferably at the start *) - val ty: t -> Ty.t - (** Return the type of a node *) - - val index_sem: 'a ThTermKind.t -> 'a -> Ty.t -> t + val index_sem: 'a ThTermKind.t -> 'a -> t (** Return the corresponding node from a theory term *) - val index_value: 'a ValueKind.t -> 'a -> Ty.t -> t + val index_value: 'a ValueKind.t -> 'a -> t (** Return the corresponding node from a value *) end @@ -73,15 +70,12 @@ val print_thterm : 'a ThTermKind.t -> 'a Format.printer module ThTerm: sig include Datatype - val index: 'a ThTermKind.t -> 'a -> Ty.t -> t + val index: 'a ThTermKind.t -> 'a -> t (** Return the corresponding node from a theory term *) val node: t -> Node.t (** Returns the node associated to this theory term *) - val ty: t -> Ty.t - (** Returns the type of the theory term *) - end (** {3 Construction of a theory terms } *) @@ -96,15 +90,12 @@ module type RegisteredThTerm = sig (** thterm *) include Datatype - val index: s -> Ty.t -> t + val index: s -> t (** Return a theory term from the user type *) val node: t -> Node.t (** Return a class from a thterm *) - val ty: t -> Ty.t - (** Return the type from a thterm *) - val sem: t -> s (** Return the sem from a thterm *) @@ -142,13 +133,11 @@ val check_value_registered: 'a ValueKind.t -> unit module Value: sig include Datatype - val index: 'a ValueKind.t -> 'a -> Ty.t -> t + val index: 'a ValueKind.t -> 'a -> t (** Return the corresponding node from a value *) val node: t -> Node.t - val ty: t -> Ty.t - val value: 'a ValueKind.t -> t -> 'a option val semantic_equal: t -> t -> [ `Uncomparable | `Equal | `Disequal ] @@ -165,7 +154,7 @@ module type RegisteredValue = sig (** nodevalue *) include Datatype - val index: ?basename:string -> s -> Ty.t -> t + val index: ?basename:string -> s -> t (** Return a nodevalue from a valueantical term. Basename is used only for debug *) @@ -173,9 +162,6 @@ module type RegisteredValue = sig val node: t -> Node.t (** Return a class from a nodevalue *) - val ty: t -> Ty.t - (** Return the type from a nodevalue *) - val value: t -> s (** Return the value from a nodevalue *) diff --git a/src/core/synTerm.ml b/src/core/synTerm.ml new file mode 100644 index 0000000000000000000000000000000000000000..2dacf209c20618ed6f836fdd8419591a121ed685 --- /dev/null +++ b/src/core/synTerm.ml @@ -0,0 +1,101 @@ +(*************************************************************************) +(* This file is part of Witan. *) +(* *) +(* Copyright (C) 2017 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* INRIA (Institut National de Recherche en Informatique et en *) +(* Automatique) *) +(* CNRS (Centre national de la recherche scientifique) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(*************************************************************************) + +open Witan_popop_lib +open Nodes + +let synsem = ThTermKind.create_key (module struct type t = Expr.Term.t let name = "syntax" end) + +module ThTerm = RegisterThTerm(struct + let key = synsem + include Expr.Term + end) + +let node_of_term x = ThTerm.node (ThTerm.index x) + + +type env = { + converters: (Egraph.t -> Expr.Term.t -> Node.t option) list; + decvars: (Expr.Term.t -> Node.t -> Egraph.choice option) list; +} + +let converters = Env.create_key (module struct + type t = env + let name = "Synsem.converters" + end) + +let register_converter env r = + let e = Egraph.get_env env converters in + Egraph.set_env env converters {e with converters = r::e.converters} + +let register_decvars env r = + let e = Egraph.get_env env converters in + Egraph.set_env env converters {e with decvars = r::e.decvars} + +let () = Env.register (fun _ _ -> ()) converters + +module DaemonConvertTerm = struct + let key = Demon.Fast.create "Synsem.DaemonConvertTerm" + + module Data = Popop_stdlib.DUnit + + let immediate = false + let throttle = 100 + let wakeup d = function + | Events.Fired.EventRegSem(thterm,()) -> + begin try begin + let e = Egraph.get_env d converters in + let thterm = ThTerm.coerce_thterm thterm in + let v = ThTerm.sem thterm in + begin match v with + | { descr = App({builtin = Dolmen_std.Expr.Base; _ },_,[]); _ } -> + let n = ThTerm.node thterm in + List.iter (fun f -> + Opt.iter + (Egraph.register_decision d) + (f v n) + ) e.decvars + | _ -> () + end; + let iter conv = + match conv d v with + | None -> () + | Some node -> + Egraph.register d node; + Egraph.merge d (ThTerm.node thterm) node + in + List.iter iter e.converters + end with Exit -> () end + | _ -> raise UnwaitedEvent + +end + +module RDaemonConvertTerm = Demon.Fast.Register(DaemonConvertTerm) + +let init env = + Egraph.set_env env converters {converters=[]; decvars = []}; + RDaemonConvertTerm.init env; + Demon.Fast.attach env + DaemonConvertTerm.key [Demon.Create.EventRegSem(ThTerm.key,())]; + +include ThTerm diff --git a/src/solver/notypecheck.mli b/src/core/synTerm.mli similarity index 64% rename from src/solver/notypecheck.mli rename to src/core/synTerm.mli index 6276577418fe6ff4a4261e9cc0ea84086379bf7f..17bf2bce8e10819415064c1ed47c6fe3e167b455 100644 --- a/src/solver/notypecheck.mli +++ b/src/core/synTerm.mli @@ -1,9 +1,12 @@ (*************************************************************************) -(* This file is part of Colibrics. *) +(* This file is part of Witan. *) (* *) (* Copyright (C) 2017 *) (* CEA (Commissariat à l'énergie atomique et aux énergies *) (* alternatives) *) +(* INRIA (Institut National de Recherche en Informatique et en *) +(* Automatique) *) +(* CNRS (Centre national de la recherche scientifique) *) (* *) (* you can redistribute it and/or modify it under the terms of the GNU *) (* Lesser General Public License as published by the Free Software *) @@ -18,12 +21,25 @@ (* for more details (enclosed in the file licenses/LGPLv2.1). *) (*************************************************************************) -exception Typing_error of string * Dolmen.Term.t +open Nodes -val get_loc: Dolmen.Term.t -> Dolmen.ParseLocation.t +val key: Dolmen_std.Expr.Term.t ThTermKind.t -val run: - ?limit:int -> - theories:(Egraph.t -> unit) list -> - (unit -> Dolmen.Statement.t option) -> - [> `Sat | `Unsat ] +include RegisteredThTerm with type s = Expr.Term.t + +val node_of_term : Expr.Term.t -> Node.t + +val init: Egraph.t -> unit + +val register_converter: + Egraph.t -> + (Egraph.t -> Expr.Term.t -> Node.t option) -> + unit +(** register converters between syntactic terms *) + + +val register_decvars: + Egraph.t -> + (Expr.Term.t -> Node.t -> Egraph.choice option) -> + unit +(** register decision adder on variables *) diff --git a/src/core/trail.ml b/src/core/trail.ml deleted file mode 100644 index 36fafe02f8f1ba25912b287d5c892d4b3515170d..0000000000000000000000000000000000000000 --- a/src/core/trail.ml +++ /dev/null @@ -1,32 +0,0 @@ -(*************************************************************************) -(* This file is part of Colibrics. *) -(* *) -(* Copyright (C) 2017 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(*************************************************************************) - -(** explanation are removed from Colibrics *) -module Pexp = Witan_popop_lib.Popop_stdlib.DUnit -module Exp = struct - type 'a t = unit - include (Witan_popop_lib.Popop_stdlib.DUnit : Witan_popop_lib.Popop_stdlib.Datatype with type t := unit) -end -module Chogen = Witan_popop_lib.Popop_stdlib.DUnit -type chogen = Chogen.t -module Age = Witan_popop_lib.Popop_stdlib.DUnit -type age = Age.t -type t = unit -type dec = unit diff --git a/src/core/witan_core.ml b/src/core/witan_core.ml index 77ead76da405d97c23a117618bd3270855d78be1..0092fca85ce4350ef18ebc0fd535efb6539f9163 100644 --- a/src/core/witan_core.ml +++ b/src/core/witan_core.ml @@ -20,8 +20,8 @@ (** Witan core: define basic types and the solver *) -module Id = Id -module Term = Term +module Expr = Expr +module Term = Expr.Term module Ty = Ty module Keys = Keys @@ -80,16 +80,11 @@ end module Env = Env -module Exp = Trail.Exp - module Egraph = Egraph -module Trail = Trail module Events = Events module Demon = Demon -module Conflict = Conflict - exception UnwaitedEvent = Nodes.UnwaitedEvent (** Can be raised by daemon when receiving an event that they don't waited for. It is the sign of a bug in the core solver *) diff --git a/src/popop_lib/dune b/src/popop_lib/dune index 35ba3fe2c6018aa8cb75871b4f20b3fdeb55f352..c3b02b2180542500799c811cf8d1bbb9a4ebc816 100644 --- a/src/popop_lib/dune +++ b/src/popop_lib/dune @@ -4,7 +4,7 @@ (name witan_popop_lib) (public_name witan.popop_lib) (synopsis "Temporary for witan (intended to be replaced by another library)") - (libraries str unix zarith) + (libraries str unix zarith base) (flags :standard -w +a-4-42-44-48-50-58-32-60-40-9@8 -color always) (ocamlopt_flags :standard -O3 -bin-annot -unbox-closures -unbox-closures-factor 20)) diff --git a/src/popop_lib/popop_stdlib.ml b/src/popop_lib/popop_stdlib.ml index fe7be2908b4c20e1782909271e9542d0c30b0a38..09c34e3861b07a626289eaa6b12c21a8f69cdd8f 100644 --- a/src/popop_lib/popop_stdlib.ml +++ b/src/popop_lib/popop_stdlib.ml @@ -63,6 +63,7 @@ module MakeMSH (X : TaggedType) = struct module T = OrderedHashed(X) include T + let hash_fold_t state t = Base.Hash.fold_int state (X.tag t) module MGen = Intmap.Make(struct include X let equal ts1 ts2 = X.tag ts1 == X.tag ts2 @@ -90,6 +91,7 @@ end module type Datatype = sig include OrderedHashedType + val hash_fold_t: Base.Hash.state -> t -> Base.Hash.state module M : Map_intf.PMap with type key = t module S : Map_intf.Set with type 'a M.t = 'a M.t and type M.key = M.key @@ -102,6 +104,7 @@ module type Printable = sig end module MkDatatype(T : OrderedHashedType) = struct + let hash_fold_t state t = Base.Hash.fold_int state (T.hash t) module M = Map.Make(T) module S = Extset.MakeOfMap(M) module H = XHashtbl.Make(T) @@ -122,6 +125,7 @@ module Int = struct module DInt = struct include Int let pp fmt x = Format.pp_print_int fmt x + let hash_fold_t = Base.Int.hash_fold_t module GM = Intmap.Make(Int) module M = GM.NT module S = Extset.MakeOfMap(M) @@ -142,6 +146,7 @@ end module DBool = struct include Bool + let hash_fold_t = Base.Bool.hash_fold_t module M = Map.Make(Bool) module S = Extset.MakeOfMap(M) module H = XHashtbl.Make(Bool) @@ -156,6 +161,7 @@ module DStr = struct let pp = Format.pp_print_string end include Str + let hash_fold_t = Base.String.hash_fold_t module M = Map.Make(Str) module S = Extset.MakeOfMap(M) module H = XHashtbl.Make(Str) @@ -171,7 +177,7 @@ module Float = struct let pp = Format.pp_print_float end include Float - + let hash_fold_t = Base.Float.hash_fold_t module M = Map.Make(Float) module S = Extset.MakeOfMap(M) module H = XHashtbl.Make(Float) diff --git a/src/popop_lib/popop_stdlib.mli b/src/popop_lib/popop_stdlib.mli index 5b8d425b5cc9c3676183c1d0c7f70ea9d97d4328..1df2d7296cd1d762039151da87a0fdbb7aee5508 100644 --- a/src/popop_lib/popop_stdlib.mli +++ b/src/popop_lib/popop_stdlib.mli @@ -41,6 +41,7 @@ end module type Datatype = sig include OrderedHashedType + val hash_fold_t: t Base.Hash.folder module M : Map_intf.PMap with type key = t module S : Map_intf.Set with type 'a M.t = 'a M.t @@ -54,6 +55,7 @@ module type Printable = sig end module MkDatatype(T : OrderedHashedType) : sig + val hash_fold_t: T.t Base.Hash.folder module M : Map_intf.PMap with type key = T.t module S : Map_intf.Set with type 'a M.t = 'a M.t and type M.key = M.key diff --git a/src/popop_lib/unit.ml b/src/popop_lib/unit.ml index 826c994f7974e7e8997daad8d68227d595555197..0d457c6487d461e1ae5698f86af194e5e7fee99c 100644 --- a/src/popop_lib/unit.ml +++ b/src/popop_lib/unit.ml @@ -24,6 +24,7 @@ let compare () () = 0 let equal () () = true let hash _ = 0 let pp fmt () = Format.pp_print_string fmt "()" +let hash_fold_t = Base.Unit.hash_fold_t module M = struct type key = unit diff --git a/src/popop_lib/unit.mli b/src/popop_lib/unit.mli index 233a4dadd9d3682a1e51278b8a80fe1ad556455d..43c11eaeb51cfae742aac3baaf62dc094405d962 100644 --- a/src/popop_lib/unit.mli +++ b/src/popop_lib/unit.mli @@ -24,6 +24,7 @@ type t = unit val hash : t -> int val equal : t -> t -> bool val compare : t -> t -> int +val hash_fold_t: t Base.Hash.folder val pp: t Pp.pp module M: Map_intf.Map with type key = unit diff --git a/src/solver/dune b/src/solver/dune index ac2167626d439ea6dbda84ba4995ad4743722401..d22b11cfc67ba305f5305c45ab85e76810c28de3 100644 --- a/src/solver/dune +++ b/src/solver/dune @@ -3,7 +3,7 @@ (public_name witan.solver) (synopsis "witan's solver") (libraries containers zarith ocamlgraph gen dolmen spelll witan.stdlib - witan.popop_lib str witan.core witan.core.structures) + witan.popop_lib str witan.core witan.core.structures dolmen_loop) (preprocess (pps ppx_deriving.std)) (flags :standard -w +a-4-42-44-48-50-58-32-60-40-9@8 -color always -open diff --git a/src/solver/input.ml b/src/solver/input.ml index a6bd478b40959065e8cc1d0f5918226ce4850ee0..024c098b59128511f7150519c860b21a7ce72e0d 100644 --- a/src/solver/input.ml +++ b/src/solver/input.ml @@ -18,69 +18,310 @@ (* for more details (enclosed in the file licenses/LGPLv2.1). *) (*************************************************************************) -(* The Dolmen library is used to parse input languages *) -(* ************************************************************************ *) - -exception File_not_found of string -(** Raised when file is not found. *) - -(** See documentation at - {{:http://gbury.github.io/dolmen/dev/Logic.Make.html} Logic.Make} *) -module P = Dolmen.Logic.Make - (Dolmen.ParseLocation) - (Dolmen.Id) - (Dolmen.Term) - (Dolmen.Statement) - -(* Some re-export of definitions *) -type language = P.language = - | Dimacs - | ICNF - | Smtlib - | Tptp - | Zf - -let enum = P.enum - -(** Convenience function to expand includes *) -let read_aux ~language ~dir input = - let acc = ref [input] in - let rec aux () = - match !acc with - | [] -> None - | g :: r -> - begin match g () with - | None -> acc := r; aux () - | Some { Dolmen.Statement.descr = Dolmen.Statement.Include f; _ } -> - let file = match P.find ~language ~dir f with - | None -> raise (File_not_found f) - | Some f -> f - in - let _, g', _ = P.parse_input ~language (`File file) in - acc := g' :: !acc; - aux () - | (Some _) as res -> res +type ctx = { + scheduler : Scheduler.t; + mutable state: [`Sat of Egraph.t | `Unknown | `Unsat | `StepLimitReached]; + mutable pushpop: Scheduler.bp list; +} + +let create_ctx theories = + let t = Scheduler.new_solver () in + Scheduler.init_theories t ~theories; + { + scheduler = t; + state = `Unknown; + pushpop = []; + } + +module State = struct + include Dolmen_loop.State + type t = ctx state + let is_interactive _ = false +end +module Pipeline = Dolmen_loop.Pipeline.Make(State) + +module Parser = Dolmen_loop.Parser.Pipe(Dolmen.Std.Expr)(State) +module Header = Dolmen_loop.Headers.Pipe(State) +module Typer = struct + module T = Dolmen_loop.Typer.Make(State) + include T + include Dolmen_loop.Typer.Pipe(Dolmen.Std.Expr)(State)(T) +end + +let split_input = function + | `Stdin -> + Sys.getcwd (), `Stdin + | `File f -> + Filename.dirname f, `File (Filename.basename f) + +let print_exn st = function + + (* Sigint, potentially wrapped by the typechecker *) + | Pipeline.Sigint + | Dolmen_loop.Typer.T.Typing_error ( + Dolmen_loop.Typer.T.Error (_, _, Dolmen_loop.Typer.T.Uncaught_exn ( + Pipeline.Sigint, _))) -> + Format.pp_print_flush Format.std_formatter (); + State.error st "User Interrupt" + + (* Timeout, potentially wrapped by the typechecker *) + | Pipeline.Out_of_time + | Dolmen_loop.Typer.T.Typing_error ( + Dolmen_loop.Typer.T.Error (_, _, Dolmen_loop.Typer.T.Uncaught_exn ( + Pipeline.Out_of_time, _))) -> + Format.pp_print_flush Format.std_formatter (); + State.error st "Time limit reached" + + | Pipeline.Out_of_space + | Dolmen_loop.Typer.T.Typing_error ( + Dolmen_loop.Typer.T.Error (_, _, Dolmen_loop.Typer.T.Uncaught_exn ( + Pipeline.Out_of_space, _))) -> + Format.pp_print_flush Format.std_formatter (); + State.error st "Memory limit reached" + + (* Parsing errors *) + | Dolmen.Std.Loc.Uncaught (loc, exn) -> + let file = Dolmen_loop.State.input_file_loc st in + State.error ~loc:{ file; loc; } st "%s" (Printexc.to_string exn) + | Dolmen.Std.Loc.Lexing_error (loc, lex) -> + let file = Dolmen_loop.State.input_file_loc st in + State.error ~loc:{ file; loc; } st "Lexing error: invalid character '%s'" lex + | Dolmen.Std.Loc.Syntax_error (loc, `Regular msg) -> + let file = Dolmen_loop.State.input_file_loc st in + State.error ~loc: { file; loc; } st "%t@." msg + | Dolmen.Std.Loc.Syntax_error (loc, `Advanced (prod, lexed, expected)) -> + let file = Dolmen_loop.State.input_file_loc st in + State.error ~loc: { file; loc; } st + "@[<v>@[<hv>while parsing %t,@ read %t,@]@ @[<hov>but expected %t.@]@]" + prod lexed expected + + (* Typing errors *) + | Dolmen_loop.Typer.T.Typing_error ( + Dolmen_loop.Typer.T.Error (env, fragment, _err) as error) -> + let loc = Dolmen_loop.Typer.T.fragment_loc env fragment in + if st.context then + Format.eprintf "@[<hv 2>While typing:@ @[<hov>%a@]@]@." + Typer.print_fragment (env, fragment); + State.error ~loc st "%a" + Typer.report_error error + + (* State errors *) + | Dolmen_loop.State.File_not_found (loc, dir, f) -> + if dir = "." then + State.error ~loc st "File not found: '%s'" f + else + State.error ~loc st "File not found: '%s' in directory '%s'" f dir + | Dolmen_loop.State.Input_lang_changed (l, l') -> + State.error st "Input language changed from %s to %s (probably because of an include statement)" + (Dolmen_loop.Logic.string_of_language l) + (Dolmen_loop.Logic.string_of_language l') + + (* Internal Dolmen Expr errors *) + | Dolmen.Std.Expr.Bad_ty_arity (c, l) -> + let pp_sep fmt () = Format.fprintf fmt ";@ " in + State.error st "@[<hv>Internal error: Bad arity for type constant '%a',@ which was provided arguments:@ [@[<hv>%a@]]@]" + Dolmen.Std.Expr.Print.ty_const c (Format.pp_print_list ~pp_sep Dolmen.Std.Expr.Ty.print) l + | Dolmen.Std.Expr.Bad_term_arity (c, tys, ts) -> + let pp_sep fmt () = Format.fprintf fmt ";@ " in + State.error st "@[<hv>Internal error: Bad arity for type constant '%a',@ which was provided arguments:@ [@[<hv>%a;@ %a@]]@]" + Dolmen.Std.Expr.Print.term_const c + (Format.pp_print_list ~pp_sep Dolmen.Std.Expr.Ty.print) tys + (Format.pp_print_list ~pp_sep Dolmen.Std.Expr.Term.print) ts + | Dolmen.Std.Expr.Type_already_defined c -> + State.error st "@[<hv>Internal error: Type constant '%a' was already defined earlier,@ cannot re-define it.@]" + Dolmen.Std.Expr.Print.id c + + | Dolmen.Std.Expr.Term.Wrong_type (t, ty) -> + State.error st "@[<hv>Internal error: A term of type@ %a@ was expected but instead got a term of type@ %a@]" + Dolmen.Std.Expr.Ty.print ty Dolmen.Std.Expr.Ty.print (Dolmen.Std.Expr.Term.ty t) + + (* File format auto-detect *) + | Dolmen_loop.Logic.Extension_not_found ext -> + State.error st "@[<hv>The following extension was not recognized: '%s'.@ %s" ext + "Please use a recognised extension or specify an input language on the command line" + + (* Generic catch-all *) + | e -> State.error st "@[<hv>Unhandled exception:@ %s@]" (Printexc.to_string e) + + +let handle_exn_with_exit st exn = + if st.State.debug then + Format.eprintf "%a@\n%s@." + State.debug st + (Printexc.to_string exn); + let () = print_exn st exn in + exit 2 + +let handle_exn_with_error _ exn = + raise exn + + +let finally ~handle_exn st e = + match st.State.solve_state.state,e with + | `StepLimitReached, None -> + raise Scheduler.ReachStepLimit + | _, None -> st + | _, Some exn -> + handle_exn st exn; + assert false + +let debug_pipe st c = + if st.State.debug then + Format.eprintf "%a@\n%a@." + State.debug st + Dolmen.Std.Statement.print c; + st, c + +let def _st _d = invalid_arg "unimplemented" + +let set_term_true ~set_true d t = + let t = SynTerm.node_of_term t in + Egraph.register d t; + set_true d t + +let hyp ~set_true st t = + Scheduler.add_assertion st.scheduler (fun d -> + set_term_true ~set_true d t + ) + +let solve ?limit ~set_true st t = + let check st = + match Scheduler.check_sat ?limit st.scheduler with + | res -> st.state <- res + | exception Scheduler.ReachStepLimit -> + st.state <- `StepLimitReached + in + match t with + | [] -> check st; + | l -> + let bp = Scheduler.push st.scheduler in + Scheduler.add_assertion st.scheduler (fun d -> + List.iter (set_term_true ~set_true d) l + ); + check st; + Scheduler.pop_to st.scheduler bp + +let rec push st i = + assert (0 <= i); + if 0 < i then begin + st.pushpop <- (Scheduler.push st.scheduler)::st.pushpop; + push st (i-1) + end + +let rec pop st i = + assert (0 <= i); + match i, st.pushpop with + | 0, _ -> () + | _, [] -> assert false (* absurd by dolmen invariant *) + | 1, bp::l -> + st.pushpop <- l; + Scheduler.pop_to st.scheduler bp + | n, _::l -> + st.pushpop <- l; + pop st (n-1) + + +let handle_stmt ?(show_checksat_result=true) ?limit ~set_true (st:State.t) (stmt:Typer.typechecked Typer.stmt) = + begin match stmt.contents with + | `Reset + | `Get_unsat_core + | `Plain _ + | `Get_assignment + | `Get_unsat_assumptions + | `Get_info _ + | `Get_proof + | `Get_assertions + | `Get_value _ + | `Get_option _ + | `Get_model + | `Reset_assertions + | `Set_option _ -> invalid_arg "Unimplemented stmt" + | `Push i -> push st.State.solve_state i + | `Pop i -> pop st.State.solve_state i + | `Decls _ -> (* nothing to do handled by dolmen *) () + | `Defs d -> List.iter (def st.State.solve_state) d + | `Goal _ -> invalid_arg "unimplemented" + | `Clause l -> hyp ~set_true st.State.solve_state (Expr.Term._or l) + | `Hyp d -> hyp ~set_true st.State.solve_state d + | `Solve s -> begin + solve ~set_true ?limit st.State.solve_state s; + if show_checksat_result then + match st.State.solve_state.state with + | `Unsat -> Format.printf "unsat@." + | `Sat _ -> Format.printf "sat@." + | `Unknown -> Format.printf "unknown@." + | `StepLimitReached -> Format.printf "steplimitreached@." end + | `Echo s -> Format.printf "%s@." s + | `Set_info _ -> () + | `Set_logic _ -> (* Perhaps something to do here *) () + | `Exit -> () + end; + st, () + +let read ?show_checksat_result ?limit ~set_true ~handle_exn st = + let st, g = + try Parser.parse [] st + with exn -> + handle_exn st exn; + assert false in - aux - -let read ?language ~dir f = - (** Formats Dimacs and Tptp are descriptive and lack the emission - of formal solve/prove instructions, so we need to add them. *) - let s = Dolmen.Statement.include_ f [] in - (* Auto-detect input format *) - let language = - match language with - | Some l -> l - | None -> let res, _, _ = P.of_filename f in res + let st = + let open Pipeline in + run ~finally:(finally ~handle_exn) g st ( + (fix (op ~name:"expand" Parser.expand) ( + (op ~name:"debug" debug_pipe) + @>>> (op ~name:"headers" Header.inspect) + @>>> (op ~name:"typecheck" Typer.typecheck) + @>|> (op (handle_stmt ?show_checksat_result ?limit ~set_true)) @>>> _end + ) + ) + ) in - let g = - match language with - | P.Zf - | P.ICNF - | P.Smtlib -> Gen.singleton s - | P.Dimacs - | P.Tptp -> Gen.of_list [s; Dolmen.Statement.prove ()] + let st = Header.check st in + let _st = Dolmen_loop.State.flush st () in + () + +let mk_state + ?(gc=false) ?(gc_opt=Gc.get ()) ?(bt=true) ?(colors=true) + ?(time_limit=1_000_000_000.) ?(size_limit=1_000_000_000.) + ?input_lang ?input_mode ~input + ?(header_check=false) ?(header_licenses=[]) + ?(header_lang_version=None) + ?(type_strict=true) + ?(debug=false) ?(context=true) ?(max_warn=max_int) + theories + = + (* Side-effects *) + let () = Gc.set gc_opt in + let () = + let style = if colors then `Ansi_tty else `None in + Fmt.set_style_renderer Format.err_formatter style; in - read_aux ~language ~dir g + let () = if bt then Printexc.record_backtrace true in + let () = if gc then at_exit (fun () -> Gc.print_stat stdout;) in + (* State creation *) + let input_dir, input_source = split_input input in + let st : State.t = { + debug; + + context; max_warn; + cur_warn = 0; + + time_limit; size_limit; + + input_dir; input_lang; + input_mode; input_source; + input_file_loc = Dolmen.Std.Loc.mk_file ""; + + header_check; header_licenses; header_lang_version; + header_state = Dolmen_loop.Headers.empty; + + type_check = true; type_strict; + type_state = Dolmen_loop.Typer.new_state (); + + solve_state = create_ctx theories; + export_lang = []; + } in + st diff --git a/src/solver/input.mli b/src/solver/input.mli deleted file mode 100644 index ce5bce6a8d32765af34bb1e5eaf16d93ab1e026f..0000000000000000000000000000000000000000 --- a/src/solver/input.mli +++ /dev/null @@ -1,38 +0,0 @@ -(*************************************************************************) -(* This file is part of Colibrics. *) -(* *) -(* Copyright (C) 2017 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(*************************************************************************) - -(** Problem input for Witan *) - -(** {2 Parsing some input} *) - -type language = - | Dimacs (** The dimacs language *) - | ICNF (** iCNF is ane xtension of dimacs *) - | Smtlib (** smtlib language *) - | Tptp (** TPTP problems language *) - | Zf (** Zipperposition format *) -(** The type of input language supported. *) - -val enum : (string * language) list -(** Enumeration of pairs of a language and its name, mainly for use by cmdliner. *) - -val read : ?language:language -> dir:string -> string -> Dolmen.Statement.t Gen.t -(** Read a file in a directory. Automatically expands all include statements. - @language: if set, overrides input language auto-detection performed by dolmen. *) diff --git a/src/solver/notypecheck.ml b/src/solver/notypecheck.ml deleted file mode 100644 index 1a4c2ee6fd9ed16fcab463996442de57443c773c..0000000000000000000000000000000000000000 --- a/src/solver/notypecheck.ml +++ /dev/null @@ -1,361 +0,0 @@ -(*************************************************************************) -(* This file is part of Colibrics. *) -(* *) -(* Copyright (C) 2017 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(*************************************************************************) - -open Witan_popop_lib - -(* Exception for typing errors *) -module R = Exthtbl.Hashtbl.Make(Dolmen.Id) -module MId = CCMap.Make(struct include Dolmen.Id let pp = print end) -type env = Term.Id.t R.t - -let create_env () = - R.create 10 - -exception Typing_error of string * Dolmen.Term.t - -let _bad_op_arity _ s n t = - let msg = Format.asprintf "Bad arity for operator '%s' (expected %d arguments)" s n in - raise (Typing_error (msg, t)) - -let regexp_decimal = Str.regexp "^[0-9]+\\(\\.[0-9]*\\)?$" - -(** no typing *) -let rec parse_formula' (env:env) (lets:Term.t MId.t) (t:Dolmen.Term.t) = - let module Ast = Dolmen.Term in - let open Term in - match t with - - (* Ttype & builtin types *) - | { Ast.term = Ast.Builtin Ast.Ttype } -> - _Type - | { Ast.term = Ast.Builtin Ast.Prop } -> - _Prop - - | { Ast.term = Ast.Symbol {Dolmen.Id.name = "Real"} } -> - _Real - - (* Basic formulas *) - | { Ast.term = Ast.App ({ Ast.term = Ast.Builtin Ast.True }, []) } - | { Ast.term = Ast.Builtin Ast.True } -> - true_term - - | { Ast.term = Ast.App ({ Ast.term = Ast.Builtin Ast.False }, []) } - | { Ast.term = Ast.Builtin Ast.False } -> - false_term - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.And}, l) } -> - let f = (and_term (List.length l)) in - let l = (List.map (parse_formula env lets) l) in - apply f l - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Or}, l) } -> - apply (or_term (List.length l)) (List.map (parse_formula env lets) l) - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Xor}, l) } as t -> - begin match l with - | [p; q] -> - let f = parse_formula env lets p in - let g = parse_formula env lets q in - apply not_term [apply equal_term [f.Term.ty;f;g]] - | _ -> _bad_op_arity env "xor" 2 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Imply}, l) } as t -> - begin match l with - | [p; q] -> - let f = parse_formula env lets p in - let g = parse_formula env lets q in - apply imply_term [f;g] - | _ -> _bad_op_arity env "=>" 2 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Equiv}, l) } as t -> - begin match l with - | [p; q] -> - let f = parse_formula env lets p in - let g = parse_formula env lets q in - apply equiv_term [f;g] - | _ -> _bad_op_arity env "<=>" 2 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Not}, l) } as t -> - begin match l with - | [p] -> - apply not_term [parse_formula env lets p] - | _ -> _bad_op_arity env "not" 1 t - end - - (* (\* Binders *\) - * | { Ast.term = Ast.Binder (Ast.All, vars, f) } -> - * let ttype_vars, ty_vars, env' = - * parse_quant_vars (expect env (Typed Expr.Ty.base)) vars in - * Formula ( - * mk_quant_ty env' Expr.Formula.allty ttype_vars - * (mk_quant_term env' Expr.Formula.all ty_vars - * (parse_formula env' f))) - * - * | { Ast.term = Ast.Binder (Ast.Ex, vars, f) } -> - * let ttype_vars, ty_vars, env' = - * parse_quant_vars (expect env (Typed Expr.Ty.base)) vars in - * Formula ( - * mk_quant_ty env' Expr.Formula.exty ttype_vars - * (mk_quant_term env' Expr.Formula.ex ty_vars - * (parse_formula env' f))) *) - - (* (Dis)Equality *) - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Eq}, l) } as t -> - begin match l with - | [a; b] -> - let a = parse_formula env lets a in - let b = parse_formula env lets b in - apply equal_term [a.Term.ty;a;b] - (* begin match promote env t @@ parse_expr env a, - * promote env t @@ parse_expr env b with - * | Term t1, Term t2 -> - * Formula (make_eq env t t1 t2) - * | Formula f1, Formula f2 -> - * Formula (Expr.Formula.equiv f1 f2) - * | _ -> - * _expected env "either two terms or two formulas" t None - * end *) - | _ -> _bad_op_arity env "=" 2 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Distinct}, a::args) } -> - let a = parse_formula env lets a in - apply (distinct_term (List.length args + 1)) (a.Term.ty::a::(List.map (parse_formula env lets) args)) - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Ite}, l) } - | { Ast.term = Ast.App ({Ast.term = Ast.Symbol {Dolmen.Id.name = "ite"}}, l) } -> - begin match l with - | [cond;then_; else_] -> - let cond = parse_formula env lets cond in - let then_ = parse_formula env lets then_ in - let else_ = parse_formula env lets else_ in - apply ite_term [then_.Term.ty;cond;then_;else_] - | _ -> _bad_op_arity env "ite" 3 t - end - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Add}, l) } - | { Ast.term = Ast.App ({Ast.term = Ast.Symbol {Dolmen.Id.name = "+"}}, l) } -> - let f = (add_real_term (List.length l)) in - let l = (List.map (parse_formula env lets) l) in - apply f l - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Sub}, ([_;_] as l)) } - | { Ast.term = Ast.App ({Ast.term = Ast.Symbol {Dolmen.Id.name = "-"}}, ([_;_] as l)) } -> - let f = sub_real_term in - let l = (List.map (parse_formula env lets) l) in - apply f l - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Sub}, ([_] as l)) } - | { Ast.term = Ast.App ({Ast.term = Ast.Symbol {Dolmen.Id.name = "-"}}, ([_] as l)) } -> - let f = neg_real_term in - let l = (List.map (parse_formula env lets) l) in - apply f l - - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Mult}, ([_;_] as l)) } - | { Ast.term = Ast.App ({Ast.term = Ast.Symbol {Dolmen.Id.name = "*"}}, ([_;_] as l)) } -> - let f = mul_real_term in - let l = (List.map (parse_formula env lets) l) in - apply f l - - | {Ast.term = Ast.Symbol {Dolmen.Id.name = cst}} - | { Ast.term = Ast.App ({Ast.term = Ast.Symbol {Dolmen.Id.name = cst}}, []) } when Str.string_match regexp_decimal cst 0 -> - const_real_term cst - - (* General case: application *) - | { Ast.term = Ast.Symbol s } as ast -> - begin match MId.find_opt s lets with - | Some t -> t - | None -> - begin match R.find_opt env s with - | Some id -> (const id) - | None -> raise (Typing_error("unbound variable",ast)) - end - end - - | { Ast.term = Ast.App ({ Ast.term = Ast.Symbol s }, l) } as ast -> - begin match MId.find_opt s lets with - | Some t -> apply t (List.map (parse_formula env lets) l) - | None -> - begin match R.find_opt env s with - | Some id -> apply (const id) (List.map (parse_formula env lets) l) - | None -> raise (Typing_error("unbound variable",ast)) - end - end - - | { term = Ast.Binder (_,[],t); _; } -> - parse_formula env lets t - - (* Local bindings *) - | { Ast.term = Ast.Binder (Ast.Let, vars, f) } -> - let rec aux lets = function - | [] -> parse_formula env lets f - | {Ast.term = Ast.Colon({Ast.term = Ast.Symbol s},t)}::l -> - let t = parse_formula env lets t in - if false then - let s' = Format.asprintf "%a" Dolmen.Id.print s in - let id = Witan_core.Id.mk s' t.Term.ty in - R.add env s id; - let l = aux lets l in - R.remove env s; - Term.letin id t l - else - let lets = MId.add s t lets in - aux lets l - | t::_ -> - raise (Typing_error ("Unexpected let binding", t)) - in - aux lets vars - - (* Functionnal arrows *) - | { Ast.term = Ast.Binder (Ast.Arrow, vars, f) } -> - Term.arrows (List.map (parse_formula env lets) vars) (parse_formula env lets f) - - (* Other cases *) - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin _}, _) } -> - raise (Typing_error ("Unexpected builtin", t)) - | { term = Ast.Builtin _; _; } -> - raise (Typing_error ("Unexpected builtin", t)) - | { term = Ast.Colon (_,_); _; } -> - raise (Typing_error ("Unexpected colon", t)) - | { term = Ast.App (_,_); _; }-> - raise (Typing_error ("Unexpected app", t)) - | { term = Ast.Binder (_,_,_); _; } -> - raise (Typing_error ("Unexpected binder", t)) - | { term = Ast.Match (_,_); _; } -> - raise (Typing_error ("Unexpected construction", t)) - -and parse_formula (env:env) lets (t:Dolmen.Term.t) = - try - parse_formula' env lets t - with - | (Typing_error _) as exn -> raise exn - | exn -> - raise (Typing_error (Printexc.to_string exn, t)) - -let rec parse_clause_lit (env:env) t = - let module Ast = Dolmen.Term in - let open Term in - match t with - | { Ast.term = Ast.Symbol s } - | { Ast.term = Ast.App ({ Ast.term = Ast.Symbol s }, []) } -> - let id = R.memo (fun id -> - let s = Format.asprintf "%a" Dolmen.Id.print id in - (** only in dimacs they are not declared *) - Witan_core.Id.mk s _Prop) env s in - const id - | { Ast.term = Ast.App ({Ast.term = Ast.Builtin Ast.Not}, l) } as t -> - begin match l with - | [p] -> - apply not_term [parse_clause_lit env p] - | _ -> _bad_op_arity env "not" 1 t - end - | _ -> - raise (Typing_error ("Unexpected construction in dimacs", t)) - - -let get_loc = - let default_loc = Dolmen.ParseLocation.mk "<?>" 0 0 0 0 in - (fun t -> CCOpt.get_or ~default:default_loc t.Dolmen.Term.loc) - -(** used to complete partial model *) -let get_model env d = - let model : Value.t Term.H.t = Term.H.create 16 in - R.iter (fun _ id -> - let t = Term.const id in - let n = SynTerm.node_of_term t in - let v = Interp.model d n in - Term.H.add_new Std.Impossible model t v) - env; - model - -let interp_model model n = - let leaf t = Term.H.find_opt model t in - (Interp.node ~leaf n) - -let check_model model expected n = - Value.equal (interp_model model n) expected - -let run ?limit ~theories statements = - let env = create_env () in - let clauses = ref [] in - let open Witan_core in - let res = - Scheduler.run - ~theories - ?limit - (fun d -> - Gen.iter (fun stmt -> - let open Dolmen.Statement in - match stmt.descr with - | Set_logic _ -> () - | Set_info _ -> () - | Prove -> () - | Dolmen.Statement.Exit -> () - | Decl (id,t) -> - let t = Dolmen.Normalize.smtlib t in - let ty = parse_formula env MId.empty t in - let t' = - let s = Format.asprintf "%a" Dolmen.Id.print id in - Witan_core.Id.mk s ty - in - R.add_new Witan_stdlib.Std.Impossible env id t'; - | Clause l -> - let map t = SynTerm.node_of_term (parse_clause_lit env t), Witan_core.Conflict.Pos in - let l = Witan_stdlib.Shuffle.shufflel l in - let l = List.map map l in - let l = Witan_stdlib.Shuffle.shufflel l in - let cl = !Witan_core.Conflict._or l in - clauses := cl::!clauses; - Egraph.register d cl; - !Witan_core.Conflict._set_true d Trail.pexp_fact cl - | Antecedent t -> - let map t = SynTerm.node_of_term (parse_formula env MId.empty t) in - let t = Dolmen.Normalize.smtlib t in - let cl = map t in - clauses := cl::!clauses; - Egraph.register d cl; - !Witan_core.Conflict._set_true d Trail.pexp_fact cl - | _ -> invalid_arg (Format.asprintf "Unimplemented command: %a" Dolmen.Statement.print stmt)) - statements) in - match res with - | `Contradiction -> `Unsat - | `Done _d -> - (* let model = get_model env d in - * Format.printf "(%a)@." - * Witan_popop_lib.Pp.(iter22 Witan_core.Term.H.iter space - * (fun fmt t v -> Format.fprintf fmt "(%a %a)" - * Witan_core.Term.pp t Witan_core.Values.pp v)) - * model *) - `Sat - - - -let () = Exn_printer.register (fun fmt exn -> - match exn with - | Typing_error (msg, t) -> - Format.fprintf fmt - "%a:@\n%s:@ %a" - Dolmen.ParseLocation.fmt (get_loc t) msg - Dolmen.Term.print t; - | exn -> raise exn - ) diff --git a/src/solver/scheduler.ml b/src/solver/scheduler.ml index f0e90ab70e5c7e2f32f9a9e114e997a8eb568784..e5a5352f7e16c905751c85f29aaf36191efa3995 100644 --- a/src/solver/scheduler.ml +++ b/src/solver/scheduler.ml @@ -21,8 +21,6 @@ open Witan_popop_lib open Witan_core -module S = Egraph - let debug = Debug.register_info_flag ~desc:"for the scheduler in the simple version" "sched_queue" @@ -47,7 +45,7 @@ exception NeedStopDelayed module Att = struct type t = | Daemon of int * Events.Wait.daemon_key - | Decision of int * Trail.chogen + | Decision of int * Egraph.choice type prio = float type db = float Node.H.t @@ -61,29 +59,26 @@ module Att = struct if xp = yp then x <= y else xp >= yp (** min *) | Daemon _ , Decision _ -> true | Decision _, Daemon _ -> false - let reprio db = function + let reprio _ = function | Daemon _ -> 0. - | Decision (_,Trail.GCho(n,_,_)) -> get_prio db n + | Decision (_,choice) -> float_of_int choice.prio end -exception Contradiction + +exception Contradiction = Egraph.Contradiction module Prio = Leftistheap.Make(Att) -type pre = +type bp = { pre_wakeup_daemons : Prio.t; - pre_prev_scheduler_state : pre option; + pre_prev_scheduler_state : bp option; pre_backtrack_point : Context.bp; - pre_age_dec : Trail.Age.t; - pre_learnt : Conflict.Learnt.t Bag.t; - pre_last_dec : Trail.chogen; } type t = { mutable wakeup_daemons : Prio.t; - mutable prev_scheduler_state : pre option; - solver_state : S.Backtrackable.t; - mutable delayed : S.t option; - mutable learnt : Conflict.Learnt.t Bag.t; + mutable prev_scheduler_state : bp option; + solver_state : Egraph.Backtrackable.t; + mutable delayed : Egraph.t option; (* global *) decprio : Att.db; var_inc : float ref; @@ -97,9 +92,7 @@ let print_level fmt t = let nb_dec = Prio.fold (fun acc x _ -> match x with Att.Decision _ -> acc + 1 | _ -> acc) 0 t.wakeup_daemons in - Format.fprintf fmt "%a (level:%i, dec waiting:%i)" - Trail.Age.pp (S.Backtrackable.current_age t.solver_state) - (S.Backtrackable.current_nbdec t.solver_state) nb_dec + Format.fprintf fmt "(dec waiting:%i)" nb_dec (* let new_handler t = * if t.delayed <> None then raise NeedStopDelayed; @@ -116,30 +109,25 @@ let new_solver () = let context = Context.create () in { wakeup_daemons = Prio.empty; prev_scheduler_state = None; - solver_state = S.Backtrackable.new_t (Context.creator context); + solver_state = Egraph.Backtrackable.new_t (Context.creator context); context; - learnt = Bag.empty; delayed = None; decprio = Node.H.create 100; var_inc = ref 1.; } -let push t chogen = +let push t = if Debug.test_flag debug_dotgui then - S.Backtrackable.draw_graph ~force:true t.solver_state; + Egraph.Backtrackable.draw_graph ~force:true t.solver_state; Debug.dprintf0 debug_pushpop "[Scheduler] push"; - let age_dec = Trail.last_dec (S.Backtrackable.get_trail t.solver_state) in let prev = { pre_wakeup_daemons = t.wakeup_daemons; pre_prev_scheduler_state = t.prev_scheduler_state; pre_backtrack_point = Context.bp t.context; - pre_learnt = t.learnt; - pre_last_dec = chogen; - pre_age_dec = age_dec; } in t.prev_scheduler_state <- Some prev; - t.learnt <- Bag.empty; - ignore (Context.push t.context) + ignore (Context.push t.context); + prev let update_prio t chogen = Node.H.change (function @@ -163,7 +151,7 @@ let new_delayed = !dec_count; t.wakeup_daemons <- Prio.insert t.decprio (Att.Decision (!dec_count,dec)) t.wakeup_daemons in - S.Backtrackable.new_delayed ~sched_daemon ~sched_decision t.solver_state + Egraph.Backtrackable.new_delayed ~sched_daemon ~sched_decision t.solver_state (* let rec apply_learnt llearnt t d = @@ -183,39 +171,27 @@ let new_delayed = conflict_analysis t pexp *) -let rec apply_learnt learntdec llearnt t d = - try - Debug.dprintf0 debug "[Scheduler] Apply previously learnt"; - let iter_learnt n = - Debug.dprintf2 debug "[Scheduler] @[Apply %a@]" - Conflict.Learnt.pp n; - Conflict.apply_learnt d n; - S.Backtrackable.flush d in - Bag.iter iter_learnt llearnt; - if Conflict.learnt_is_already_true d learntdec - then assert false; (** absurd: If it is already true it should not be this conflict *) - iter_learnt learntdec; - run_until_dec t d; - Debug.dprintf0 debug_pushpop "[Scheduler] Learnt applied"; - (** TODO: decision on the last decision if it is multiple theory *) - d - with S.Contradiction pexp -> - Debug.dprintf0 debug "[Scheduler] Contradiction during apply learnt"; - conflict_analysis t pexp - -and pop_to t prev = +let pop_to t prev = Debug.dprintf2 debug_pushpop "[Scheduler] pop from %a" print_level t; t.wakeup_daemons <- prev.pre_wakeup_daemons; t.prev_scheduler_state <- prev.pre_prev_scheduler_state; Context.pop prev.pre_backtrack_point; - t.learnt <- prev.pre_learnt; let d = new_delayed t in Egraph.Backtrackable.draw_graph t.solver_state; Debug.dprintf2 debug_pushpop "[Scheduler] pop to %a" print_level t; d + +let rec apply_learnt t d = + try + run_until_dec t d; + d + with Egraph.Contradiction -> + Debug.dprintf0 debug "[Scheduler] Contradiction during apply learnt"; + conflict_analysis t + (* and conflict_analysis t pexp = Debug.incr stats_con; @@ -228,7 +204,7 @@ and pop_to t prev = | None -> raise Contradiction | Some prev when Trail.current_age - (S.get_trail prev.pre_solver_state) <= maxage -> + (Egraph.get_trail prev.pre_solver_state) <= maxage -> llearnt,prev | Some prev -> let llearnt = List.rev_append llearnt prev.pre_learnt in @@ -241,72 +217,48 @@ and pop_to t prev = pop_to llearnt t prev *) -and conflict_analysis t pexp = +and conflict_analysis t = if Debug.test_flag debug_dotgui then - S.Backtrackable.draw_graph ~force:true t.solver_state; + Egraph.Backtrackable.draw_graph ~force:true t.solver_state; Debug.incr stats_con; - if Egraph.Backtrackable.current_nbdec t.solver_state = 0 then begin - Debug.dprintf0 debug "[Scheduler] contradiction at level 0"; - raise Contradiction - end - else - let backlevel, learnt, useful = - Conflict.learn - (Egraph.Backtrackable.get_getter t.solver_state) - (Egraph.Backtrackable.get_trail t.solver_state) - pexp - in - t.var_inc := !(t.var_inc) *. var_decay; - Bag.iter (update_prio t) useful; - (** We look for the level just below the backtrack level *) - let rec rewind t learnt llearnt prevo = - match prevo with - | None -> - Debug.dprintf0 debug "[Scheduler] learnt clause false at level 0"; - raise Contradiction - | Some prev -> - let llearnt_all = Bag.concat llearnt prev.pre_learnt in - let age_dec = prev.pre_age_dec in - if Trail.Age.(backlevel < age_dec) then - rewind t learnt llearnt_all prev.pre_prev_scheduler_state - else - let d = pop_to t prev in - t.learnt <- Bag.append llearnt_all learnt; - d,learnt,llearnt - in - let d,learntdec,llearnt = - rewind t learnt t.learnt t.prev_scheduler_state in - t.wakeup_daemons <- Prio.reprio t.decprio t.wakeup_daemons; - apply_learnt learntdec llearnt t d + t.var_inc := !(t.var_inc) *. var_decay; + (** We look for the level just below the backtrack level *) + let rewind t prevo = + match prevo with + | None -> + Debug.dprintf0 debug "[Scheduler] learnt clause false at level 0"; + raise Contradiction + | Some prev -> + let d = pop_to t prev in + d + in + let d = + rewind t t.prev_scheduler_state in + t.wakeup_daemons <- Prio.reprio t.decprio t.wakeup_daemons; + apply_learnt t d and try_run_dec: - t -> S.t -> Prio.t -> Trail.chogen -> S.t = fun t d prio chogen -> + t -> Egraph.t -> Prio.t -> Egraph.choice -> Egraph.t = fun t d prio choice -> (** First we verify its the decision is at this point needed *) try - match Conflict.choose_decision d chogen with - | Conflict.DecNo -> + match choice.choice d with + | Egraph.DecNo -> t.wakeup_daemons <- prio; d (** d can be precised by choose_decision *) - | Conflict.DecTodo todo -> + | Egraph.DecTodo todo -> Debug.incr stats_dec; - S.Backtrackable.delayed_stop d; + Egraph.Backtrackable.delayed_stop d; (** The registered state keep the old prio *) - push t chogen; + ignore (push t); (** We use the priority list without the decision only in the branch where the decision is made *) t.wakeup_daemons <- prio; - let declevel = S.Backtrackable.new_dec t.solver_state in - Debug.dprintf4 debug_pushpop - "[Scheduler] Make decision: decision %a level %a" - Trail.print_dec declevel - print_level t; - assert (Egraph.Backtrackable.current_nbdec t.solver_state > 0); let d = new_delayed t in todo d; d - with S.Contradiction pexp -> + with Egraph.Contradiction -> Debug.dprintf0 debug "[Scheduler] Contradiction"; - conflict_analysis t pexp + conflict_analysis t and run_until_dec t d = let act = Prio.min t.wakeup_daemons in @@ -315,8 +267,8 @@ and run_until_dec t d = let _, prio = Prio.extract_min t.wakeup_daemons in Debug.incr stats_propa; t.wakeup_daemons <- prio; - S.Backtrackable.run_daemon d att; - S.Backtrackable.flush d; + Egraph.Backtrackable.run_daemon d att; + Egraph.Backtrackable.flush d; run_until_dec t d end | Some (Att.Decision (_,_)) | None -> () @@ -329,19 +281,19 @@ let run_one_step t d = Debug.incr stats_propa; t.wakeup_daemons <- prio; try - S.Backtrackable.run_daemon d att; d - with S.Contradiction pexp -> + Egraph.Backtrackable.run_daemon d att; d + with Egraph.Contradiction -> Debug.dprintf0 debug "[Scheduler] Contradiction"; - conflict_analysis t pexp + conflict_analysis t end | Att.Decision (_,chogen) -> try_run_dec t d prio chogen let rec flush t d = try - S.Backtrackable.flush d; d - with S.Contradiction pexp -> + Egraph.Backtrackable.flush d; d + with Egraph.Contradiction -> Debug.dprintf0 debug "[Scheduler] Contradiction"; - let d = conflict_analysis t pexp in + let d = conflict_analysis t in flush t d exception ReachStepLimit @@ -360,7 +312,7 @@ let rec run_inf_step ?limit ~nodec t d = let d = run_one_step t d in run_inf_step ?limit:(Opt.map pred limit) ~nodec t d else begin - S.Backtrackable.delayed_stop d + Egraph.Backtrackable.delayed_stop d end let run_inf_step ?limit ?(nodec=false) t = @@ -387,26 +339,54 @@ let flush_delayed t = | Some d -> t.delayed <- Some (flush t d) +let stop t d = + let d = flush t d in + Egraph.Backtrackable.delayed_stop d; + t.delayed <- None + let stop_delayed t = match t.delayed with | None -> () | Some d -> let d = flush t d in - S.Backtrackable.delayed_stop d; - t.delayed <- None + stop t d + +let init_theories ~theories t = + try + let d = get_delayed t in + List.iter (fun f -> f d) (SynTerm.init::theories); + Egraph.Backtrackable.flush d; + let d = flush t d in + stop t d + with Egraph.Contradiction -> + Debug.dprintf0 debug + "[Scheduler] Contradiction during theory initialization"; + raise Contradiction + + +let add_assertion t f = + try + let d = get_delayed t in + f d; + let d = flush t d in + stop t d + with Egraph.Contradiction -> + Debug.dprintf0 debug + "[Scheduler] Contradiction during assertion"; + raise Contradiction + +let check_sat ?limit t = + try + stop_delayed t; + run_inf_step ?limit t; + `Sat (get_delayed t) + with Contradiction -> + `Unsat let run_exn ?nodec ?limit ~theories f = let t = new_solver () in - begin try - let d = get_delayed t in - List.iter (fun f -> f d) (SynTerm.init::theories); - Egraph.Backtrackable.flush d; - f d - with S.Contradiction _ -> - Debug.dprintf0 debug - "[Scheduler] Contradiction during initial assertion"; - raise Contradiction - end; + init_theories ~theories t; + add_assertion t f; stop_delayed t; run_inf_step ~nodec:(nodec=Some ()) ?limit t; get_delayed t @@ -416,3 +396,5 @@ let run ?nodec ?limit ~theories f = `Done (run_exn ?nodec ?limit ~theories f) with Contradiction -> `Contradiction + +let pop_to st bp = ignore (pop_to st bp) diff --git a/src/solver/scheduler.mli b/src/solver/scheduler.mli index c88706891085d51acf1d52630917ccfd98c453e5..2bf87eabaf9c5d65079cac2a26e6a8a6406b6d1a 100644 --- a/src/solver/scheduler.mli +++ b/src/solver/scheduler.mli @@ -34,3 +34,17 @@ val run: [> `Contradiction | `Done of Egraph.t ] + +type t + +val new_solver: unit -> t +val init_theories: theories:(Egraph.t -> unit) list -> t -> unit +val add_assertion: t -> (Egraph.t -> unit) -> unit +val check_sat: ?limit:int -> t -> [> `Unsat | `Sat of Egraph.t ] + +type bp + +val push: t -> bp +val pop_to: t -> bp -> unit + +exception ReachStepLimit diff --git a/src/solver/solver.ml b/src/solver/solver.ml index 9cc3b06470bde0f608b3188aadf70d548debe007..25c5bee75fe9b8e3c78fdeda2a09a7f092210b9b 100644 --- a/src/solver/solver.ml +++ b/src/solver/solver.ml @@ -19,4 +19,3 @@ (*************************************************************************) module Scheduler = Scheduler -module Input = Input diff --git a/src/stdlib/dune b/src/stdlib/dune index 0973647a7dd79b4577e73b09367111673cfabb33..55423e337a0f8cd17f020434a1ac1fabdbcc3458 100644 --- a/src/stdlib/dune +++ b/src/stdlib/dune @@ -4,7 +4,7 @@ (synopsis "Stdlib for witan") (libraries zarith containers witan_popop_lib) (preprocess - (pps ppx_optcomp ppx_deriving.std)) + (pps ppx_optcomp ppx_deriving.std ppx_hash)) (flags :standard -w +a-4-42-44-48-50-58-32-60-40-9@8 -color always -open Containers) (ocamlopt_flags :standard -O3 -bin-annot -unbox-closures diff --git a/src/stdlib/std.ml b/src/stdlib/std.ml index ba98859a1a3fd255175202981fc584e35b742acc..2b0a8bc46064447e4ee540f008f119d41875be2a 100644 --- a/src/stdlib/std.ml +++ b/src/stdlib/std.ml @@ -22,9 +22,10 @@ (*************************************************************************) include Std_sig +module Hash = Base.Hash let nnil = function [] -> false | _::_ -> true - + module Poly = struct type (_,_,_) t = @@ -59,7 +60,7 @@ end module Q = struct module Arg = struct include Q (* Module from Zarith *) - let hash = Hash.poly + let hash = CCHash.poly let pp fmt q = Format.( match Q.classify q with @@ -79,7 +80,7 @@ module Q = struct let of_string_decimal = let decimal = Str.regexp "\\(+\\|-\\)?\\([0-9]+\\)\\([.]\\([0-9]*\\)\\)?" in fun s -> - if not (Str.string_match decimal s 0) then None + if not (Str.string_match decimal s 0) then assert false else let sgn = match Str.matched_group 1 s with | "-" -> Q.minus_one @@ -96,6 +97,6 @@ module Q = struct let ten = Q.of_int 10 in Witan_popop_lib.Util.foldi (fun acc _ -> Q.(acc * ten)) dec 1 l in - Some Q.(sgn * (int_part + dec_part)) + Q.(sgn * (int_part + dec_part)) end diff --git a/src/stdlib/std.mli b/src/stdlib/std.mli index 4f087cbddc299d8afe1e4605577fb36233d4a8bf..2ec37f57c76a37b7b5ac7045efd08d6241672712 100644 --- a/src/stdlib/std.mli +++ b/src/stdlib/std.mli @@ -56,5 +56,5 @@ module Q : sig val two : t val ge : t -> t -> bool val le : t -> t -> bool - val of_string_decimal : string -> t option + val of_string_decimal : string -> t end diff --git a/src/tests/dune b/src/tests/dune index 304220bb3b64f214f8a1c2edb4e68b1b8c106612..6d4e4271aae9684ed72837992f1a80d9acd760c2 100644 --- a/src/tests/dune +++ b/src/tests/dune @@ -2,7 +2,7 @@ (modes byte exe) (name tests) (libraries containers witan.core witan.theories.bool witan.theories.LRA - oUnit witan.solver witan.stdlib) + ounit2 witan.solver witan.stdlib) (flags :standard -w +a-4-42-44-48-50-58-32-60-9@8 -color always) (ocamlopt_flags :standard -O3 -unbox-closures -unbox-closures-factor 20)) diff --git a/src/tests/tests.ml b/src/tests/tests.ml index ba008aa24da0e1d4aef91c87b1e92f0fbc469717..9c0630752249a6db2952b6707066c6a34cfff5c1 100644 --- a/src/tests/tests.ml +++ b/src/tests/tests.ml @@ -18,10 +18,10 @@ (* for more details (enclosed in the file licenses/LGPLv2.1). *) (*************************************************************************) -open OUnit -open Witan_stdlib -open Witan_core -open Tests_lib +open OUnit2 +(* open Witan_stdlib + * open Witan_core + * open Tests_lib *) let opt_seed = ref 0 @@ -35,8 +35,8 @@ let make_tests acc seed = let test = ((Witan_popop_lib.Pp.sprintf "seed %a" print_seed seed) >::: [ Tests_bool.tests; Tests_uf.tests; Tests_LRA.tests ]) in - let test = test_decorate - (fun f -> (fun () -> Shuffle.set_shuffle seed; f ())) test in + (* let test = test_decorate + * (fun f -> (fun () -> Shuffle.set_shuffle seed; f ())) test in *) test::acc let tests () = @@ -45,98 +45,101 @@ let tests () = make_tests l None let tests () = - if Printexc.backtrace_status () - then - (test_decorate - (fun f -> - fun () -> - try f () - with exn -> - Format.fprintf (Witan_popop_lib.Debug.get_debug_formatter ()) "%s" - (Printexc.get_backtrace ()); - raise exn - )) (TestList (tests ())) - else - (TestList (tests ())) + (* if Printexc.backtrace_status () + * then + * (test_decorate + * (fun f -> + * fun () -> + * try f () + * with + * | exn -> + * Format.fprintf (Witan_popop_lib.Debug.get_debug_formatter ()) "%s" + * (Printexc.get_backtrace ()); + * raise exn + * )) (test_list (tests ())) + * else *) + (test_list (tests ())) (** From oUnit.ml v 1.2.2 *) (** just need to make the tests lazily computed *) -(* Returns true if the result list contains successes only *) -let rec was_successful = - function - | [] -> true - | RSuccess _::t - | RSkip _::t -> - was_successful t - - | RFailure _::_ - | RError _::_ - | RTodo _::_ -> - false - - -(* Call this one from you test suites *) -let run_test_tt_main ?(arg_specs=[]) suite = - let only_test = ref [] in - let () = - Arg.parse - (Arg.align - [ - "-only-test", - Arg.String (fun str -> only_test := str :: !only_test), - "path Run only the selected test"; - - "-list-test", - Arg.Unit - (fun () -> - List.iter - (fun pth -> - print_endline (string_of_path pth)) - (test_case_paths (suite ())); - exit 0), - " List tests"; - ] @ arg_specs - ) - (fun x -> raise (Arg.Bad ("Bad argument : " ^ x))) - ("usage: " ^ Sys.argv.(0) ^ " [-verbose] [-only-test path]*") - in - let () = Witan_popop_lib.Debug.Args.set_flags_selected () in - let verbose = Witan_popop_lib.Debug.test_flag debug in - let nsuite = - if !only_test = [] then - suite () - else - begin - match test_filter ~skip:true !only_test (suite ()) with - | Some test -> - test - | None -> - failwith ("Filtering test "^ - (String.concat ", " !only_test)^ - " lead to no test") - end - in - let result = run_test_tt ~verbose nsuite in - if not (was_successful result) then - exit 1 - else - result - -(*** End *) - -let () = - if not (Egraph.check_initialization () && Conflict.check_initialization ()) then - exit 1 - -let _ = - try - run_test_tt_main - ~arg_specs:(["--seed",Arg.Set_int opt_seed, - " Base seed used for shuffling the arbitrary decision"; - Witan_popop_lib.Debug.Args.desc_debug_all]@ - Witan_popop_lib.Debug.Args.desc_debug) - tests - with e when not (Witan_popop_lib.Debug.test_flag Witan_popop_lib.Debug.stack_trace) -> - Format.eprintf "%a" Witan_popop_lib.Exn_printer.exn_printer e; - exit 1 +(* (\* Returns true if the result list contains successes only *\) + * let rec was_successful = + * function + * | [] -> true + * | RSuccess _::t + * | RSkip _::t -> + * was_successful t + * + * | RFailure _::_ + * | RError _::_ + * | RTodo _::_ -> + * false + * + * + * (\* Call this one from you test suites *\) + * let run_test_tt_main ?(arg_specs=[]) suite = + * let only_test = ref [] in + * let () = + * Arg.parse + * (Arg.align + * [ + * "-only-test", + * Arg.String (fun str -> only_test := str :: !only_test), + * "path Run only the selected test"; + * + * "-list-test", + * Arg.Unit + * (fun () -> + * List.iter + * (fun pth -> + * print_endline (string_of_path pth)) + * (test_case_paths (suite ())); + * exit 0), + * " List tests"; + * ] @ arg_specs + * ) + * (fun x -> raise (Arg.Bad ("Bad argument : " ^ x))) + * ("usage: " ^ Sys.argv.(0) ^ " [-verbose] [-only-test path]*") + * in + * let () = Witan_popop_lib.Debug.Args.set_flags_selected () in + * let verbose = Witan_popop_lib.Debug.test_flag debug in + * let nsuite = + * if !only_test = [] then + * suite () + * else + * begin + * match test_filter ~skip:true !only_test (suite ()) with + * | Some test -> + * test + * | None -> + * failwith ("Filtering test "^ + * (String.concat ", " !only_test)^ + * " lead to no test") + * end + * in + * let result = run_test_tt ~verbose nsuite in + * if not (was_successful result) then + * exit 1 + * else + * result + * + * (\*** End *\) + * + * let () = + * if not (Egraph.check_initialization ()) then + * exit 1 + * + * let _ = + * try + * run_test_tt_main + * ~arg_specs:(["--seed",Arg.Set_int opt_seed, + * " Base seed used for shuffling the arbitrary decision"; + * Witan_popop_lib.Debug.Args.desc_debug_all]@ + * Witan_popop_lib.Debug.Args.desc_debug) + * tests + * with e when not (Witan_popop_lib.Debug.test_flag Witan_popop_lib.Debug.stack_trace) -> + * Format.eprintf "%a" Witan_popop_lib.Exn_printer.exn_printer e; + * exit 1 *) + +let () = run_test_tt_main (tests ()) diff --git a/src/tests/tests_LRA.ml b/src/tests/tests_LRA.ml index 5dc64c2d2dbe8525665b4bba219de728115cd755..493318dbb32dcbec6003b6563ed08e9c4e1ff3ec 100644 --- a/src/tests/tests_LRA.ml +++ b/src/tests/tests_LRA.ml @@ -18,7 +18,7 @@ (* for more details (enclosed in the file licenses/LGPLv2.1). *) (*************************************************************************) -open OUnit +open OUnit2 open Tests_lib open Witan_theories_bool open Witan_theories_LRA @@ -38,9 +38,10 @@ let ($$) f x = f x (* The tests with rundec check only the result on a model satisfying the hypothesis *) +open Expr -let solve0a () = - let a = fresh Term._Real "ar" in +let solve0a _ = + let a = fresh Ty.real "ar" in let _1 = LRA.cst Q.one in let a1 = LRA.add a _1 in let env = run $$ fun env -> @@ -49,7 +50,7 @@ let solve0a () = in assert_bool "a+1 = 1 => a = 0" (is_equal env a LRA.zero) -(* let solve0b () = +(* let solve0b _ = * let a = fresh Term._Real "ar" in * let _1 = LRA.cst Q.one in * let _2 = LRA.cst Q.two in @@ -62,9 +63,9 @@ let solve0a () = * in * assert_bool "a+1 = 2 => 2*a+2 = 4" (is_equal env _2a2 _4) *) -let solve0c () = - let a = fresh Term._Real "ar" in - let b = fresh Term._Real "br" in +let solve0c _ = + let a = fresh Ty.real "ar" in + let b = fresh Ty.real "br" in let _1 = LRA.cst Q.one in let a1 = LRA.add a _1 in let b1 = LRA.add b _1 in @@ -74,8 +75,8 @@ let solve0c () = in assert_bool "a+1 = b+1 => a = b" (is_equal env a b) -let solve1 () = - let a,b = Shuffle.seq2 (fresh Term._Real) ("ar","br") in +let solve1 _ = + let a,b = Shuffle.seq2 (fresh Ty.real) ("ar","br") in let _1 = LRA.cst Q.one in let a1 = LRA.add a _1 in let b1 = LRA.add b _1 in @@ -88,8 +89,8 @@ let solve1 () = in assert_bool "a+1 = b+1 => a+2 = b+2" (is_equal env a2 b2) -let solve2 () = - let a,b = Shuffle.seq2 (fresh Term._Real) ("ar","br") in +let solve2 _ = + let a,b = Shuffle.seq2 (fresh Ty.real) ("ar","br") in let _1 = LRA.cst Q.one in let a1 = LRA.add a _1 in let b1 = LRA.add b _1 in @@ -102,8 +103,8 @@ let solve2 () = in assert_bool "a+2 = b+1 => a+1 = b" (is_equal env a1 b) -let solve3 () = - let a,b = Shuffle.seq2 (fresh Term._Real) ("ar","br") in +let solve3 _ = + let a,b = Shuffle.seq2 (fresh Ty.real) ("ar","br") in let _1 = LRA.cst Q.one in let b1 = LRA.add b _1 in let _2 = LRA.cst (Q.of_int 2) in @@ -128,9 +129,9 @@ let solve3 () = assert_bool "a+2 = b+1 => a = 2 => b = 3" (is_equal env b _3) -let solve4 () = +let solve4 _ = let a,b,c = - Shuffle.seq3 (fresh Term._Real) ("ar","br","cr") in + Shuffle.seq3 (fresh Ty.real) ("ar","br","cr") in let t1 = LRA.cst (Q.of_int 2) in let t1 = LRA.add t1 c in let t1 = LRA.add a t1 in @@ -154,10 +155,10 @@ let solve4 () = assert_bool "a+(2+c) = b+1 => a = 2 + b => c = -3" (is_equal env c t3') -let solve5 () = - let a = fresh Term._Real "ar" in - let b = fresh Term._Real "br" in - let c = fresh Term._Real "cr" in +let solve5 _ = + let a = fresh Ty.real "ar" in + let b = fresh Ty.real "br" in + let c = fresh Ty.real "cr" in let t1 = LRA.sub b c in let t1 = LRA.add a t1 in let t1' = (LRA.cst (Q.of_int 2)) in @@ -191,9 +192,9 @@ let basic = "LRA.Basic" &: solve5 ] -(* let mult0 () = - * let a = fresh Term._Real "ar" in - * let b = fresh Term._Real "br" in +(* let mult0 _ = + * let a = fresh Ty.real "ar" in + * let b = fresh Ty.real "br" in * let t1 = LRA.sub a b in * let t1' = LRA.mult a b in * let t2 = a in @@ -215,10 +216,10 @@ let basic = "LRA.Basic" &: * assert_bool "a - b = a * b -> a = 1 -> 1 = 2b" (is_equal env t3 t3') * * (\** test that mult normalization trigger the needed solve *\) - * let mult1 () = - * let a = fresh Term._Real "ar" in - * let b = fresh Term._Real "br" in - * let c = fresh Term._Real "cr" in + * let mult1 _ = + * let a = fresh Ty.real "ar" in + * let b = fresh Ty.real "br" in + * let c = fresh Ty.real "cr" in * let t1 = LRA.mult a b in * let t1 = LRA.add a t1 in * let t1' = LRA.add b c in @@ -253,48 +254,4 @@ let basic = "LRA.Basic" &: * let altergo = TestList (List.map Tests_lib.test_split files) *) - -let check_file filename = - let statements = Witan_solver.Input.read - ~language:Witan_solver.Input.Smtlib - ~dir:(Filename.dirname filename) - (Filename.basename filename) - in - Witan_solver.Notypecheck.run ~theories ~limit:1000 statements - -let tests_smt2 expected dir = - if Sys.file_exists dir then - let files = Sys.readdir dir in - Array.sort String.compare files; - let files = Array.to_list files in - List.map - (fun s -> - s >: TestCase (fun () -> - begin match check_file (Filename.concat dir s) with - | `Sat -> - Witan_popop_lib.Debug.dprintf1 Tests_lib.debug "@[%s: Sat@]" s; - assert_bool s (`Sat = expected) - | `Unsat -> - Witan_popop_lib.Debug.dprintf1 Tests_lib.debug "@[%s: Unsat@]" s; - assert_bool s (`Unsat = expected) - | exception Witan_solver.Notypecheck.Typing_error (msg, t) -> - assert_string - (Format.asprintf - "%a:@\n%s:@ %a" - Dolmen.ParseLocation.fmt (Witan_solver.Notypecheck.get_loc t) msg - Dolmen.Term.print t - ) - end; - )) files - else - [] - -let smtlib2sat = - "smtlib2-lra-sat" >::: - tests_smt2 `Sat "solve/smt_lra/sat/" - -let smtlib2unsat = - "smtlib2-lra-unsat" >::: - tests_smt2 `Unsat "solve/smt_lra/unsat/" - -let tests = TestList [basic;(* (\* mult;*\)altergo;*) (* smtlib2sat; smtlib2unsat *)] +let tests = test_list [basic;(* (\* mult;*\)altergo;*) (* smtlib2sat; smtlib2unsat *)] diff --git a/src/tests/tests_bool.ml b/src/tests/tests_bool.ml index ae7b9bf841a051d5261de9c3afd1c8e2f0471814..e2958df8de42f2d2950bbb22cf5a2fec20809f5b 100644 --- a/src/tests/tests_bool.ml +++ b/src/tests/tests_bool.ml @@ -18,7 +18,7 @@ (* for more details (enclosed in the file licenses/LGPLv2.1). *) (*************************************************************************) -open OUnit +open OUnit2 open Witan_stdlib open Witan_core open Tests_lib @@ -30,21 +30,23 @@ let ($$) f x = f x let run = Tests_lib.run_exn ~theories -let bool_interp () = - let ta = Term.const (Id.mk "a" Boolean.ty) in - let tb = Term.const (Id.mk "b" Boolean.ty) in - let tc = Term.const (Id.mk "c" Boolean.ty) in +open Expr + +let bool_interp _ = + let ta = fresht Ty.bool "a" in + let tb = fresht Ty.bool "b" in + let tc = fresht Ty.bool "c" in let to_n x = SynTerm.node_of_term x in let na = to_n ta in let nb = to_n tb in let nc = to_n tc in let leaf ~a ~b ~c t = if Term.equal t ta - then Some (Value.index Boolean.dom a Boolean.ty) + then Some (Value.index Boolean.dom a) else if Term.equal t tb - then Some (Value.index Boolean.dom b Boolean.ty) + then Some (Value.index Boolean.dom b) else if Term.equal t tc - then Some (Value.index Boolean.dom c Boolean.ty) + then Some (Value.index Boolean.dom c) else None in let l = [ @@ -64,36 +66,36 @@ let bool_interp () = in List.iter test l -let true_is_true () = +let true_is_true _ = let env = run (fun _ -> ()) in assert_bool "" (Boolean.is_true env Boolean._true); assert_bool "" (not (Boolean.is_false env Boolean._true)) -let not_true_is_false () = +let not_true_is_false _ = let not_true = Boolean._not Boolean._true in let env = run $$ fun env -> Egraph.register env not_true in assert_bool "" (Boolean.is_false env not_true); assert_bool "" (not (Boolean.is_true env not_true)) -let and_true_is_true () = +let and_true_is_true _ = let _t = Boolean._true in let _and = Boolean._and [_t;_t;_t] in let env = run $$ fun env -> Egraph.register env _and in assert_bool "" (Boolean.is_true env _and); assert_bool "" (not (Boolean.is_false env _and)) -let or_not_true_is_false () = +let or_not_true_is_false _ = let _f = (Boolean._not Boolean._true) in let _or = Boolean._and [_f;_f;_f] in let env = run $$ fun env -> Egraph.register env _or in assert_bool "" (Boolean.is_false env _or); assert_bool "" (not (Boolean.is_true env _or)) -let merge_true () = - let a = fresh Boolean.ty "a" in - let b = fresh Boolean.ty "b" in - let c = fresh Boolean.ty "c" in - let d = fresh Boolean.ty "d" in +let merge_true _ = + let a = fresh Ty.bool "a" in + let b = fresh Ty.bool "b" in + let c = fresh Ty.bool "c" in + let d = fresh Ty.bool "d" in let _and = Boolean._and [a;b;c] in let env = run $$ fun env -> Egraph.register env _and; @@ -103,22 +105,22 @@ let merge_true () = (fun () -> merge env a c); ]; merge env a d; - Boolean.set_true env Trail.pexp_fact d; + Boolean.set_true env d; in assert_bool "" (Boolean.is_true env _and) -let imply_implies () = - let a = Term.const (Id.mk "a" Term._Prop) in - let b = Term.const (Id.mk "b" Term._Prop) in - let t = Term.apply Term.imply_term [a;b] in +let imply_implies _ = + let a = fresht Ty.bool "a" in + let b = fresht Ty.bool "b" in + let t = Term.imply a b in let an = SynTerm.node_of_term a in let bn = SynTerm.node_of_term b in let tn = SynTerm.node_of_term t in let env = run $$ fun env -> Egraph.register env tn; - Boolean.set_true env Trail.pexp_fact tn; + Boolean.set_true env tn; Egraph.register env an; - Boolean.set_true env Trail.pexp_fact an; + Boolean.set_true env an; in assert_bool "" (Boolean.is_true env bn) @@ -132,55 +134,4 @@ let basic = "Boolean.Basic" >::: [ "bool_interp" >:: bool_interp; (* "modus_ponens" >:: modus_ponens; *) ] - -let check_file filename = - let statements = Witan_solver.Input.read - ~language:Witan_solver.Input.Dimacs - ~dir:(Filename.dirname filename) - (Filename.basename filename) - in - try - Witan_solver.Notypecheck.run ~theories ~limit:1000 statements - with - | Witan_solver.Notypecheck.Typing_error (msg, t) -> - assert_failure - (Format.asprintf - "%a:@\n%s:@ %a" - Dolmen.ParseLocation.fmt (Witan_solver.Notypecheck.get_loc t) msg - Dolmen.Term.print t - ) - -let tests_dimacs expected dir = - let files = Sys.readdir dir in - Array.sort String.compare files; - let files = Array.to_list files in - List.map - (fun s -> - s >: TestCase (fun () -> - let res = check_file (Filename.concat dir s) in - begin match res with - | `Sat -> Witan_popop_lib.Debug.dprintf1 Tests_lib.debug "@[%s: Sat@]" s - | `Unsat -> Witan_popop_lib.Debug.dprintf1 Tests_lib.debug "@[%s: Unsat@]" s - end; - assert_bool s (res = expected); - )) files - -let dimacssat = - "dimacs-sat" >::: tests_dimacs `Sat "solve/dimacs/sat/" - -let dimacsunsat = - "dimacs-unsat" >::: tests_dimacs `Unsat "solve/dimacs/unsat/" - -let tests = TestList [basic; dimacssat;dimacsunsat] - - -let () = Witan_popop_lib.Exn_printer.register (fun fmt exn -> - match exn with - | Dolmen.ParseLocation.Syntax_error(l,"") -> - Format.fprintf fmt "%a: syntax error." - Dolmen.ParseLocation.fmt l - | Dolmen.ParseLocation.Syntax_error(l,c) -> - Format.fprintf fmt "%a: syntax error %s." - Dolmen.ParseLocation.fmt l c - | exn -> raise exn - ) +let tests = test_list [basic] diff --git a/src/tests/tests_lib.ml b/src/tests/tests_lib.ml index d6a34c68f4f701265c2709d8a6529b0b67884cb9..3ae0cca61108fed5ca589023aedc3f7143c2a669 100644 --- a/src/tests/tests_lib.ml +++ b/src/tests/tests_lib.ml @@ -18,23 +18,24 @@ (* for more details (enclosed in the file licenses/LGPLv2.1). *) (*************************************************************************) -open OUnit +open OUnit2 open Witan_popop_lib open Witan_core let debug = Debug.register_flag ~desc:" Run the test in verbose mode." "ounit" -let fresh ty s = SynTerm.node_of_term (Term.const (Id.mk s ty)) +let fresht ty s = Expr.Term.apply (Expr.Term.Const.mk s [] [] ty) [] [] +let fresh ty s = SynTerm.node_of_term (Expr.Term.apply (Expr.Term.Const.mk s [] [] ty) [] []) -let (&:) s l = s >::: (List.map (fun f -> TestCase f) l) +let (&:) s l = s >::: (List.map (fun f -> OUnit2.test_case f) l) let register d cl = Egraph.register d cl; Egraph.Backtrackable.flush d let merge d cl1 cl2 = - Egraph.merge d Trail.pexp_fact cl1 cl2; + Egraph.merge d cl1 cl2; Egraph.Backtrackable.flush d let is_equal = Egraph.is_equal @@ -65,4 +66,54 @@ exception Contradiction let run_exn = Witan_solver.Scheduler.run_exn -let fresh ty s = SynTerm.node_of_term (Term.const (Id.mk s ty)) +let check_file ?limit ~theories filename = + let st = + Witan_solver.Input.mk_state + ~input:(`File filename) + theories + ~bt:false + in + Witan_solver.Input.read + ~show_checksat_result:false + ?limit + ~set_true:Witan_theories_bool.Boolean.set_true + ~handle_exn:Witan_solver.Input.handle_exn_with_error + st; + let r = st.Witan_solver.Input.State.solve_state.Witan_solver.Input.state in + match r with + | `Sat _ -> `Sat + | `Unsat -> `Unsat + | `Unknown -> `Unknown + | `StepLimitReached -> `StepLimitReached + + +let tests_file ?limit ~theories expected dir = + if Sys.file_exists dir then + let files = Sys.readdir dir in + Array.sort String.compare files; + let files = Array.to_list files in + List.map + (fun s -> + s >: test_case (fun _ -> + begin match check_file ?limit ~theories (Filename.concat dir s) with + | `Sat -> + Witan_popop_lib.Debug.dprintf1 debug "@[%s: Sat@]" s; + assert_bool s (`Sat = expected) + | `Unsat -> + Witan_popop_lib.Debug.dprintf1 debug "@[%s: Unsat@]" s; + assert_bool s (`Unsat = expected) + | `Unknown -> + Witan_popop_lib.Debug.dprintf1 debug "@[%s: Unknown@]" s; + assert_bool s (`Unknown = expected) + | `StepLimitReached -> + Witan_popop_lib.Debug.dprintf0 debug "StepLimit Reached@."; + assert_bool s false + | exception exn -> + Witan_popop_lib.Debug.dprintf2 debug "@.Error: %s@.%s@." + (Printexc.to_string exn) + (Printexc.get_backtrace ()); + assert_bool s false; + end; + )) files + else + [] diff --git a/src/tests/tests_uf.ml b/src/tests/tests_uf.ml index 9359afc2de194c2398695f8a70bc8e011a3ebc5d..831c3e37e0d54fdd68fc82dd1dd5dfa4ade48de3 100644 --- a/src/tests/tests_uf.ml +++ b/src/tests/tests_uf.ml @@ -19,7 +19,7 @@ (*************************************************************************) -open OUnit +open OUnit2 open Witan_core open Tests_lib open Witan_theories_bool @@ -28,17 +28,19 @@ let theories = [Boolean.th_register; Equality.th_register; Uninterp.th_register let run = Tests_lib.run_exn ~theories ~nodec:() let ($$) f x = f x -let a = SynTerm.node_of_term (Term.const (Id.mk "a" Boolean.ty)) -let b = SynTerm.node_of_term (Term.const (Id.mk "b" Boolean.ty)) -let c = SynTerm.node_of_term (Term.const (Id.mk "c" Boolean.ty)) +open Expr -let empty () = +let a = fresh Ty.bool "a" +let b = fresh Ty.bool "b" +let c = fresh Ty.bool "c" + +let empty _ = let env = run $$ fun env -> register env a; register env b; in assert_bool "⊬ a == b" (not (is_equal env a b)) -let tauto () = +let tauto _ = let env = run $$ fun env -> register env a; register env b; merge env a b; @@ -46,7 +48,7 @@ let tauto () = assert_bool "a = b => a = b" (is_equal env a b) -let tauto_equal () = +let tauto_equal _ = let env = run $$ fun env -> register env a; register env b; merge env a b; @@ -54,7 +56,7 @@ let tauto_equal () = assert_bool "a = b => a = b" (is_equal env a b) -let trans () = +let trans _ = let env = run $$ fun env -> register env a; register env b; register env c; merge env a b; merge env b c; @@ -63,7 +65,7 @@ let trans () = assert_bool "a = b => b = c => a = b" (is_equal env a b); assert_bool "a = b => b = c => b = c" (is_equal env b c) -let noteq () = +let noteq _ = let env = run $$ fun env -> register env a; register env b; register env c; merge env b c; @@ -79,19 +81,19 @@ let fb = f b let ffa = f (f a) let ffb = f (f b) -let refl () = +let refl _ = let env = run $$ fun env -> register env fa; in assert_bool "f(a) = f(a)" (is_equal env fa fa) -let empty () = +let empty _ = let env = run $$ fun env -> register env fa; register env fb; in assert_bool "f(a) != f(b)" (not (is_equal env fa fb)) -let congru () = +let congru _ = let env = run $$ fun env -> Shuffle.seql [ (fun () -> register env fa); @@ -104,7 +106,7 @@ let congru () = assert_bool "a = b => f(a) = f(b)" (is_equal env fa fb) -let _2level () = +let _2level _ = let env = run $$ fun env -> Shuffle.seql [ (fun () -> register env ffa); @@ -117,7 +119,7 @@ let _2level () = assert_bool "a = b => f(f(a)) = f(f(b))" (is_equal env ffa ffb) -let _2level' () = +let _2level' _ = let env = run $$ fun env -> register env a; register env b; merge env a b; @@ -126,7 +128,7 @@ let _2level' () = assert_bool "a = b => f(f(a)) = f(f(b))" (is_equal env ffa ffb) -let bigger () = +let bigger _ = let rec bf n = if n < 1 then a else (f (bf(n-1))) in let fa = bf 1 in let fffa = bf 3 in @@ -158,11 +160,11 @@ let gab = g a b let gaa = g a a let ggabb = g gab b -let refl () = +let refl _ = let env = run $$ fun env -> register env gab in assert_bool "g(a,b) = g(a,b)" (is_equal env gab gab) -let congru () = +let congru _ = let env = run $$ fun env -> Shuffle.seql [ (fun () -> register env gab); @@ -175,7 +177,7 @@ let congru () = assert_bool "a = b => g(a,b) = g(a,a)" (is_equal env gab gaa) -let notcongru () = +let notcongru _ = let env = run $$ fun env -> register env a; register env gab; register env gaa; merge env a gab; @@ -183,7 +185,7 @@ let notcongru () = assert_bool "a = g(a,b) => g(a,b) != g(a,a)" (not (is_equal env gab gaa)) -let _2level () = +let _2level _ = let env = run $$ fun env -> Shuffle.seql [ (fun () -> register env a); @@ -208,7 +210,7 @@ let merge env x y = let x = Variable.fresh ty "x" let y = Variable.fresh ty "y" -let altergo0 () = +let altergo0 _ = let h = Uninterp.fun1 ty "h" in let g = Uninterp.fun2 ty "g" in let gax = g a x in @@ -224,7 +226,7 @@ let altergo0 () = assert_bool "h(x)=x and g(a,x)=a -> g(g(a,h(x)),x)=a" (is_equal env ggahxx a) -let altergo1 () = +let altergo1 _ = let h = Uninterp.fun2 ty "h" in let rec bf n = if n < 1 then a else f (bf (n-1)) in let fffa = bf 3 in @@ -247,7 +249,7 @@ let altergo1 () = h(g(g(x,y),y),a)=h(x,f(a))" (is_equal env hggxyya hxfa) -let altergo2 () = +let altergo2 _ = let h = Uninterp.fun2 ty "h" in let gxy = g x y in let fa = f a in @@ -275,47 +277,5 @@ let altergo2 = TestList (List.map Tests_lib.test_split files) *) -let check_file filename = - let statements = Witan_solver.Input.read - ~language:Witan_solver.Input.Smtlib - ~dir:(Filename.dirname filename) - (Filename.basename filename) - in - try - Witan_solver.Notypecheck.run ~theories ~limit:1000 statements - with - | Witan_solver.Notypecheck.Typing_error (msg, t) -> - assert_failure - (Format.asprintf - "%a:@\n%s:@ %a" - Dolmen.ParseLocation.fmt (Witan_solver.Notypecheck.get_loc t) msg - Dolmen.Term.print t - ) - -let tests_smt2 expected dir = - let files = Sys.readdir dir in - Array.sort String.compare files; - let files = Array.to_list files in - List.map - (fun s -> - s >: TestCase (fun () -> - let res = check_file (Filename.concat dir s) in - begin match res with - | `Sat -> Witan_popop_lib.Debug.dprintf1 Tests_lib.debug "@[%s: Sat@]" s - | `Unsat -> Witan_popop_lib.Debug.dprintf1 Tests_lib.debug "@[%s: Unsat@]" s - end; - assert_bool s (res = expected); - )) files - - -let smtlib2sat = - "smtlib2-uf-sat" >::: - tests_smt2 `Sat "solve/smt_uf/sat/" - -let smtlib2unsat = - "smtlib2-uf-unsat" >::: - tests_smt2 `Unsat "solve/smt_uf/unsat/" - - -let tests = TestList [basic;(* congru1;congru2;altergo;altergo2;*) - smtlib2sat; smtlib2unsat] +let tests = OUnit2.test_list [basic;(* congru1;congru2;altergo;altergo2;*) + ] diff --git a/src/theories/LRA/LRA.ml b/src/theories/LRA/LRA.ml index be09e0f9f7db882d77d5e41ad83612c8c506a7c4..976d80a1b52ca552ad414efd7200bc7441c2201b 100644 --- a/src/theories/LRA/LRA.ml +++ b/src/theories/LRA/LRA.ml @@ -34,7 +34,7 @@ module RealValue = ValueKind.Register(struct let key = real end) -let cst' c = RealValue.index ~basename:(Format.asprintf "%aR" Q.pp c) c Term._Real +let cst' c = RealValue.index ~basename:(Format.asprintf "%aR" Q.pp c) c let cst c = RealValue.node (cst' c) let debug_todo = debug @@ -45,7 +45,6 @@ module S = struct type t = | Add of Q.t * Node.t * Q.t * Node.t | GZero of Node.t * bound - | Conflict of Polynome.t * bound [@@ deriving eq,ord] let pp fmt = function @@ -61,8 +60,6 @@ module S = struct else Format.fprintf fmt "%a + %a" pp (q1,cl1) pp (q2,cl2) | GZero (node,b) -> Format.fprintf fmt "0 %a %a" Interval.pp_bound b Node.pp node - | Conflict (p,b) -> - Format.fprintf fmt "0 %a %a" Interval.pp_bound b Polynome.pp p let hash = function | Add (q1,cl1,q2,cl2) -> @@ -70,8 +67,6 @@ module S = struct + 5*(Hashtbl.hash q2) + 7*Node.hash cl2) + 1 | GZero (node,Strict) -> 7 * Node.hash node + 2 | GZero (node,Large) -> 7 * Node.hash node + 3 - | Conflict(p,Strict) -> CCHash.combine2 (Polynome.hash p) 4 - | Conflict(p,Large) -> CCHash.combine2 (Polynome.hash p) 5 end include T @@ -85,29 +80,11 @@ module D = Interval.Convexe let dom = DomKind.create_key (module struct type t = D.t let name = "ARITH" end) -type exp = - | ExpAdd of SE.t * Node.t (** on what we propagated *) - | ExpEmptyDomMerge of Trail.Pexp.t * Node.t * Node.t - | ExpEmptyDomInter of Trail.Pexp.t * Node.t - | ExpDistIsZero of SE.t - | ExpGZeroUp of SE.t * bool - | ExpGZeroDown of SE.t * Node.t * bool - | ExpIsSingleton of Trail.Pexp.t * Node.t - * bool (* the domain of node *) * RealValue.t - | ExpCst of RealValue.t - | ExpDec of Node.t * Q.t -[@@ deriving show] - -(** The explanation for a dom will always work on conflict which is an inequality *) - -let exp = Trail.Exp.create_key (module struct type t = exp let name = "LRA.exp" end) - -let set_dom d pexp node v b = +let set_dom d node v = match D.is_singleton v with | Some q -> let cst = cst' q in - let pexp = Egraph.mk_pexp d exp (ExpIsSingleton(pexp,node,b,cst)) in - Egraph.set_value d pexp node (RealValue.nodevalue cst) + Egraph.set_value d node (RealValue.nodevalue cst) | None -> (** the pexp must be in the dom *) Egraph.set_dom d dom node v @@ -126,14 +103,13 @@ let () = DomKind.register(module struct | Some i1, Some i2 -> D.equal i1 i2 | _ -> false - let merge d pexp (i1,cl1) (i2,cl2) _ = + let merge d (i1,cl1) (i2,cl2) _ = assert (not (Egraph.is_equal d cl1 cl2)); match i1, cl1, i2, cl2 with | Some i1,_, Some i2,_ -> begin match D.inter i1 i2 with | None -> - let pexp = Egraph.mk_pexp d exp (ExpEmptyDomMerge(pexp,cl1,cl2)) in - Egraph.contradiction d pexp + Egraph.contradiction d | Some i -> if not (D.equal i i1) then Egraph.set_dom d dom cl1 i; @@ -164,31 +140,25 @@ module DaemonPropa = struct | None -> D.reals | Some d -> D.singleton d - let upd del node d d' pexp = + let upd del node d d' = match D.inter d d' with | None -> - let pexp = Egraph.mk_pexp del exp pexp in - let pexp = Egraph.mk_pexp del exp (ExpEmptyDomInter(pexp,node)) in Debug.dprintf6 debug "[LRA] upd node = %a d = %a d' = %a" Node.pp node D.pp d D.pp d'; - Egraph.contradiction del pexp + Egraph.contradiction del | Some d' -> if not (D.equal d d') - then set_dom del (Egraph.mk_pexp del exp pexp) node d' - (Equal.option Q.equal (D.is_singleton d') None) + then set_dom del node d' - let upd_value del node d d' pexp = + let upd_value del node d d' = match D.inter d d' with | None -> - let pexp = Egraph.mk_pexp del exp pexp in - let pexp = Egraph.mk_pexp del exp (ExpEmptyDomInter(pexp,node)) in Debug.dprintf6 debug "[LRA] upd node = %a d = %a d' = %a" Node.pp node D.pp d D.pp d'; - Egraph.contradiction del pexp + Egraph.contradiction del | Some d' -> if not (D.equal d d') - then set_dom del (Egraph.mk_pexp del exp pexp) node d' - (Equal.option Q.equal (D.is_singleton d') None) + then set_dom del node d' let propagate del s = match SE.sem s with @@ -197,12 +167,11 @@ module DaemonPropa = struct let d0 = get_value del cl0 in if Q.equal q1 Q.one && Q.equal q2 Q.minus_one && D.equal d0 D.zero then - let pexp = Egraph.mk_pexp del exp (ExpDistIsZero(s)) in - Egraph.merge del pexp cl1 cl2 + Egraph.merge del cl1 cl2 else let d1 = get_value del cl1 in let d2 = get_value del cl2 in - let upd_value node d d' = upd_value del node d d' (ExpAdd(s,node)) in + let upd_value node d d' = upd_value del node d d' in let qd1 = D.mult_cst q1 d1 in let qd2 = D.mult_cst q2 d2 in upd_value cl0 d0 (D.add qd1 qd2); @@ -215,70 +184,12 @@ module DaemonPropa = struct let dzero_false = if equal_bound b Strict then le_zero else lt_zero in if D.is_included d dzero_true then begin - let pexp = Egraph.mk_pexp del exp (ExpGZeroUp(s,true)) in - Boolean.set_true del pexp cl0 + Boolean.set_true del cl0 end else if D.is_included d dzero_false then - let pexp = Egraph.mk_pexp del exp (ExpGZeroUp(s,false)) in - Boolean.set_false del pexp cl0 + Boolean.set_false del cl0 end - | S.Conflict(p,b) -> - (** Choose representative of the equivalence class among the - present classes, not the current representative *) - let repr = Polynome.fold (fun acc node _ -> - Node.M.add (Egraph.find del node) node acc) - Node.M.empty p in - let p' = Polynome.fold (fun acc node q -> - let node = Egraph.find del node in - let node = Node.M.find_exn Impossible node repr in - Polynome.add acc (Polynome.monome q node) - ) - (Polynome.cst p.cst) - p in - let rec aux d_first = function - | [] -> begin - let cl0 = SE.node s in - if Equal.option Q.equal (D.is_singleton d_first) None then - let d = d_first in - let dzero_true = if equal_bound b Strict then gt_zero else ge_zero in - let dzero_false = if equal_bound b Strict then le_zero else lt_zero in - if D.is_included d dzero_true - then begin - let pexp = Egraph.mk_pexp del exp (ExpGZeroUp(s,true)) in - Boolean.set_true del pexp cl0; - raise Exit - end - else if D.is_included d dzero_false - then - let pexp = Egraph.mk_pexp del exp (ExpGZeroUp(s,false)) in - Boolean.set_false del pexp cl0; - raise Exit - else - assert false - else - match Boolean.is del cl0 with - | Some nonot -> - let dzero = if equal_bound b Strict - then if nonot then gt_zero else le_zero - else if nonot then ge_zero else lt_zero in - dzero,nonot - | None -> - raise Exit - end - | (node,q)::l -> - let d = get_dom del node in - let d' = (D.mult_cst q d) in - let d_last,b = aux (D.add d' d_first) l in - Debug.dprintf6 debug "node=%a d_first=%a d_last=%a" - Node.pp node D.pp d_first D.pp d_last; - let upd node d d' = upd del node d d' (ExpGZeroDown(s,node,b)) in - upd node d (D.mult_cst (Q.inv q) (D.minus d_last d_first)); - D.minus d_last d', b - in - try - ignore (aux (D.singleton p'.cst) (Node.M.bindings p'.poly)) - with Exit -> () let wakeup del = function | Events.Fired.EventValue(_,_,s) @@ -303,16 +214,6 @@ module DaemonPropa = struct Demon.Fast.attach del key [Demon.Create.EventValue(SE.node s, Boolean.dom, s); Demon.Create.EventValue(node, real, s)] - | Conflict(p,_) -> - Demon.Fast.attach del key - [Demon.Create.EventValue(SE.node s, Boolean.dom, s)]; - Polynome.iter (fun node _ -> - Egraph.register del node; - Demon.Fast.attach del key - [Demon.Create.EventValue(node, real, s); - Demon.Create.EventChange(node, s); - ] - ) p end; propagate del s; end @@ -321,7 +222,7 @@ module RDaemonPropa = Demon.Fast.Register(DaemonPropa) let zero = cst Q.zero let one = cst Q.one -let index s = SE.index s Term._Real +let index s = SE.index s let add' q1 cl1 q2 cl2 = let norm q node = if Q.equal q Q.zero then Q.one, zero else q, node in @@ -356,14 +257,8 @@ let of_poly p = let to_poly = function | S.Add(q1,cl1,q2,cl2) -> Polynome.of_list Q.one [cl1,q1;cl2,q2] - | Conflict (p,_) -> p | GZero _ -> raise Impossible -let choarith = - Trail.Cho.create_key (module struct type t = Node.t let name = "LRA.cho" end) - -let make_dec node = Trail.GCho(node,choarith,node) - (** Choice *) (* (** Conflict *) @@ -623,359 +518,28 @@ let pp_hyppoly fmt c = (bound c.bound) Polynome.pp c.poly -module HypDom = struct - type t = hyppoly - - let pp = pp_hyppoly - - let key = - Trail.Hyp.create_key (module struct type nonrec t = t let name = "Arith.hyp" end) - - let pp_v fmt v = - let aux fmt (_,v) = pp_hyppoly fmt v in - SE.M.bindings v |> Format.(list ~sep:(const char ';') aux) fmt - - let levels _ = assert false - let split _ = assert false - let apply_learnt hyp = - match hyp.bound with - | Eq -> - let n = of_poly hyp.poly in - (Equality.equality [n;zero], Conflict.Neg) - | Le | Lt -> - let b = if equal_hypbound hyp.bound Le then Interval.Large else Interval.Strict in - let i = SE.index (S.Conflict(hyp.poly, b)) Term._Real in - let i = SE.node i in - (i, Conflict.Neg) - let useful_nodes _ = assert false -end - -let () = Conflict.register_hyp(module HypDom) - -module ExpEquality = struct - (* open Conflict *) - - type t = exp - let pp = pp_exp - let key = exp - - (* let extract_add s node = match SE.sem s with - * | S.Cst _ - * | S.GZero _ - * | S.Conflict _ - * -> raise Impossible - * (\* cl1 = 1/q1*(SE.node s) - q2/q1*cl2 *\) - * | S.Add (q1,cl1,q2,cl2) when Node.equal node cl1 -> - * cl1, (Q.inv q1), SE.node s, Q.neg (Q.div q2 q1), cl2 - * (\* cl2 = 1/q2*(SE.node s) - q1/q2*cl1 *\) - * | S.Add (q1,cl1,q2,cl2) when Node.equal node cl2 -> - * cl2, (Q.inv q2), SE.node s, Q.neg (Q.div q1 q2), cl1 - * (\* SE.node s = q1*cl1 + q2*cl2 *\) - * | S.Add (q1,cl1,q2,cl2) -> - * SE.node s,q1,cl1,q2,cl2 - * - * (\** the result must be physically one or the other *\) - * let best_bound_inf op1 op2 = - * match op1,op2 with - * | None, None -> None - * | None, (Some _ as p) | (Some _ as p), None -> p - * | Some p1, Some p2 -> - * let q1 = get_exp_conpoly p1 in - * let q2 = get_exp_conpoly p2 in - * if Interval.compare_bounds_inf (q1,p1.bound) (q2,p2.bound) < 0 - * then op2 else op1 - * - * (\** the result must be physically one or the other *\) - * let best_bound_sup op1 op2 = - * match op1,op2 with - * | None, None -> None - * | None, (Some _ as p) | (Some _ as p), None -> p - * | Some p1, Some p2 -> - * let q1 = get_exp_conpoly p1 in - * let q2 = get_exp_conpoly p2 in - * if Interval.compare_bounds_sup (q1,p1.bound) (q2,p2.bound) < 0 - * then op1 else op2 - * - * let best_bound p1 p2 = - * { mi = best_bound_inf p1.mi p2.mi; - * ma = best_bound_sup p1.ma p2.ma } - * - * (\** - * 0 <= x + P x + Q < 0 - * implies - * 0 < x - x + P - Q ( -P <= x < -Q ) - * there was an empty domain so that it was not verified. So for the proof - * we suppose that it is not verified - * 0 <= Q - P - * *\) - * let bound_distance_not_verified p1 = - * { mi = - * Opt.map2 (fun mi ma -> - * let p = x_p_cy_conpoly ma Q.minus_one mi in - * { p with bound = inv_bound p.bound } - * ) p1.mi p1.ma; - * ma = None } - * - * let get_pexp_or_add_def t pexp = - * match Conflict.Helpers.get_pexp_or_add t pexp condom with - * | None -> assert false - * | Some p -> p - * - * let get_dom t age node = - * (\* Look at all the modifications of the cls that are part of the - * equivalence class of this node, and keep the two with the best bounds - * *\) - * Debug.dprintf2 ~nobox:() debug "@,@[<v 3>@[[LRA] get_dom for %a@]" Node.pp node; - * let f t = - * let mod_doms = get_dom_before_last_dec t age node dom in - * let mi, ma = - * List.fold_left - * (fun (((mi,_) as miacc),((ma,_) as maacc)) - * (mod_dom:Trail.mod_dom) -> - * (\** dom -> modcl *\) - * let p' = (get_pexp_or_add_def t mod_dom.modpexp) in - * let mi'' = best_bound_inf mi p'.mi in - * let ma'' = best_bound_sup ma p'.ma in - * (if mi'' == mi then miacc else (p'.mi,mod_dom.modcl)), - * (if ma'' == ma then maacc else (p'.ma,mod_dom.modcl))) - * ((None,(\* dumb *\) zero),(None,(\* dumb *\) zero)) - * mod_doms in - * let f which = function - * | (None,_) -> - * Debug.dprintf0 debug "[LRA] Choose None"; - * None - * | (d,modcl) -> - * (\** node -> modcl *\) - * Debug.dprintf4 debug "[LRA] Choose %a from %a" (Opt.pp pp_conpoly) d Node.pp modcl; - * Opt.map2 add_conpoly d (which (get_rlist_conpair t node modcl)) - * in - * { mi = f (fun c -> c.mi) mi; ma = f (fun c -> c.ma) ma } - * in - * let p,deps = ComputeConflict.wrap_deps t f in - * let add_deps m = {m with deps = Deps.concat deps m.deps } in - * Debug.dprintf0 ~nobox:() debug "@]"; - * { mi = Opt.map add_deps p.mi; ma = Opt.map add_deps p.ma } - * - * - * let analyse t age con = function - * | ExpCst(node,q) -> - * Conflict.return con condom - * (mk_conpair (Polynome.of_list (Q.neg q) [node,Q.one])) - * | ExpAdd (s,cls) -> begin - * match SE.sem s with - * | S.Add _-> - * let cl0, q1, cl1, q2, cl2 = extract_add s cls in - * let d1 = get_dom t age cl1 in - * (\* Debug.dprintf2 debug "[LRA] d1=%a" pp_conpair d1; *\) - * let d2 = get_dom t age cl2 in - * (\* Debug.dprintf2 debug "[LRA] d2=%a" pp_conpair d2; *\) - * let semv = mk_conpair - * (Polynome.of_list Q.zero [cl0,Q.one;cl1,Q.neg q1;cl2,Q.neg q2]) in - * let d0 = add_conpair semv (cx_p_cy_conpair q1 d1 q2 d2) in - * (\* Debug.dprintf2 debug "[LRA] d0=%a" pp_conpair d0; *\) - * (\* Debug.dprintf10 debug *\) - * (\* "[LRA] cl0=%a q1=%a cl1=%a q2=%a cl2=%a" *\) - * (\* Node.pp cl0 Q.pp q1 Node.pp cl1 Q.pp q2 Node.pp cl2 ; *\) - * Conflict.return con condom d0 - * | S.Conflict p -> - * let repr = Polynome.fold (fun acc node _ -> - * Node.M.add (Conflict.ComputeConflict.get_repr_at t age node) node acc) - * Node.M.empty p in - * let cl0 = SE.node s in - * let semv,p' = Polynome.fold (fun (semv,acc) node q -> - * let node' = Conflict.ComputeConflict.get_repr_at t age node in - * let node' = Node.M.find_exn Impossible node' repr in - * let semv = x_p_cy_conpair semv q (get_rlist_conpair t node' node) in - * semv,Polynome.add acc (Polynome.monome q node') - * ) - * (mk_conpair p,Polynome.cst p.cst) - * p in - * let pcl0 = Polynome.monome Q.minus_one cl0 in - * let semv = add_conpair semv (mk_conpair pcl0) in - * let p' = Polynome.add p' pcl0 in - * Debug.dprintf2 debug "[LRA] p=%a" Polynome.pp p; - * Debug.dprintf2 debug "[LRA] semv=%a" pp_conpair semv; - * Debug.dprintf2 debug "[LRA] p'=%a" Polynome.pp p'; - * let mi = match semv.mi with - * | None -> assert false - * | Some mi -> mi in - * assert (Polynome.equal p' mi.exp); - * let qcls = Node.M.find_exn Impossible cls (mi.exp).poly in - * let semv = cst_mult_conpair (Q.inv qcls) semv in - * let mi = match semv.mi with - * | None -> assert false - * | Some mi -> mi in - * let semv = - * Polynome.fold (fun semv node q -> - * if Node.equal node cls then semv - * else - * let d = get_dom t age node in - * x_p_cy_conpair semv (Q.neg q) d - * ) semv (mi.exp) in - * Conflict.return con condom semv - * | _ -> raise Impossible - * end - * | ExpGZeroDown (s,nonot) -> - * let node,b = match SE.sem s with - * | S.GZero (node,b) -> node,b - * | _ -> raise Impossible in - * let cl0 = SE.node s in - * ComputeConflict.unknown_con t conclause - * (Boolean.get_dom t age cl0 Node.M.empty); - * let p = - * let exp = Polynome.monome Q.one node in - * if nonot - * then - * {mi = Some - * { imp = exp; exp; bound=b; - * deps = Deps.empty}; - * ma = None} - * else - * {ma = Some - * { imp = exp; exp; - * bound=inv_bound b; - * deps = Deps.empty}; - * mi = None} - * in - * Conflict.return con condom p - * | ExpEmptyDomMerge (pexp,cl1,cl2) -> - * let d1 = get_dom t age cl1 in - * let d2 = get_dom t age cl2 in - * let eq,deps = - * Conflict.ComputeConflict.Equal.one_pexp t ~from:cl1 ~to_:cl2 condom - * zero_conpair Deps.empty pexp - * in - * Conflict.ComputeConflict.add_deps t deps; - * assert (conpair_is_an_equality eq); - * Debug.dprintf6 debug "d1=%a;@ d2=%a;@ eq=%a" - * pp_conpair d1 pp_conpair d2 pp_conpair eq; - * let d2 = add_conpair eq d2 in - * let r = best_bound d1 d2 in - * Debug.dprintf4 debug "d2=%a@ r=%a" - * pp_conpair d2 pp_conpair r; - * let r = bound_distance_not_verified r in - * assert (None <> r.mi); - * assert (match Polynome.is_cst (Opt.get r.mi).exp, - * (Opt.get r.mi).bound with - * | Some q, Strict -> Q.lt Q.zero q - * | Some q, Large -> Q.leq Q.zero q - * | None,_ -> false); - * return con condom r - * | ExpEmptyDomInter (pexp,cl1) -> - * let d1 = get_dom t age cl1 in - * Debug.dprintf2 debug "d1=%a" pp_conpair d1; - * let d2 = (get_pexp_or_add_def t pexp) in - * Debug.dprintf2 debug "d2=%a" pp_conpair d2; - * let r' = best_bound d1 d2 in - * let r = bound_distance_not_verified r' in - * Debug.dprintf4 debug "r'=%a r=%a@" - * pp_conpair r' pp_conpair r; - * assert (None <> r.mi); - * assert (match Polynome.is_cst (Opt.get r.mi).exp, - * (Opt.get r.mi).bound with - * | Some q, Strict -> Q.lt Q.zero q - * | Some q, Large -> Q.leq Q.zero q - * | None,_ -> false); - * return con condom r - * | ExpGZeroUp(s,nonot) -> - * let node,b = match SE.sem s with - * | S.GZero (node,b) -> node,b - * | _ -> raise Impossible in - * let d = get_dom t age node in - * Debug.dprintf6 debug "node=%a %a d=%a" Node.pp node pp_bound b pp_conpair d; - * if nonot then begin - * assert ( implies d {ma = None; mi = Some { (mk_conpoly (Polynome.monome Q.one node)) with bound = b}} ); - * ComputeConflict.unknown_con t condom - * { d with ma = None } - * end else begin - * assert ( implies d {mi = None; ma = Some { (mk_conpoly (Polynome.monome Q.one node)) - * with bound = inv_bound b}} ); - * ComputeConflict.unknown_con t condom - * { d with mi = None } - * end; - * Conflict.return con conclause Node.M.empty - * | ExpDistIsZero s -> - * let cl0, q1, cl1, q2, cl2 = extract_add s (SE.node s) in - * let d0 = get_dom t age cl0 in - * let semv = mk_conpair - * (Polynome.of_list Q.zero [cl0,Q.minus_one;cl1,q1;cl2,q2]) in - * return con condom (add_conpair semv d0) - * | ExpIsSingleton(pexp,node,b,cst) -> - * let q = match SE.sem cst with | Cst q -> q | _ -> raise Impossible in - * let d1 = if b then get_dom t age node else {mi=None;ma=None} in - * let d2 = (get_pexp_or_add_def t pexp) in - * let r = best_bound d1 d2 in - * Debug.dprintf8 - * debug - * "r=%a d1=%a d2=%a q=%a" - * pp_conpair r pp_conpair d1 pp_conpair d2 Q.pp q; - * Conflict.return con condom r - * - * let expdomlimit _t _age dom' node con v _ = - * let v = Opt.get_exn Impossible v in - * let v = Dom.Eq.coerce dom' dom v in - * let mk = function - * | None -> None - * | Some (v,bound) -> - * let p = Polynome.of_list (Q.neg v) [node,Q.one] in - * Some {imp = p; exp = p; bound; deps = Deps.empty} in - * let mi,ma = D.get_convexe_hull v in - * return con condom {mi=mk mi;ma=mk ma} - * - * - * let same_sem (type a) t age (sem':a sem) (v:a) con exp cl1 cl2 = - * let r1 = analyse t age condom exp in - * let p = match r1 with - * | GRequested p1 -> - * let p2 = - * match Sem.Eq.eq_type S.key sem' with - * | None -> raise Impossible (\* understand why that happend *\) - * | Some Types.Eq -> - * Polynome.x_p_cy (Polynome.monome Q.one cl2) Q.minus_one - * (to_poly v) - * in - * x_p_cy_conpair p1 Q.minus_one (mk_conpair p2) - * | GOther _ -> raise Impossible (\* not created by analyse *\) - * in - * Debug.dprintf6 debug_todo "@[same_sem cl1:%a cl2:%a = %a@]" - * Node.pp cl1 Node.pp cl2 pp_conpair p; - * assert (conpair_is_an_equality p); - * assert (Polynome.equal (Opt.get p.mi).exp (dist cl1 cl2)); - * Conflict.return con condom p *) - - let analyse _ = assert false - let from_contradiction _ = assert false - -end - -let () = Conflict.register_exp(module ExpEquality) - - module ChoLRA = struct - open Conflict - - module OnWhat = Node - let make_decision node b env = - Debug.dprintf4 print_decision + Debug.dprintf4 Egraph.print_decision "[LRA] decide %a on %a" Q.pp b Node.pp node; - let pexp = Egraph.mk_pexp env exp (ExpDec(node,b)) in - set_dom env pexp node (D.singleton b) false + set_dom env node (D.singleton b) - let choose_decision env node = + let choose_decision node env = let v = Opt.get_def D.reals (Egraph.get_dom env dom node) in match D.is_singleton v with - | Some _ -> DecNo + | Some _ -> Egraph.DecNo | None -> DecTodo (make_decision node (D.choose v)) - let key = choarith -end + let choice n = { + Egraph.prio = 1; + choice = choose_decision n; + } -let () = Conflict.register_cho(module ChoLRA) +end (** API *) -let index x = SE.node (SE.index x Term._Real) +let index x = SE.node (SE.index x) let as_node node = index (S.Add (Q.one,node,Q.one,zero)) @@ -997,10 +561,10 @@ let mult_cst cst node = add' cst node Q.one zero let gt_zero node = - SE.node (SE.index (GZero(node,Strict)) Boolean.ty) + SE.node (SE.index (GZero(node,Strict))) let ge_zero node = - SE.node (SE.index (GZero(node,Large)) Boolean.ty) + SE.node (SE.index (GZero(node,Large))) let lt cl1 cl2 = gt_zero (sub cl2 cl1) let le cl1 cl2 = ge_zero (sub cl2 cl1) @@ -1008,42 +572,55 @@ let gt cl1 cl2 = lt cl2 cl1 let ge cl1 cl2 = le cl2 cl1 (** {2 Initialization} *) -let converter d f l = +let converter d (f:Expr.Term.t) = let of_term t = let n = SynTerm.node_of_term t in Egraph.register d n; n in - let node = match f, l with - | f,[] when Term.is_const_real_term f -> - Some (cst (Term.get_const_real_term f)) - | f,a::args when Term.is_add_real_term f -> - Some (List.fold_left add (of_term a) (List.map of_term args)) - | f,[arg1;arg2] when Term.equal f Term.sub_real_term -> - Some (sub (of_term arg1) (of_term arg2)) - | f,[arg] when Term.equal f Term.neg_real_term -> - Some (neg (of_term arg)) - | f,args when Term.equal f Term.mul_real_term -> begin - let mult_cst c t = - Some (mult_cst (Term.get_const_real_term c) (of_term t)) - in - match args with - | [arg1;arg2] when Term.is_const_real_term arg1 -> - mult_cst arg1 arg2 - | [arg1;arg2] when Term.is_const_real_term arg2 -> - mult_cst arg2 arg1 - | _ -> None - end - | f,[arg1;arg2] when Term.is_lt_real_term f -> - Some (lt (of_term arg1) (of_term arg2)) - | f,[arg1;arg2] when Term.is_le_real_term f -> - Some (le (of_term arg1) (of_term arg2)) - | _ -> None in - node - -let decvars n = - if Ty.equal (Node.ty n) Term._Real - then Some (make_dec n) + match f with + | { descr = Expr.App({builtin = Expr.Integer s},[],[]); _ } -> + Some (cst (Q.of_string s)) + | { descr = Expr.App({builtin = Expr.Decimal s},[],[]); _ } -> + Some (cst (Q.of_string_decimal s)) + | { descr = Expr.App({builtin = Expr.Rational s},[],[]); _ } -> + Some (cst (Q.of_string_decimal s)) + | { descr = Expr.App({builtin = Expr.Add},[],[a;b]); _ } -> + Some (add (of_term a) (of_term b)) + | { descr = Expr.App({builtin = Expr.Sub},[],[a;b]); _ } -> + Some (sub (of_term a) (of_term b)) + | { descr = Expr.App({builtin = Expr.Neg},[],[a]); _ } -> + Some (neg (of_term a)) + | { descr = Expr.App({builtin = Expr.Mul},[],args); _ } -> begin + let mult_cst c t = Some (mult_cst c (of_term t)) in + match args with + | [{descr = Expr.App({builtin = Expr.Integer s; _},[],[])};arg2] -> + mult_cst (Q.of_string s) arg2 + | [{descr = Expr.App({builtin = Expr.Decimal s; _},[],[])};arg2] -> + mult_cst (Q.of_string_decimal s) arg2 + | [{descr = Expr.App({builtin = Expr.Rational s; _},[],[])};arg2] -> + mult_cst (Q.of_string_decimal s) arg2 + | [arg2;{descr = Expr.App({builtin = Expr.Integer s; _},[],[])}] -> + mult_cst (Q.of_string s) arg2 + | [arg2;{descr = Expr.App({builtin = Expr.Decimal s; _},[],[])}] -> + mult_cst (Q.of_string_decimal s) arg2 + | [arg2;{descr = Expr.App({builtin = Expr.Rational s; _},[],[])}] -> + mult_cst (Q.of_string_decimal s) arg2 + | _ -> None + end + | { descr = Expr.App({builtin = Expr.Lt},[],[arg1;arg2]); _ } -> + Some (lt (of_term arg1) (of_term arg2)) + | { descr = Expr.App({builtin = Expr.Leq},[],[arg1;arg2]); _ } -> + Some (le (of_term arg1) (of_term arg2)) + | { descr = Expr.App({builtin = Expr.Gt},[],[arg1;arg2]); _ } -> + Some (gt (of_term arg1) (of_term arg2)) + | { descr = Expr.App({builtin = Expr.Geq},[],[arg1;arg2]); _ } -> + Some (ge (of_term arg1) (of_term arg2)) + | _ -> None + +let decvars t n = + if Expr.Ty.equal (Expr.Term.ty t) Expr.Ty.real + then Some (ChoLRA.choice n) else None @@ -1063,8 +640,6 @@ let th_register env = (fun d value -> let v = RealValue.value value in let s = D.singleton v in - let _pexp = Egraph.mk_pexp d exp (ExpCst value) in - (** something must be done with the pexp *) Egraph.set_dom d dom (RealValue.node value) s ) env; () @@ -1080,44 +655,48 @@ let () = match t with | Add(q1,n1,q2,n2) -> let v = Q.( q1 * (get_v n1) + q2 * (get_v n2)) in - RealValue.nodevalue (RealValue.index v Term._Real) + RealValue.nodevalue (RealValue.index v) | GZero(n,bound) -> gzero bound (get_v n) - | Conflict (p,bound) -> - let v = Polynome.fold (fun acc n q -> Q.( acc + q * (get_v n))) Q.zero p in - gzero bound v in Interp.Register.thterm S.key interp let default_value = Q.zero -let () = - Interp.Register.model Term._Real (fun d n -> - let v = Egraph.get_value d real n in - let v = Witan_popop_lib.Opt.get_def default_value v in - let v = RealValue.nodevalue (RealValue.index v Term._Real) in - v) +(* let () = + * Interp.Register.model Term._Real (fun d n -> + * let v = Egraph.get_value d real n in + * let v = Witan_popop_lib.Opt.get_def default_value v in + * let v = RealValue.nodevalue (RealValue.index v Term._Real) in + * v) *) let () = - Interp.Register.id (fun id args -> - let is builtin = Term.Id.equal id builtin in - let (!>) n = RealValue.value (RealValue.coerce_nodevalue n) in - let (!<) v = Some (RealValue.nodevalue (RealValue.index v Term._Real)) in + Interp.Register.id (fun interp t -> + let (!>) t = RealValue.value (RealValue.coerce_nodevalue (interp t)) in + let (!<) v = Some (RealValue.nodevalue (RealValue.index v)) in let (!<<) b = Some (if b then Boolean.values_true else Boolean.values_false) in - match args with - | [] when Term.is_const_real_id id -> - !< (Term.get_const_real_id id) - | args when Term.is_add_real_id id -> - !< (List.fold_left (fun acc a -> Q.add acc (!> a)) Q.zero args) - | [arg1;arg2] when is Term.sub_real_id -> - !< (Q.sub (!> arg1) (!> arg2)) - | [arg] when is Term.neg_real_id -> - !< (Q.neg (!> arg)) - | [arg1;arg2] when is Term.mul_real_id -> - !< (Q.mul (!> arg1) (!> arg2)) - | [arg1;arg2] when Term.is_lt_real_id id -> - !<< (Q.lt (!> arg1) (!> arg2)) - | [arg1;arg2] when Term.is_le_real_id id -> - !<< (Q.le (!> arg1) (!> arg2)) - | _ -> None + match t with + | { descr = Expr.App({builtin = Expr.Integer s},[],[]); _ } -> + !< (Q.of_string s) + | { descr = Expr.App({builtin = Expr.Decimal s},[],[]); _ } -> + !< (Q.of_string_decimal s) + | { descr = Expr.App({builtin = Expr.Rational s},[],[]); _ } -> + !< (Q.of_string_decimal s) + | { descr = Expr.App({builtin = Expr.Add},[],[a;b]); _ } -> + !< (Q.add !>a !>b) + | { descr = Expr.App({builtin = Expr.Sub},[],[a;b]); _ } -> + !< (Q.sub !>a !>b) + | { descr = Expr.App({builtin = Expr.Neg},[],[a]); _ } -> + !< (Q.neg !>a) + | { descr = Expr.App({builtin = Expr.Mul},[],[a;b]); _ } -> + !< (Q.mul !>a !>b) + | { descr = Expr.App({builtin = Expr.Lt},[],[arg1;arg2]); _ } -> + !<< (Q.lt !>arg1 !>arg2) + | { descr = Expr.App({builtin = Expr.Leq},[],[arg1;arg2]); _ } -> + !<< (Q.leq !>arg1 !>arg2) + | { descr = Expr.App({builtin = Expr.Gt},[],[arg1;arg2]); _ } -> + !<< (Q.gt !>arg1 !>arg2) + | { descr = Expr.App({builtin = Expr.Geq},[],[arg1;arg2]); _ } -> + !<< (Q.geq !>arg1 !>arg2) + | _ -> None ) diff --git a/src/theories/bool/boolean.ml b/src/theories/bool/boolean.ml index 9bf7e90d57d5d6022336f3e0fb03814c646f6072..3121fa1d8bb7f228ecbef04da2bded41c4ee80ab 100644 --- a/src/theories/bool/boolean.ml +++ b/src/theories/bool/boolean.ml @@ -29,7 +29,6 @@ let debug = Debug.register_info_flag ~desc:"for the boolean theory" "bool" -let ty = Term._Prop let dom = ValueKind.create_key (module struct type t = bool let name = "bool" end) module BoolValue = ValueKind.Register(struct @@ -37,11 +36,11 @@ module BoolValue = ValueKind.Register(struct let key = dom end) -let value_true = BoolValue.index ~basename:"⊤" true ty +let value_true = BoolValue.index ~basename:"⊤" true let values_true = BoolValue.nodevalue value_true let node_true = BoolValue.node value_true -let value_false = BoolValue.index ~basename:"⊥" false ty +let value_false = BoolValue.index ~basename:"⊥" false let values_false = BoolValue.nodevalue value_false let node_false = BoolValue.node value_false @@ -49,7 +48,7 @@ let node_false = BoolValue.node value_false (* let union_disjoint m1 m2 = * Node.M.union (fun _ b1 b2 -> assert (Equal.physical b1 b2); Some b1) m1 m2 *) -let index sem v = Node.index_sem sem v ty +let index sem v = Node.index_sem sem v let is env node = Egraph.get_value env dom node let is_true env node = Node.equal node node_true @@ -58,8 +57,8 @@ let is_false env node = Node.equal node node_false || Equal.option Equal.bool (is env node) (Some false) let is_unknown env node = Equal.option Equal.bool (is env node) None -let set_bool env pexp node b = - Egraph.merge env pexp node +let set_bool env node b = + Egraph.merge env node (if b then node_true else node_false) type t = @@ -166,22 +165,6 @@ end module ThE = ThTermKind.Register(Th) -(** At least all the leaves except one are known and can be discarded *) -type bcpkind = - | BCPOwnKnown (** Top is known and true modulo topnot, propagate true modulo sign to propa *) - | BCPLeavesKnown (** All leaves are known and false modulo sign, propagate false modulo topnot to own *) - | BCP (** Merge top with the remaining leave *) -[@@deriving eq] - -type expprop = -| ExpBCP of ThE.t (* own *) * Node.t (* propa *) * bcpkind -| ExpUp of ThE.t (* own *) * Node.t (* one leaf to own *) -| ExpDown of ThE.t (* own *) * Node.t (* leaf *)(* own to leaf *) -| ExpNot of (Th.t * Node.t * Node.t) * bool (* what have been propagated *) -| ExpDec of Node.t * bool - -let expprop = Exp.create_key (module struct type t = expprop let name = "Bool.prop" end) - module DaemonPropaNot = struct module Data = struct @@ -195,13 +178,12 @@ module DaemonPropaNot = struct let throttle = 100 let wakeup d = function - | Events.Fired.EventValue(_,dom',((_,node,ncl) as x)) -> + | Events.Fired.EventValue(_,dom',((_,node,ncl))) -> assert (ValueKind.equal dom dom'); begin match Egraph.get_value d dom node with | None -> raise Impossible | Some b -> - let pexp = Egraph.mk_pexp d expprop (ExpNot(x,not b)) in - set_bool d pexp ncl (not b) + set_bool d ncl (not b) end; | _ -> raise UnwaitedEvent @@ -210,14 +192,11 @@ module DaemonPropaNot = struct let own = ThE.node thterm in match is d own with | Some b -> - let pexp = Egraph.mk_pexp d expprop (ExpNot((v,own,node),not b)) in - set_bool d pexp node (not b) + set_bool d node (not b) | None -> match is d node with | Some b -> - let pexp = Egraph.mk_pexp d expprop - (ExpNot((v,node,own),not b)) in - set_bool d pexp own (not b) + set_bool d own (not b) | None -> let events = [Demon.Create.EventValue(own,dom,(v,own,node)); Demon.Create.EventValue(node,dom,(v,node,own))] in @@ -252,35 +231,26 @@ module DaemonPropa = struct let wakeup_lit d thterm watched watcher = let v = ThE.sem thterm in let own = ThE.node thterm in - let pexp exp = Egraph.mk_pexp d expprop exp in - let set_dom_up_true d own leaf _ = + let set_dom_up_true d own _ _ = let b = (not v.topnot) in match Egraph.get_value d dom own with | Some b' when Equal.bool b' b -> () - | _ -> set_bool d (pexp (ExpUp(thterm,leaf))) own b in + | _ -> set_bool d own b in let merge_bcp node sign = Debug.dprintf2 debug "[Bool] @[merge_bcp %a@]" Node.pp node; match Egraph.get_value d dom own with | Some b' -> - let pexp = if (mulbool b' v.topnot) - then pexp (ExpBCP(thterm,node,BCPOwnKnown)) - else pexp (ExpDown(thterm,node)) - in let b = mulbool sign (mulbool b' v.topnot) in - set_bool d pexp node b + set_bool d node b | None -> (** merge *) match Egraph.get_value d dom node with | Some b' -> - let pexp = if (mulbool b' sign) - then pexp (ExpUp(thterm,node)) - else pexp (ExpBCP(thterm,node,BCPLeavesKnown)) - in let b = mulbool sign (mulbool b' v.topnot) in - set_bool d pexp own b + set_bool d own b | None -> (** merge *) if mulbool v.topnot sign then DaemonPropaNot.init d thterm node - else Egraph.merge d (pexp (ExpBCP(thterm,node,BCP))) own node in + else Egraph.merge d own node in let rec find_watch dir pos bound = assert (dir = 1 || dir = -1); if pos = bound @@ -319,7 +289,6 @@ module DaemonPropa = struct let wakeup_own d thterm = let v = ThE.sem thterm in let own = ThE.node thterm in - let pexp exp = Egraph.mk_pexp d expprop exp in begin match Egraph.get_value d dom own with | None -> (* only during init *) Demon.Fast.attach d key @@ -327,8 +296,7 @@ module DaemonPropa = struct true (** \/ c1 c2 = false ==> c1 = false /\ c2 = false *) | Some b when not (mulbool v.topnot b) -> - let set_dom_down_false (node,sign) = - set_bool d (pexp (ExpDown(thterm,node))) node sign in + let set_dom_down_false (node,sign) = set_bool d node sign in IArray.iter set_dom_down_false v.lits; false | Some _ -> true @@ -440,241 +408,65 @@ let mk_clause m = let _false = node_false -let set_true env pexp node = set_bool env pexp node true - -let () = - let gen_or l = - let l = List.map (function - | (n,Conflict.Pos) -> (n,false) - | (n,Conflict.Neg) -> (n,true)) l in - gen false l in - Conflict._or := gen_or; - Conflict._set_true := set_true; - Conflict._is_true := is_true - -let set_false env pexp node = set_bool env pexp node false +let set_true env node = set_bool env node true +let set_false env node = set_bool env node false -let chobool = Trail.Cho.create_key (module struct type t = Node.t let name = "Bool.cho" end) -let make_dec node = Trail.GCho(node,chobool,node) - -let converter d f l = +let converter d (f:Expr.Term.t) = let of_term t = let n = SynTerm.node_of_term t in Egraph.register d n; n in - let node = match f, l with - | f,args when Term.is_or_term f -> - Some (_or (List.map of_term args)) - | f,args when Term.is_and_term f -> - Some (_and (List.map of_term args)) - | f,[arg1;arg2] when Term.equal f Term.imply_term -> - Some (gen false [of_term arg1,true;of_term arg2,false]) - | f,[arg] when Term.equal f Term.not_term -> - Some (_not (of_term arg)) - | f,[] when Term.equal f Term.true_term -> - Some _true - | f,[] when Term.equal f Term.false_term -> - Some _false - | _ -> None in - node - -let decvars n = - if Ty.equal (Node.ty n) ty - then Some (make_dec n) - else None - -let th_register env = - RDaemonPropaNot.init env; - RDaemonPropa.init env; - RDaemonInit.init env; - Demon.Fast.attach env - DaemonInit.key [Demon.Create.EventRegSem(sem,())]; - Egraph.register env node_true; - Egraph.register env node_false; - SynTerm.register_converter env converter; - SynTerm.register_decvars env decvars; - () + match f with + | { descr = Expr.App({builtin = Expr.Or},[],args); _ } -> + Some (_or (List.map of_term args)) + | { descr = Expr.App({builtin = Expr.And},[],args); _ } -> + Some (_and (List.map of_term args)) + | { descr = Expr.App({builtin = Expr.Imply},[],[arg1;arg2]); _ } -> + Some (gen false [of_term arg1,true;of_term arg2,false]) + | { descr = Expr.App({builtin = Expr.Neg},[],[arg]); _ } -> + Some (_not (of_term arg)) + | { descr = Expr.App({builtin = Expr.True},[],[]); _ } -> + Some _true + | { descr = Expr.App({builtin = Expr.False},[],[]); _ } -> + Some _false + | _ -> None (** {2 Choice on bool} *) module ChoBool = struct - open Conflict - - module OnWhat = Node - module What = DBool - let make_decision env node b = - Debug.dprintf3 print_decision "[Bool] decide %b on %a" b Node.pp node; - let pexp = Egraph.mk_pexp env expprop (ExpDec(node,b)) in - set_bool env pexp node b + Debug.dprintf3 Egraph.print_decision "[Bool] decide %b on %a" b Node.pp node; + set_bool env node b - let choose_decision env node = + let choose_decision node env = match Egraph.get_value env dom node with - | Some _ -> DecNo + | Some _ -> Egraph.DecNo | None -> DecTodo (fun env -> make_decision env node true) (** why not true? *) - let key = chobool - -end - -let () = Conflict.register_cho (module ChoBool) - -(** {2 Conflict} *) - -(** We could use instead directly EqHyp, but it gives an example of a - simple conflict other than EqHyp *) -module HypProp = struct - type t = (Node.t * bool) - - let pp fmt (n,b) = - if b - then Format.fprintf fmt "¬%a" Node.pp n - else Node.pp fmt n - - let key = Trail.Hyp.create_key (module struct type nonrec t = t let name = "hypprop" end) - - let apply_learnt (n,b) = (n,if b then Conflict.Neg else Conflict.Pos) - - let node_of_sign b = (node_of_bool (mulbool true b)) - - let levels t (n,b) = - let levels = Conflict.Levels.empty in - let age = Conflict.Conflict.age_merge t n (node_of_sign b) in - Conflict.Levels.add t age levels - - let useful_nodes (n,_) = Bag.elt n - - let split t (n,b) a' b' = - let l', r' = Conflict.EqHyp.split t {l=n;r=node_of_sign b} a' b' in - (match l' with - | None -> [] - | Some r -> [Trail.Phyp.phyp Conflict.EqHyp.key {l=n; r}]) - @ - (match r' with - | None -> [] - | Some l -> [Trail.Phyp.phyp key (l,b)]) - end -let () = Conflict.register_hyp (module HypProp) - -(** {2 Explanation} *) - -module ExpProp = struct - open Conflict - type t = expprop - - let pp fmt = function - | ExpBCP (thterm,node,kind) -> - Format.fprintf fmt "Bcp(%a,%a = %a;%t)" - ThE.pp thterm Node.pp (ThE.node thterm) Node.pp node - (fun _ -> match kind with - | BCPOwnKnown -> Format.fprintf fmt "Own" - | BCPLeavesKnown -> Format.fprintf fmt "Leaves" - | BCP -> ()) - | ExpUp (thterm,leaf) -> - Format.fprintf fmt "Up(%a,%a <- %a)" - ThE.pp thterm Node.pp (ThE.node thterm) Node.pp leaf - | ExpDown (thterm,node) -> - Format.fprintf fmt "Down(%a,%a,%a ->)" - ThE.pp thterm Node.pp (ThE.node thterm) Node.pp node - | ExpNot ((v,clf,clt),b) -> - Format.fprintf fmt "Not(%a,%a,%a,%b)" - Th.pp v Node.pp clf Node.pp clt b - | ExpDec (n,b) -> - Format.fprintf fmt "Dec(%a,%b)" - Node.pp n b - - let eq_of_bool ?dec n b = - Trail.Phyp.phyp ?dec HypProp.key (n,not b) - - let analyse_one_to_one ?dec t phyp to_ to_b from_ from_b = - (** we have - c: a = b - we propagated: to_ = to_b - because : from_ = from_b - *) - let to_not = node_of_bool to_b in - let eqs = Conflict.split t phyp to_ to_not in - let eq = eq_of_bool ?dec from_ from_b in - Debug.dprintf10 debug "clfrom:%a from_b:%b clto:%a to_b:%b eqs:%a eq:%a" - Node.pp from_ - from_b - Node.pp to_ - to_b - (Format.(list ~sep:(const char ',') pp_phyp)) - eqs - pp_phyp eq; - (eq::eqs) - - let analyse : - Conflict.t -> - t -> Trail.Phyp.t -> Trail.Phyp.t list = - fun t exp phyp -> - match exp with - | ExpBCP (thterm,_,_) when IArray.length (ThE.sem thterm).lits = 1 -> - raise Impossible - | ExpBCP (thterm,propa,kind) -> - let v = ThE.sem thterm in - let own = ThE.node thterm in - let eqs = - match kind with - | BCP -> Conflict.split t phyp own propa - | BCPOwnKnown -> - let propa_sign = mulbool true (Opt.get (find v propa)) in - Conflict.split t phyp propa (node_of_bool propa_sign) - | BCPLeavesKnown -> - let sign = mulbool false v.topnot in - Conflict.split t phyp propa (node_of_bool sign) - in - let eqs = if equal_bcpkind kind BCPOwnKnown then (eq_of_bool own (mulbool true v.topnot))::eqs else eqs in - fold (fun eqs (node,sign) -> - if (not(equal_bcpkind kind BCPLeavesKnown)) && (Node.equal node propa) then eqs - else (eq_of_bool node (mulbool false sign))::eqs) eqs v - | ExpUp (thterm,leaf) -> - let v = ThE.sem thterm in - let own = ThE.node thterm in - analyse_one_to_one t phyp - own (mulbool true v.topnot) - leaf (mulbool true (Opt.get (find v leaf))) - | ExpDown (thterm,leaf) -> - let v = ThE.sem thterm in - let own = ThE.node thterm in - analyse_one_to_one t phyp - leaf (mulbool false (Opt.get (find v leaf))) - own (mulbool false v.topnot) - | ExpNot ((_,clfrom,clto),b)-> - analyse_one_to_one t phyp - clto b - clfrom (not b) - | ExpDec (cl,b) -> - analyse_one_to_one ~dec:() t phyp - cl b - cl b - - let key = expprop - - let from_contradiction _ _ = - assert false (** absurd: never used for contradiction *) -end +let chobool n = { + Egraph.prio = 1; + choice = ChoBool.choose_decision n; +} -let () = Conflict.register_exp(module ExpProp) +let decvars t n = + if Ty.equal (Expr.Term.ty t) Dolmen_std.Expr.Ty.bool + then Some (chobool n) + else None -let () = - let parity_of_bool b = if b then Conflict.Neg else Conflict.Pos in - Conflict.EqHyp.register_apply_learnt ty - (fun {Conflict.EqHyp.l;r} -> - if Node.equal l node_false - then (r,parity_of_bool true) - else if Node.equal l node_true - then (r,parity_of_bool false) - else if Node.equal r node_false - then (l,parity_of_bool true) - else if Node.equal r node_true - then (l,parity_of_bool false) - else !Conflict._equality l r, Pos - ) +let th_register env = + RDaemonPropaNot.init env; + RDaemonPropa.init env; + RDaemonInit.init env; + Demon.Fast.attach env + DaemonInit.key [Demon.Create.EventRegSem(sem,())]; + Egraph.register env node_true; + Egraph.register env node_false; + SynTerm.register_converter env converter; + SynTerm.register_decvars env decvars; + () (** {2 Interpretations} *) let () = @@ -693,27 +485,32 @@ let () = let default_value = true -let () = - Interp.Register.model ty (fun d n -> - let v = Egraph.get_value d dom n in - let v = Witan_popop_lib.Opt.get_def default_value v in - let v = if v then values_true else values_false in - v) +(* let () = + * Interp.Register.model ty (fun d n -> + * let v = Egraph.get_value d dom n in + * let v = Witan_popop_lib.Opt.get_def default_value v in + * let v = if v then values_true else values_false in + * v) *) let () = - Interp.Register.id (fun id args -> - let open Term in - let is builtin = Term.Id.equal id builtin in - let (!>) n = BoolValue.value (BoolValue.coerce_nodevalue n) in + Interp.Register.id (fun interp t -> + let (!>) t = BoolValue.value (BoolValue.coerce_nodevalue (interp t)) in let (!<) b = Some (if b then values_true else values_false) in - match args with - | [] when is true_id -> Some values_true - | [] when is false_id -> Some values_false - | [a] when is not_id -> !< (not (!> a)) - | l when is_or_id id -> !< (List.fold_left (||) false (List.map (!>) l)) - | l when is_and_id id -> !< (List.fold_left (&&) true (List.map (!>) l)) + match t with + | { descr = Expr.App({builtin = Expr.Or},[],args); _ } -> + !< (List.fold_left (||) false (List.map (!>) args)) + | { descr = Expr.App({builtin = Expr.And},[],args); _ } -> + !< (List.fold_left (&&) true (List.map (!>) args)) + | { descr = Expr.App({builtin = Expr.Imply},[],[arg1;arg2]); _ } -> + !< ( not (!> arg1) || !> arg2 ) + | { descr = Expr.App({builtin = Expr.Neg},[],[arg]); _ } -> + !< (not (!> arg)) + | { descr = Expr.App({builtin = Expr.True},[],[]); _ } -> + Some values_true + | { descr = Expr.App({builtin = Expr.False},[],[]); _ } -> + Some values_false | _ -> None ) diff --git a/src/theories/bool/boolean.mli b/src/theories/bool/boolean.mli index cf84af45a711bffe6b964801437bdd3183b01728..3bd258bfbe0968715515cafe347bdb46defe9cc5 100644 --- a/src/theories/bool/boolean.mli +++ b/src/theories/bool/boolean.mli @@ -18,8 +18,6 @@ (* for more details (enclosed in the file licenses/LGPLv2.1). *) (*************************************************************************) -open Witan_core_structures - type t val sem: t ThTermKind.t val dom: bool ValueKind.t @@ -34,8 +32,8 @@ val gen : bool -> (Node.t * bool) list -> Node.t not_b0 (or (not_b1 cl1,not_b2 cl2)) with not_x f = if x then not f else f *) -val set_true : Egraph.t -> Trail.Pexp.t -> Node.t -> unit -val set_false : Egraph.t -> Trail.Pexp.t -> Node.t -> unit +val set_true : Egraph.t -> Node.t -> unit +val set_false : Egraph.t -> Node.t -> unit val is : Egraph.t -> Node.t -> bool option val is_true : Egraph.t -> Node.t -> bool @@ -48,12 +46,10 @@ val is_unknown : Egraph.t -> Node.t -> bool val th_register: Egraph.t -> unit -val chobool: Node.t Trail.Cho.t +val chobool: Node.t -> Egraph.choice (* val make_dec: Variable.make_dec *) -val ty: Ty.t - module BoolValue : ValueKind.Registered with type s = bool val value_true : BoolValue.t diff --git a/src/theories/bool/dune b/src/theories/bool/dune index 9d88d4ee3ec606d7a188bb8118532f48b16432cf..3829004922a81c207b21da48120cf334f340aa4b 100644 --- a/src/theories/bool/dune +++ b/src/theories/bool/dune @@ -4,9 +4,9 @@ (synopsis "theories for witan") (modules Boolean Equality Uninterp) (libraries containers ocamlgraph witan.stdlib witan.popop_lib - witan.core.structures witan.core) + witan.core.structures witan.core dolmen.std) (preprocess - (pps ppx_deriving.std)) + (pps ppx_deriving.std ppx_hash)) (flags :standard -w +a-4-42-44-48-50-58-32-60-40-9@8 -color always -open Containers -open Witan_stdlib -open Std -open Witan_core) (ocamlopt_flags :standard -O3 -bin-annot -unbox-closures diff --git a/src/theories/bool/equality.ml b/src/theories/bool/equality.ml index b673b83297b61d82d5d77852173b7350c72529e9..9776c7affa0c392d24b3bafab253526095df7306 100644 --- a/src/theories/bool/equality.ml +++ b/src/theories/bool/equality.ml @@ -35,11 +35,7 @@ let sem = ThTermKind.create_key (module struct type nonrec t = t let name = "Eq" module Th = struct - let get_ty v = Node.ty (fst (Node.M.choose v)) - - let inv s = not (Node.M.is_empty s || Node.M.is_num_elt 1 s) && - let ty = get_ty s in - (Node.M.for_all (fun e _ -> Ty.equal ty (Node.ty e)) s) + let inv s = not (Node.M.is_empty s || Node.M.is_num_elt 1 s) let only_two s = assert (inv s); @@ -86,34 +82,34 @@ module Dis : sig val empty: t val of_node: ThE.t -> elt val to_node: elt -> ThE.t - val test_disjoint: (elt -> Trail.Age.t -> unit) -> t -> t -> t + val test_disjoint: (elt -> unit) -> t -> t -> t val disjoint : t -> t -> bool - val singleton : elt -> Trail.Age.t -> t + val singleton : elt -> t val inter : t -> t -> t val is_empty : t -> bool - val choose : t -> elt * Trail.Age.t - val iter : (elt -> Trail.Age.t -> unit) -> t -> unit + val choose : t -> elt + val iter : (elt -> unit) -> t -> unit end = struct - type t = Trail.Age.t ThE.M.t + type t = ThE.S.t type elt = ThE.t - let empty = ThE.M.empty + let empty = ThE.S.empty let pp fmt s = let aux fmt m = ThE.M.bindings m |> Format.(list ~sep:(const char ';') - (pair ~sep:(const char ',') ThE.pp Trail.Age.pp)) fmt + (pair ~sep:(const char ',') ThE.pp Pp.nothing)) fmt in Format.fprintf fmt "{%a}" aux s let of_node x = x let to_node x = x let test_disjoint f m1 m2 = - ThE.M.union (fun k v1 v2 -> assert (Trail.Age.equal v1 v2); f k v1; Some v1) m1 m2 - let disjoint = ThE.M.set_disjoint - let singleton = ThE.M.singleton - let is_empty = ThE.M.is_empty - let inter m1 m2 = ThE.M.inter (fun _ v1 v2 -> assert (Trail.Age.equal v1 v2); Some v2) m1 m2 - let choose m1 = ThE.M.choose m1 - let iter = ThE.M.iter + ThE.M.union (fun k () () -> f k; Some ()) m1 m2 + let disjoint = ThE.S.disjoint + let singleton = ThE.S.singleton + let is_empty = ThE.S.is_empty + let inter m1 m2 = ThE.S.inter m1 m2 + let choose m1 = ThE.S.choose m1 + let iter = ThE.S.iter end let dom = DomKind.create_key (module struct type t = Dis.t let name = "dis" end) @@ -121,16 +117,6 @@ let dom = DomKind.create_key (module struct type t = Dis.t let name = "dis" end) (** For each value key give the value *) module MValues = ValueKind.MkMap(struct type ('a, _) t = 'a end) -type exp = - | Merge of Trail.Pexp.t * Node.t * Node.t * Dis.elt * Trail.Age.t - | SubstUpTrue of ThE.t * Node.t (* e1 *) * Node.t (* e2 *) * Node.t - | SubstUpFalse of ThE.t * (Node.t * (Dis.t option * unit MValues.t)) list - | SubstDownTrue of ThE.t - | SubstDownFalse of ThE.t * Dis.elt - | Dec of Node.t * Node.t - -let exp = Trail.Exp.create_key (module struct type t = exp let name = "Equality" end) - module D = struct type t = Dis.t @@ -141,7 +127,7 @@ module D = struct | None, None -> true | _ -> false - let merge d pexp (s1,cl1) (s2,cl2) _ = + let merge d (s1,cl1) (s2,cl2) _ = match s1, s2 with | None, None -> raise Impossible | Some s, None -> @@ -149,9 +135,7 @@ module D = struct | None, Some s -> Egraph.set_dom d dom cl1 s | Some s1, Some s2 -> - let s = Dis.test_disjoint (fun i age -> - let pexp = Egraph.mk_pexp d exp (Merge(pexp,cl1,cl2,i,age)) in - Egraph.contradiction d pexp) s1 s2 in + let s = Dis.test_disjoint (fun _ -> Egraph.contradiction d) s1 s2 in Egraph.set_dom d dom cl1 s; Egraph.set_dom d dom cl2 s @@ -162,7 +146,7 @@ end let () = DomKind.register(module D) -let set_dom d _pexp cl s = +let set_dom d cl s = let s = match Egraph.get_dom d dom cl with | Some s' -> Dis.test_disjoint (fun _ -> assert false) s' s @@ -170,7 +154,7 @@ let set_dom d _pexp cl s = Egraph.set_dom d dom cl s let check_sem v cl = - let own = ThE.node (ThE.index v Boolean.ty) in + let own = ThE.node (ThE.index v) in Node.equal cl own (** API *) @@ -179,7 +163,7 @@ let equality cll = try let fold acc e = Node.S.add_new Exit e acc in let s = List.fold_left fold Node.S.empty cll in - ThE.node (ThE.index s Boolean.ty) + ThE.node (ThE.index s) with Exit -> Boolean._true @@ -194,9 +178,9 @@ let is_disequal t cl1 cl2 = | Some s1, Some s2 -> not (Dis.disjoint s1 s2) | _ -> false -let new_tag n age = +let new_tag n = let n = Dis.of_node n in - n, fun () -> Dis.singleton n age (** each instance of this tag must not be == *) + n, fun () -> Dis.singleton n (** each instance of this tag must not be == *) exception Found of Node.t * Node.t @@ -258,47 +242,41 @@ let norm_set d the = e e0 acc) Node.M.empty v); false - with Found (e1,e2) -> + with Found (_e1,_e2) -> (** TODO remove that and choose what to do. ex: int real *) - let pexp = Egraph.mk_pexp d exp (SubstUpTrue (the,e1,e2,own)) in - Boolean.set_true d pexp own; + Boolean.set_true d own; true module ChoEquals = struct - open Conflict - - module OnWhat = ThE - - let key = Trail.Cho.create_key (module struct type t = ThE.t let name = "Equals.cho" end) - let make_decision the (cl1,cl2) d = - Debug.dprintf6 print_decision + Debug.dprintf6 Egraph.print_decision "[Equality] @[decide on merge of %a and %a in %a@]" Node.pp cl1 Node.pp cl2 ThE.pp the; - let pexp = Egraph.mk_pexp d exp (Dec(cl1,cl2)) in Egraph.register d cl1; Egraph.register d cl2; - Egraph.merge d pexp cl1 cl2 + Egraph.merge d cl1 cl2 - let choose_decision d the = + let choose_decision the d = let v = ThE.sem the in let own = ThE.node the in Debug.dprintf4 debug "[Equality] @[dec on %a for %a@]" Node.pp own ThE.pp the; if norm_set d the - then DecNo + then Egraph.DecNo else match find_not_disequal d v with - | `AllDiff al -> - let pexp = Egraph.mk_pexp d exp (SubstUpFalse(the,al)) in - Boolean.set_false d pexp own; + | `AllDiff _ -> + Boolean.set_false d own; DecNo | `Found (cl1,cl2) -> DecTodo (make_decision the (cl1,cl2)) -end + let mk_choice the = { + Egraph.choice = choose_decision the; + prio = 1; + } -let () = Conflict.register_cho(module ChoEquals) +end let norm_dom d the = let v = ThE.sem the in @@ -310,32 +288,25 @@ let norm_dom d the = Node.pp own Th.pp v; match Boolean.is d own with | Some false -> - let age = Trail.Age.succ (Egraph.current_age d) in - let dis, stag = new_tag the age in - let pexp = - Egraph.mk_pexp d exp (SubstDownFalse(the,dis)) in - Egraph.add_pexp d pexp; - Node.S.iter (fun cl -> set_dom d pexp cl (stag ())) v; + let _dis, stag = new_tag the in + Node.S.iter (fun cl -> set_dom d cl (stag ())) v; Demon.AliveStopped | Some true -> begin match Th.only_two v with | Some (cl1,cl2) -> - let pexp = Egraph.mk_pexp d exp (SubstDownTrue(the)) in - Egraph.merge d pexp cl1 cl2; Demon.AliveStopped + Egraph.merge d cl1 cl2; Demon.AliveStopped | None -> match find_not_disequal d v with - | `AllDiff al -> - let pexp = Egraph.mk_pexp d exp (SubstUpFalse(the,al)) in - Boolean.set_false d pexp own; (** contradiction *) + | `AllDiff _ -> + Boolean.set_false d own; (** contradiction *) raise Impossible | `Found _ -> Demon.AliveStopped end | None -> match find_not_disequal d v with - | `AllDiff al -> - let pexp = Egraph.mk_pexp d exp (SubstUpFalse(the,al)) in - Boolean.set_false d pexp own; + | `AllDiff _ -> + Boolean.set_false d own; Demon.AliveStopped | `Found _ -> (** they are still not proved disequal *) Demon.AliveReattached @@ -352,7 +323,7 @@ module DaemonPropa = struct let immediate = false let wakeup d v _ev () = - norm_dom d (ThE.index v Boolean.ty) + norm_dom d (ThE.index v) end @@ -388,7 +359,7 @@ module DaemonInit = struct if true (* GenEquality.dodec (Th.get_ty v) *) then begin Debug.dprintf4 debug "[Equality] @[ask_dec on %a for %a@]" Node.pp own Th.pp v; - Egraph.register_decision d (Trail.GCho(own,ChoEquals.key,clsem)); + Egraph.register_decision d (ChoEquals.mk_choice clsem) end | _ -> () end @@ -401,202 +372,6 @@ end module RDaemonInit = Demon.Key.Register(DaemonInit) - -(** conflict *) -module HypDis = struct - open Conflict - - type t = { - l1 : Node.t; - l0 : Node.t; - r0 : Node.t; - r1 : Node.t; - disequality : Node.t; - age : Trail.Age.t; - } - - let key = Trail.Hyp.create_key (module struct type nonrec t = t let name = "Diff" end) - - let pp fmt c = - Format.fprintf fmt "%a=%a≠%a=%a" - Node.pp c.l1 - Node.pp c.l0 - Node.pp c.r0 - Node.pp c.r1 - - let split t c cl1 cl2 = - if Equal.option Trail.Age.equal (Conflict.age_merge_opt t cl1 c.l1) None then - let cl1, cl2 = EqHyp.orient_split t {l=c.r0;r=c.r1} cl1 cl2 in - (Trail.Phyp.phyp key {c with r1 = cl1})::(EqHyp.create_eq cl2 c.r1) - else - let cl1, cl2 = EqHyp.orient_split t {l=c.l0;r=c.l1} cl1 cl2 in - (Trail.Phyp.phyp key {c with l1 = cl1})::(EqHyp.create_eq cl2 c.l1) - - - let useful_nodes c = - Bag.list [c.l1;c.l0;c.r1;c.r0] - - let levels t c = - let l = Levels.empty in - let l = Levels.add t (Conflict.age_merge t c.l1 c.l0) l in - let l = Levels.add t (Conflict.age_merge t c.r1 c.r0) l in - let l = Levels.add t c.age l in - l - - let apply_learnt c = - let n, par = EqHyp.apply_learnt {l=c.l1;r=c.r1} in - n, neg_parity par - - let create_diff_far t cl1 cl2 i age = - let find_origin v cl = - Node.S.fold_left (fun acc cl0 -> - match acc with - | Some _ -> acc - | None -> - match Conflict.age_merge_opt t cl cl0 with - | Some _ -> Some cl0 - | None -> None) None v - in - let the = Dis.to_node i in - let v = ThE.sem the in - let cl1_0 = Opt.get (find_origin v cl1) in - let cl2_0 = Opt.get (find_origin v cl2) in - let diff = Trail.Phyp.phyp key {l1=cl1;l0=cl1_0;r0=cl2_0;r1=cl2;disequality=ThE.node the; age} in - diff - - let create_diff_near t cl1 cl2 i age = - let find_origin v cl = - Node.S.fold_left (fun acc cl0 -> - match acc with - | Some _ -> acc - | None -> - match Conflict.age_merge_opt t cl cl0 with - | Some _ -> Some cl0 - | None -> None) None v - in - let the = Dis.to_node i in - let v = ThE.sem the in - let cl1_0 = Opt.get (find_origin v cl1) in - let cl2_0 = Opt.get (find_origin v cl2) in - let diff = Trail.Phyp.phyp key {l1=cl1_0;l0=cl1_0;r0=cl2_0;r1=cl2_0;disequality=ThE.node the; age} in - diff, (Trail.Phyp.phyp EqHyp.key {l=cl1_0;r=cl2_0}) - -end - -let () = Conflict.register_hyp(module HypDis) - -module Exp = struct - open Conflict - - type t = exp - - let pp fmt = function - | Merge (pexp,cl1,cl2,i,_) -> - Format.fprintf fmt "Merge!(%a,%a,%a,%a)" - pp_pexp pexp Node.pp cl1 Node.pp cl2 ThE.pp (Dis.to_node i) - | SubstUpTrue (v,e1,e2,cl) -> (** two are equals *) - Format.fprintf fmt "SubstUpTrue(%a,%a,%a,%a)" - ThE.pp v Node.pp e1 Node.pp e2 Node.pp cl - | SubstUpFalse (the,_) -> - Format.fprintf fmt "SubstUpFalse(%a)" ThE.pp the - | SubstDownTrue (the) -> - Format.fprintf fmt "SubstDownTrue(%a)" ThE.pp the - | SubstDownFalse (v,i) -> - Format.fprintf fmt "SubstDownFalse(%a,%a)" - ThE.pp v ThE.pp (Dis.to_node i) - | Dec (n1,n2) -> - Format.fprintf fmt "Dec(%a,%a)" - Node.pp n1 Node.pp n2 - - let analyse t e phyp = - match e with - | SubstUpTrue (v,e1,e2,_) -> (** two are equals *) - let own = ThE.node v in - let lhyp = Conflict.split t phyp own Boolean._true in - let phyp = Trail.Phyp.phyp EqHyp.key {l=e1;r=e2} in - phyp::lhyp - | SubstUpFalse (v,al) -> - let own = ThE.node v in - let lhyp = Conflict.split t phyp own Boolean._false in - let al = CCList.diagonal al in - let fold lhyp ((e1,(dis1,val1)),(e2,(dis2,val2))) = - let diff_value () = (** different values *) - let fold2_inter (type a) (k:a ValueKind.t) v1 v2 acc = - let (module V) = ValueKind.get k in - if not (V.equal v1 v2) then - (EqHyp.create_eq e1 (Node.index_value k v1 (Node.ty e1))) @ - (EqHyp.create_eq e2 (Node.index_value k v2 (Node.ty e2))) @ - acc - else acc - in - let lhyp' = MValues.fold2_inter {fold2_inter} val1 val2 lhyp in - assert (not (Equal.physical lhyp lhyp')); (** One is different *) - lhyp' - in - match dis1, dis2 with - | Some dis1, Some dis2 -> - let dis = Dis.inter dis1 dis2 in - if Dis.is_empty dis - then diff_value () - else - (** choose the oldest? *) - let d,age = Dis.choose dis in - let diff = HypDis.create_diff_far t e1 e2 d age in - diff::lhyp - | _ -> diff_value () - in - List.fold_left fold lhyp al - | SubstDownTrue (the) -> begin - let v = ThE.sem the in - match Node.S.elements v with - | [a;b] -> - let lhyp = Conflict.split t phyp a b in - (EqHyp.create_eq (ThE.node the) Boolean._true)@lhyp - | _ -> raise Impossible - end - | SubstDownFalse (the,_) -> - let Trail.Phyp.Phyp(hyp,c,_) = phyp in - let c = Hyp.Eq.coerce hyp HypDis.key c in - let lhyp = [] in - let lhyp = (EqHyp.create_eq c.l1 c.l0)@lhyp in - let lhyp = (EqHyp.create_eq c.r1 c.r0)@lhyp in - let lhyp = (EqHyp.create_eq (ThE.node the) Boolean._false)@lhyp in - lhyp - | Dec(n1,n2) -> - let lhyp = Conflict.split t phyp n1 n2 in - let eq = EqHyp.create_eq ~dec:() n1 n2 in - eq@lhyp - | Merge(pexp,cl1,cl2,i,age) -> - assert (Equal.physical pexp (Trail.pexp_fact)); - (** only for bool currently *) - let cl2' = if Node.equal cl2 Boolean._true then Boolean._false else Boolean._true in - let lhyp = Conflict.split t phyp cl1 cl2' in - let diff = HypDis.create_diff_far t cl1 cl2 i age in - diff::lhyp - - let key = exp - - let far_disequality = Debug.register_flag "far-disequality" - ~desc:"Instead of explaining conflict with distinct near the disequality, explain it far from it" - - let from_contradiction t = function - | Merge(pexp,cl1,cl2,i,age) -> - if Debug.test_flag far_disequality then - let lhyp = Conflict.analyse t pexp (Trail.Phyp.phyp EqHyp.key {l=cl1;r=cl2}) in - let diff = HypDis.create_diff_far t cl1 cl2 i age in - diff::lhyp - else - let diff, eq = HypDis.create_diff_near t cl1 cl2 i age in - let lhyp = Conflict.analyse t pexp eq in - diff::lhyp - | _ -> raise Impossible - -end - - -let () = Conflict.register_exp(module Exp) - - (** ITE *) type ite = {cond: Node.t; then_: Node.t; else_: Node.t} @@ -631,13 +406,7 @@ end module EITE = ThTermKind.Register(ITE) let ite cond then_ else_ = - let ty1 = Node.ty then_ in - let ty2 = Node.ty else_ in - assert (Ty.equal ty1 ty2); - Node.index_sem ITE.key { cond; then_; else_} ty1 - -let expite = - Trail.Exp.create_key (module struct type nonrec t = EITE.t * bool let name = "Ite.exp" end) + Node.index_sem ITE.key { cond; then_; else_} module DaemonPropaITE = struct let key = Demon.Fast.create "ITE.propa" @@ -648,9 +417,8 @@ module DaemonPropaITE = struct let v = EITE.sem the in let own = EITE.node the in let branch = if b then v.then_ else v.else_ in - let pexp = Egraph.mk_pexp d expite (the,b) in Egraph.register d branch; - Egraph.merge d pexp own branch + Egraph.merge d own branch let immediate = false let throttle = 100 @@ -687,12 +455,12 @@ module DaemonInitITE = struct | Some b -> DaemonPropaITE.simplify d clsem b | None -> - let clsem = EITE.index v (Node.ty own) in + let clsem = EITE.index v in assert (Node.equal (EITE.node clsem) own); Egraph.register d v.cond; Egraph.register d v.then_; Egraph.register d v.else_; - Egraph.register_decision d (Trail.GCho(v.cond,Boolean.chobool,v.cond)); + Egraph.register_decision d (Boolean.chobool v.cond); let events = [Demon.Create.EventValue(v.cond,Boolean.dom,clsem)] in Demon.Fast.attach d DaemonPropaITE.key events end @@ -702,31 +470,6 @@ end module RDaemonInitITE = Demon.Fast.Register(DaemonInitITE) -module ExpITE = struct - open Conflict - - type t = EITE.t * bool - let key = expite - - let pp fmt (ite,b) = - Format.fprintf fmt "(%a,%b)" EITE.pp ite b - - let analyse : - Conflict.t -> - (* Trail.age -> *) t -> Trail.Phyp.t -> Trail.Phyp.t list = - fun t (the,b) hyp -> - let v = EITE.sem the in - let own = EITE.node the in - let lhyp = Conflict.split t hyp own (if b then v.then_ else v.else_) in - let phyp = EqHyp.create_eq v.cond (if b then Boolean._true else Boolean._false) in - phyp@lhyp - - let from_contradiction _ _ = raise Impossible - -end - -let () = Conflict.register_exp(module ExpITE) - (** {2 Link between diff and values} *) (** If can't be a value it they share a diff tag, are different *) @@ -739,15 +482,13 @@ let iter_on_value_different (d:Egraph.t) (own:Node.t) = let dis = Opt.get_def Dis.empty (Egraph.get_dom d dom own) in - let iter elt age = + let iter elt = let iter n = if not (Egraph.is_equal d own n) then match Egraph.get_value d Val.key n with | None -> () | Some v -> - let pexp = - Egraph.mk_pexp d exp (Merge(Trail.pexp_fact,own,n,elt,age)) in - they_are_different pexp n v + they_are_different n v in Node.S.iter iter (ThE.sem (Dis.to_node elt)) in @@ -758,17 +499,15 @@ let init_diff_to_value (type a) (type b) ?(already_registered=([]: b list)) d0 ((module Val): (module Witan_core.ValueKind.Registered with type s = a and type t = b)) - ~(they_are_different:(Egraph.t -> Trail.Pexp.t -> Node.t -> a -> unit)) = + ~(they_are_different:(Egraph.t -> Node.t -> a -> unit)) = let propagate_diff d v = let own = Val.node v in let dis = Opt.get_def Dis.empty (Egraph.get_dom d dom own) in - let iter elt age = + let iter elt = let iter n = if not (Egraph.is_equal d own n) then - let pexp = - Egraph.mk_pexp d exp (Merge(Trail.pexp_fact,n,Val.node v,elt,age)) in - they_are_different d pexp n (Val.value v) + they_are_different d n (Val.value v) in Node.S.iter iter (ThE.sem (Dis.to_node elt)) in @@ -807,9 +546,9 @@ let init_diff_to_value (type a) (type b) let bool_init_diff_to_value d = init_diff_to_value d (module Boolean.BoolValue) - ~they_are_different:(fun d pexp n b -> - if not b then Boolean.set_true d pexp n - else Boolean.set_false d pexp n + ~they_are_different:(fun d n b -> + if not b then Boolean.set_true d n + else Boolean.set_false d n ) ~already_registered:[Boolean.value_true;Boolean.value_false] @@ -833,45 +572,46 @@ let () = Interp.Register.thterm ITE.key interp let () = - Interp.Register.id (fun id args -> - let open Term in - let is builtin = Term.Id.equal id builtin in - let (!>) n = Boolean.BoolValue.value (Boolean.BoolValue.coerce_nodevalue n) in + Interp.Register.id (fun interp t -> + let (!>) n = Boolean.BoolValue.value (Boolean.BoolValue.coerce_nodevalue (interp n)) in let (!<) b = Some (if b then Boolean.values_true else Boolean.values_false) in - match args with - | [a;b] when is equal_id || is equiv_id -> !< (Value.equal a b) - | [c;a;b] when is ite_id -> Some (if (!> c) then a else b) - | _ when is_distinct_id id -> begin + match t with + | { descr = Expr.App({builtin = Expr.Equal},[_],a::l); _ } -> + let a = interp a in + !< (List.for_all (fun t -> Value.equal a (interp t)) l) + | { descr = Expr.App({builtin = Expr.Equiv},[_],[a;b]); _ } -> + !< (Value.equal (interp a) (interp b)) + | { descr = Expr.App({builtin = Expr.Distinct},[_],args); _ } -> + begin try - let fold acc v = Value.S.add_new Exit v acc in + let fold acc v = Value.S.add_new Exit (interp v) acc in let _ = List.fold_left fold Value.S.empty args in Some Boolean.values_false with Exit -> Some Boolean.values_true end + | { descr = Expr.App({builtin = Expr.Ite},[_],[c;a;b]); _ } -> + Some (if (!> c) then interp a else interp b) | _ -> None ) -let converter d f l = +let converter d (t:Expr.Term.t) = let of_term t = let n = SynTerm.node_of_term t in Egraph.register d n; n in - let node = match f, l with - | f,(_::([_;_] as args)) when Term.equal f Term.equal_term || - Term.equal f Term.equiv_term -> - Some (equality (List.map of_term args)) - | f,(_::args) when Term.is_distinct_term f -> - Some (disequality (List.map of_term args)) - | f,[_;c;a;b] when Term.equal f Term.ite_term -> - Some (ite (of_term c) (of_term a) (of_term b)) - | _, _ -> None in - node - -let () = Conflict._equality := (fun a b -> equality [a;b]) - + match t with + | { descr = Expr.App({builtin = Expr.Equal},[_],l); _ } -> + Some (equality (List.map of_term l)) + | { descr = Expr.App({builtin = Expr.Equiv},[_],[a;b]); _ } -> + Some (equality [of_term a;of_term b]) + | { descr = Expr.App({builtin = Expr.Distinct},[_],args); _ } -> + Some (disequality (List.map of_term args)) + | { descr = Expr.App({builtin = Expr.Ite},[_],[c;a;b]); _ } -> + Some (ite (of_term c) (of_term a) (of_term b)) + | _ -> None let th_register env = RDaemonPropa.init env; diff --git a/src/theories/bool/equality.mli b/src/theories/bool/equality.mli index 84faf48a9ec89bec0cc3dff743f3bebbf202850b..1352f9a6d6e658735b09747ff1c85bbd4b060f3e 100644 --- a/src/theories/bool/equality.mli +++ b/src/theories/bool/equality.mli @@ -28,7 +28,7 @@ val ite : Node.t -> Node.t -> Node.t -> Node.t val iter_on_value_different: (module ValueKind.Registered with type s = 'a and type t = 'b) -> - they_are_different:(Trail.Pexp.t -> Node.t -> 'a -> unit) -> + they_are_different:(Node.t -> 'a -> unit) -> Egraph.t -> Node.t -> unit diff --git a/src/theories/bool/uninterp.ml b/src/theories/bool/uninterp.ml index 7b666cee81b652af1eb9625cf084638d23970415..d00c58666ff37fd4435d6f396bc8bed4dff9fd48 100644 --- a/src/theories/bool/uninterp.ml +++ b/src/theories/bool/uninterp.ml @@ -20,38 +20,26 @@ open Witan_popop_lib open Popop_stdlib -open Std open Witan_core let debug = Debug.register_info_flag ~desc:"for the uninterpreted function theory" "uninterp" -type t = App of Node.t * Node.t - -let sem = ThTermKind.create_key (module struct type nonrec t = t let name = "UF" end) - module Th = struct module T = struct - type r = t - type t = r - let equal n m = - match n, m with - | App (g1,f1), App(g2,f2) -> Node.equal g1 g2 && Node.equal f1 f2 - - let hash n = - match n with - | App(g,f) -> 3 * (Node.hash g) + 5 * (Node.hash f) - - let compare n m = - match n, m with - | App(g1,f1), App(g2,f2) -> - let c = Node.compare g1 g2 in - if c <> 0 then c - else Node.compare f1 f2 + let hash_fold_list = Base.hash_fold_list + type t = + | Fun of Expr.Term.Const.t * Expr.Ty.t list + | App of Node.t * Node.t + [@@ deriving eq, ord, hash] let pp fmt v = match v with + | Fun (t,tyl) -> + Format.fprintf fmt "%a[%a]" + Expr.Term.Const.pp t + (Pp.list Pp.colon Expr.Ty.pp) tyl | App (f,g) -> Format.fprintf fmt "(@[%a@],@,@[%a@])" Node.pp f Node.pp g @@ -60,24 +48,25 @@ module Th = struct include T include MkDatatype(T) - let key = sem + let key = ThTermKind.create_key (module struct type nonrec t = t let name = "UF" end) end +let sem = Th.key + let pp = Th.pp module ThE = ThTermKind.Register(Th) -let app f g ty = Node.index_sem sem (App(f,g)) ty +let app f g = Node.index_sem sem (App(f,g)) let appl f l = - let rec aux acc ty = function + let rec aux acc = function | [] -> acc | a::l -> - let _,ty = Term.extract_fun_ty ty in - aux (app acc a ty) ty l + aux (app acc a) l in - aux f (Node.ty f) l + aux f l (* let result_of_sort = Ty.H.create 20 * @@ -116,9 +105,6 @@ let appl f l = * (fun x1 x2 x3 x4 x5 -> app_fun f [x1;x2;x3;x4;x5]) *) -type expsubst = {from:ThE.t; to_:ThE.t} -let expsubst = Trail.Exp.create_key (module struct type t = expsubst let name = "Uninterp" end) - module DaemonPropa = struct type k = ThE.t let key = Demon.Key.create "Uninterp.DaemonPropa" @@ -142,14 +128,14 @@ module DaemonPropa = struct let immediate = true (** can be false *) let wakeup d (nodesem:k) _ev () = match ThE.sem nodesem with - | App(f,g) as v -> + | Th.Fun _ -> Demon.AliveStopped + | Th.App(f,g) as v -> Debug.dprintf4 debug "[Uninterp] @[wakeup own %a v:%a@]" Node.pp (ThE.node nodesem) Th.pp v; - let v' = App(Egraph.find d f, Egraph.find d g) in + let v' = Th.App(Egraph.find d f, Egraph.find d g) in assert (not (Th.equal v v')); - let nodesem' = ThE.index v' (ThE.ty nodesem) in - let pexp = Egraph.mk_pexp d expsubst {from=nodesem;to_=nodesem'} in - Egraph.set_thterm d pexp (ThE.node nodesem) (ThE.thterm nodesem'); + let nodesem' = ThE.index v' in + Egraph.set_thterm d (ThE.node nodesem) (ThE.thterm nodesem'); Demon.AliveRedirected nodesem' end @@ -173,18 +159,18 @@ module DaemonInit = struct let own = ThE.node nodesem in Debug.dprintf2 debug "[Uninterp] @[init %a@]" Th.pp v; if DaemonPropa.is_unborn d nodesem then - match v with - | App(f,g) -> - Egraph.register d f; Egraph.register d g; - let f' = Egraph.find d f in - let g' = Egraph.find d g in - if Node.equal f' f && Node.equal g' g then - DaemonPropa.attach d f g nodesem - else - let v' = App(f',g') in - let nodesem' = ThE.index v' (Node.ty own) in - let pexp = Egraph.mk_pexp d expsubst {from=nodesem;to_=nodesem'} in - Egraph.set_thterm d pexp own (ThE.thterm nodesem') + match v with + | Fun _ -> assert false (** TODO *) + | App(f,g) -> + Egraph.register d f; Egraph.register d g; + let f' = Egraph.find d f in + let g' = Egraph.find d g in + if Node.equal f' f && Node.equal g' g then + DaemonPropa.attach d f g nodesem + else + let v' = Th.App(f',g') in + let nodesem' = ThE.index v' in + Egraph.set_thterm d own (ThE.thterm nodesem') end | _ -> raise UnwaitedEvent ) ev; @@ -195,42 +181,15 @@ end module RDaemonInit = Demon.Key.Register(DaemonInit) -module ExpSubst = struct - open Conflict - - type t = expsubst - let key = expsubst - - let pp fmt c = - match ThE.sem c.from, ThE.sem c.to_ with - | App(f,g), App(f',g') -> - Format.fprintf fmt "Subst(%a,%a -> %a,%a)" - Node.pp f Node.pp g Node.pp f' Node.pp g' - - let analyse t {from;to_} phyp = - match ThE.sem from, ThE.sem to_ with - | App(f,g), App(f',g') -> - let lhyp = Conflict.split t phyp (ThE.node from) (ThE.node to_) in - let lhyp' = if Node.equal f f' then [] else EqHyp.create_eq f f' in - let lhyp'' = if Node.equal g g' then [] else EqHyp.create_eq g g' in - lhyp'@lhyp''@lhyp - - let from_contradiction _ _ = raise Impossible - -end - -let () = Conflict.register_exp(module ExpSubst) - - -let converter d f l = +let converter d (t:Term.t) = let of_term t = let n = SynTerm.node_of_term t in Egraph.register d n; n in - let node = match f with - | {Term.term=Id id} when not (Term.is_defined id) -> - let f = of_term f in + let node = match t with + | { descr = App({builtin = Dolmen_std.Expr.Base; _ } as f,tyl,((_::_) as l)); _ } -> + let f = ThE.node (ThE.index (Fun (f,tyl))) in let l = List.map of_term l in Some (appl f l) | _ -> None diff --git a/src/theories/bool/uninterp.mli b/src/theories/bool/uninterp.mli index ee1bd8152e2b3537d081cadfb1ecf873d3ccd6b7..92a2ddf1df0586f1b0317b1a46df6941b51a0453 100644 --- a/src/theories/bool/uninterp.mli +++ b/src/theories/bool/uninterp.mli @@ -20,10 +20,14 @@ open Witan_core -type t = App of Node.t * Node.t -val pp: t Format.printer +module Th: sig + type t = + | Fun of Expr.Term.Const.t * Expr.Ty.t list + | App of Node.t * Node.t + val pp: t Format.printer +end -val sem: t ThTermKind.t +val sem: Th.t ThTermKind.t (* val fun1 : * Ty.t -> string ->