summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrian Campbell2019-02-20 09:55:19 +0000
committerBrian Campbell2019-02-28 17:16:10 +0000
commit2fd45fa939ddae7cdb31ee0495e622e6e6a6235f (patch)
treefd12b7886a866516bdd9927728428161b2359dc3 /src
parentfb362fcb5671b6f008794d0a7db31b1f2685e413 (diff)
Coq: some work on bool simplification
This introduces some simplification of informative booleans, but tries too hard to eliminate all of the existentials resulting in difficulties in and/or trees.
Diffstat (limited to 'src')
-rw-r--r--src/pretty_print_coq.ml213
1 files changed, 172 insertions, 41 deletions
diff --git a/src/pretty_print_coq.ml b/src/pretty_print_coq.ml
index 430eb40d..c4983597 100644
--- a/src/pretty_print_coq.ml
+++ b/src/pretty_print_coq.ml
@@ -350,6 +350,14 @@ match nc1, nc2 with
| _, NC_aux (NC_true,_) -> nc1
| _,_ -> nc_and nc1 nc2
+let nice_imp nc1 nc2 =
+match nc1, nc2 with
+| NC_aux (NC_true,_), _ -> nc2
+| _, NC_aux (NC_true,_) -> nc2
+| NC_aux (NC_false,l), _ -> NC_aux (NC_true,l)
+| _, NC_aux (NC_false,_) -> nc_not nc1
+| _,_ -> nc_or (nc_not nc1) nc2
+
let nice_iff nc1 nc2 =
match nc1, nc2 with
| NC_aux (NC_true,_), _ -> nc2
@@ -370,30 +378,151 @@ let doc_nc_fn id =
| "not" -> string "negb"
| s -> string s
-type ex_atom_bool = ExBool_simple | ExBool_val of bool | ExBool_complex
+let merge_bool_count = KBindings.union (fun _ m n -> Some (m+n))
-let non_trivial_ex_atom_bool l kopts nc atom_nc =
- let vars = KOptSet.union (kopts_of_constraint nc) (kopts_of_constraint atom_nc) in
- let exists = KOptSet.of_list kopts in
- if KOptSet.subset vars exists then
- let kenv = List.fold_left (fun kenv kopt -> KBindings.add (kopt_kid kopt) (unaux_kind (kopt_kind kopt)) kenv) KBindings.empty kopts in
- match Constraint.call_smt l kenv (nc_and nc atom_nc),
- Constraint.call_smt l kenv (nc_and nc (nc_not atom_nc)) with
- | Sat, Sat -> ExBool_simple
- | Sat, Unsat -> ExBool_val true
- | Unsat, Sat -> ExBool_val false
- | _ -> ExBool_complex
- else ExBool_complex
-
-type ex_kind = ExNone | ExBool | ExGeneral
+let rec count_bool_vars (NC_aux (nc,_)) =
+ let count_arg (A_aux (arg,_)) =
+ match arg with
+ | A_bool nc -> count_bool_vars nc
+ | A_nexp _ | A_typ _ | A_order _ -> KBindings.empty
+ in
+ match nc with
+ | NC_or (nc1,nc2)
+ | NC_and (nc1,nc2)
+ -> merge_bool_count (count_bool_vars nc1) (count_bool_vars nc2)
+ | NC_var kid -> KBindings.singleton kid 1
+ | NC_equal _ | NC_bounded_ge _ | NC_bounded_le _ | NC_not_equal _
+ | NC_set _ | NC_true | NC_false
+ -> KBindings.empty
+ | NC_app (_,args) ->
+ List.fold_left merge_bool_count KBindings.empty (List.map count_arg args)
+
+type prop_dir = Implied_by | Implies | Iff
+
+type atom_bool_prop =
+ Bool_boring
+| Bool_complex of prop_dir * kinded_id list * n_constraint * n_constraint
+
+let simplify_atom_bool l kopts nc atom_nc =
+prerr_endline ("simplify " ^ string_of_n_constraint nc ^ " for bool " ^ string_of_n_constraint atom_nc);
+ let counter = ref 0 in
+ let is_bound kid = List.exists (fun kopt -> Kid.compare kid (kopt_kid kopt) == 0) kopts in
+ let bool_vars = merge_bool_count (count_bool_vars nc) (count_bool_vars atom_nc) in
+ let lin_bool_vars = KBindings.filter (fun kid n -> is_bound kid && n = 1) bool_vars in
+ let rec simplify (NC_aux (nc,l) as nc_full) =
+ let is_ex_var news (NC_aux (nc,_)) =
+ match nc with
+ | NC_var kid when KBindings.mem kid lin_bool_vars -> Some kid
+ | NC_var kid when KidSet.mem kid news -> Some kid
+ | _ -> None
+ in
+ let replace kills vars =
+ let v = mk_kid ("simp#" ^ string_of_int !counter) in
+ let kills = KidSet.union kills (KidSet.of_list vars) in
+ counter := !counter + 1;
+ KidSet.singleton v, kills, NC_aux (NC_var v,l)
+ in
+ match nc with
+ | NC_or (nc1,nc2) -> begin
+ let new1, kill1, nc1 = simplify nc1 in
+ let new2, kill2, nc2 = simplify nc2 in
+ let news, kills = KidSet.union new1 new2, KidSet.union kill1 kill2 in
+ match is_ex_var news nc1, is_ex_var news nc2 with
+ | Some kid1, Some kid2 -> replace kills [kid1;kid2]
+ | _ -> news, kills, NC_aux (NC_or (nc1,nc2),l)
+ end
+ | NC_and (nc1,nc2) -> begin
+ let new1, kill1, nc1 = simplify nc1 in
+ let new2, kill2, nc2 = simplify nc2 in
+ let news, kills = KidSet.union new1 new2, KidSet.union kill1 kill2 in
+ match is_ex_var news nc1, is_ex_var news nc2 with
+ | Some kid1, Some kid2 -> replace kills [kid1;kid2]
+ | _ -> news, kills, NC_aux (NC_and (nc1,nc2),l)
+ end
+ | NC_app (Id_aux (Id "not",_) as id,[A_aux (A_bool nc1,al)]) -> begin
+ let new1, kill1, nc1 = simplify nc1 in
+ match is_ex_var new1 nc1 with
+ | Some kid -> replace kill1 [kid]
+ | None -> new1, kill1, NC_aux (NC_app (id,[A_aux (A_bool nc1,al)]),l)
+ end
+ (* We don't currently recurse into general uses of NC_app, but the
+ "boring" cases we really want to get rid of won't contain
+ those. *)
+ | _ -> KidSet.empty, KidSet.empty, nc_full
+ in
+ let new_nc, kill_nc, nc = simplify nc in
+ let new_atom, kill_atom, atom_nc = simplify atom_nc in
+ let new_kids = KidSet.union new_nc new_atom in
+ let kill_kids = KidSet.union kill_nc kill_atom in
+ let rec strip_implied (NC_aux (nc,l) as nc_full) =
+ match nc with
+ | NC_var kid when KBindings.mem kid lin_bool_vars -> None
+ | NC_var kid when KidSet.mem kid new_kids -> None
+ | NC_and (nc1,nc2) -> begin
+ match strip_implied nc1, strip_implied nc2 with
+ | Some nc1, Some nc2 -> Some (NC_aux (NC_and (nc1,nc2),l))
+ | Some nc, None
+ | None, Some nc -> Some nc
+ | None, None -> None
+ end
+ | NC_or (nc1,nc2) -> begin
+ match strip_implied nc1, strip_implied nc2 with
+ | Some nc1, Some nc2 -> Some (NC_aux (NC_or (nc1,nc2),l))
+ | _ -> None
+ end
+ | _ -> Some nc_full
+ in
+ let rec strip_implies (NC_aux (nc,l) as nc_full) =
+ match nc with
+ | NC_var kid when KBindings.mem kid lin_bool_vars -> None
+ | NC_var kid when KidSet.mem kid new_kids -> None
+ | NC_and (nc1,nc2) -> begin
+ match strip_implied nc1, strip_implied nc2 with
+ | Some nc1, Some nc2 -> Some (NC_aux (NC_and (nc1,nc2),l))
+ | _ -> None
+ end
+ | NC_or (nc1,nc2) -> begin
+ match strip_implied nc1, strip_implied nc2 with
+ | Some nc1, Some nc2 -> Some (NC_aux (NC_or (nc1,nc2),l))
+ | Some nc, None
+ | None, Some nc -> Some nc
+ | None, None -> None
+ end
+ | _ -> Some nc_full
+ in
+ let strip_implied (NC_aux (_,l) as nc) =
+ Util.option_default (NC_aux (NC_true,l)) (strip_implied nc)
+ in
+ let strip_implies (NC_aux (_,l) as nc) =
+ Util.option_default (NC_aux (NC_true,l)) (strip_implies nc)
+ in
+ let kopts =
+ List.map (fun kid -> mk_kopt K_bool kid) (KidSet.elements new_kids) @
+ List.filter (fun kopt -> not (KidSet.mem (kopt_kid kopt) kill_kids)) kopts
+ in
+prerr_endline ("now have " ^ string_of_n_constraint nc ^ " for bool " ^ string_of_n_constraint atom_nc);
+ match atom_nc with
+ | NC_aux (NC_var kid,_) when KBindings.mem kid lin_bool_vars -> Bool_boring
+ | NC_aux (NC_var kid,_) when KidSet.mem kid new_kids -> Bool_boring
+ | NC_aux (NC_and (NC_aux (NC_var kid,_),nc'),_) when KBindings.mem kid lin_bool_vars ->
+ Bool_complex (Implies, kopts, nc, strip_implied nc')
+ | NC_aux (NC_and (nc',NC_aux (NC_var kid,_)),_) when KBindings.mem kid lin_bool_vars ->
+ Bool_complex (Implies, kopts, nc, strip_implied nc')
+ | NC_aux (NC_or (NC_aux (NC_var kid,_),nc'),_) when KBindings.mem kid lin_bool_vars ->
+ Bool_complex (Implied_by, kopts, nc, strip_implies nc')
+ | NC_aux (NC_or (nc',NC_aux (NC_var kid,_)),_) when KBindings.mem kid lin_bool_vars ->
+ Bool_complex (Implied_by, kopts, nc, strip_implies nc')
+ | _ -> Bool_complex (Iff, kopts, nc, atom_nc)
+
+
+type ex_kind = ExNone | ExGeneral
let classify_ex_type (Typ_aux (t,l) as t0) =
match t with
| Typ_exist (kopts,nc,(Typ_aux (Typ_app (Id_aux (Id "atom_bool",_), [A_aux (A_bool atom_nc,_)]),_) as t1)) -> begin
- match non_trivial_ex_atom_bool l kopts nc atom_nc with
- | ExBool_simple -> ExNone, t1
- | ExBool_val _ -> ExBool, t1
- | ExBool_complex -> ExGeneral, t1
+ match simplify_atom_bool l kopts nc atom_nc with
+ | Bool_boring -> ExNone, t1
+ | Bool_complex _ -> ExGeneral, t1
end
| Typ_exist (_,_,t1) -> ExGeneral,t1
| _ -> ExNone,t0
@@ -505,12 +634,15 @@ let rec doc_typ_fns ctx =
ampersand;
doc_arithfact ctx ~exists:(List.map kopt_kid kopts) ?extra:length_constraint_pp nc])
| Typ_aux (Typ_app (Id_aux (Id "atom_bool",_), [A_aux (A_bool atom_nc,_)]),_) -> begin
- match non_trivial_ex_atom_bool l kopts nc atom_nc with
- | ExBool_simple -> string "bool"
- | ExBool_val t -> string "Bool(" ^^ if t then string "True)" else string "False)"
- | ExBool_complex ->
+ match simplify_atom_bool l kopts nc atom_nc with
+ | Bool_boring -> string "bool"
+ | Bool_complex (dir,kopts,nc,atom_nc) ->
let var = mk_kid "_bool" in (* TODO collision avoid *)
- let nc = nice_and (nice_iff (nc_var var) atom_nc) nc in
+ let nc = nice_and
+ (match dir with
+ | Implies -> nice_imp (nc_var var) atom_nc
+ | Implied_by -> nice_imp atom_nc (nc_var var)
+ | Iff -> nice_iff (nc_var var) atom_nc) nc in
braces (separate space
[doc_var ctx var; colon; string "bool";
ampersand;
@@ -816,9 +948,9 @@ let is_ctor env id = match Env.lookup_id id env with
let is_auto_decomposed_exist env typ =
let typ = expand_range_type typ in
- match destruct_exist_plain (Env.expand_synonyms env typ) with
- | Some (_, _, typ') -> Some typ'
- | _ -> None
+ match classify_ex_type (Env.expand_synonyms env typ) with
+ | ExGeneral, typ' -> Some typ'
+ | ExNone, _ -> None
(*Note: vector concatenation, literal vectors, indexed vectors, and record should
be removed prior to pp. The latter two have never yet been seen
@@ -828,6 +960,7 @@ let rec doc_pat ctxt apat_needed exists_as_pairs (P_aux (p,(l,annot)) as pat, ty
let typ = Env.expand_synonyms env typ in
match exists_as_pairs, is_auto_decomposed_exist env typ with
| true, Some typ' ->
+prerr_endline ("decomposing for pattern " ^ string_of_pat pat ^ " at type " ^ string_of_typ typ ^ " with internal type " ^ string_of_typ typ');
let pat_pp = doc_pat ctxt true true (pat, typ') in
let pat_pp = separate space [string "existT"; underscore; pat_pp; underscore] in
if apat_needed then parens pat_pp else pat_pp
@@ -1068,10 +1201,9 @@ let doc_exp, doc_let =
match destruct_exist_plain typ with
| None -> epp
| Some (kopts,nc,Typ_aux (Typ_app (Id_aux (Id "atom_bool",_), [A_aux (A_bool atom_nc,_)]),l)) -> begin
- match non_trivial_ex_atom_bool l kopts nc atom_nc with
- | ExBool_simple -> epp
- | ExBool_val t -> wrap_parens (string "build_Bool" ^/^ epp)
- | ExBool_complex -> wrap_parens (string "build_ex" ^/^ epp)
+ match simplify_atom_bool l kopts nc atom_nc with
+ | Bool_boring -> epp
+ | Bool_complex _ -> wrap_parens (string "build_ex" ^/^ epp)
end
| Some _ ->
wrap_parens (string "build_ex" ^/^ epp)
@@ -1088,10 +1220,9 @@ let doc_exp, doc_let =
let build_ex, out_typ =
match destruct_exist_plain typ' with
| Some (kopts,nc,(Typ_aux (Typ_app (Id_aux (Id "atom_bool",_), [A_aux (A_bool atom_nc,_)]),l) as t)) -> begin
- match non_trivial_ex_atom_bool l kopts nc atom_nc with
- | ExBool_simple -> None, t
- | ExBool_val _ -> Some "build_Bool", t
- | ExBool_complex -> Some "build_ex", t
+ match simplify_atom_bool l kopts nc atom_nc with
+ | Bool_boring -> None, t
+ | Bool_complex _ -> Some "build_ex", t
end
| Some (_,_,t) -> Some "build_ex", t
| None -> None, typ'
@@ -1204,7 +1335,11 @@ let doc_exp, doc_let =
| Id_aux (Id "and_bool", _) | Id_aux (Id "or_bool", _)
when effectful (effect_of full_exp) ->
let call = doc_id (append_id f "M") in
- wrap_parens (hang 2 (flow (break 1) (call :: List.map expY args)))
+ let epp = hang 2 (flow (break 1) (call :: List.map expY args)) in
+ let epp = match is_auto_decomposed_exist (env_of full_exp) (typ_of full_exp) with
+ | Some _ -> string "build_ex" ^^ space ^^ parens epp
+ | None -> epp
+ in wrap_parens epp
(* temporary hack to make the loop body a function of the temporary variables *)
| Id_aux (Id "None", _) as none -> doc_id_ctor none
| Id_aux (Id "foreach#", _) ->
@@ -1574,7 +1709,6 @@ let doc_exp, doc_let =
| ExNone, ExNone -> epp
else match cast_ex with
| ExGeneral -> string "build_ex" ^^ space ^^ epp
- | ExBool -> string "build_Bool" ^^ space ^^ epp
| ExNone -> epp
in
let epp = epp ^/^ doc_tannot ctxt (env_of e) effects typ in
@@ -1582,11 +1716,9 @@ let doc_exp, doc_let =
if effects then
match cast_ex, outer_ex with
| ExGeneral, ExNone -> string "projT1_m" ^^ space ^^ parens epp
- | ExBool, ExNone -> string "projBool_m" ^^ space ^^ parens epp
| _ -> epp
else match cast_ex with
| ExGeneral -> string "projT1" ^^ space ^^ parens epp
- | ExBool -> string "projBool" ^^ space ^^ parens epp
| ExNone -> epp
in
let epp =
@@ -1759,7 +1891,7 @@ let doc_exp, doc_let =
let binder = match classify_ex_type (Env.expand_synonyms (env_of e1) full_typ) with
| ExGeneral, _ ->
squote ^^ parens (separate space [string "existT"; underscore; doc_id id; underscore; colon; doc_typ ctxt typ])
- | (ExBool | ExNone), _ ->
+ | ExNone, _ ->
parens (separate space [doc_id id; colon; doc_typ ctxt typ])
in separate space [string ">>= fun"; binder; bigarrow]
| _ ->
@@ -2244,7 +2376,6 @@ let doc_funcl mutrec rec_opt (FCL_aux(FCL_Funcl(id, pexp), annot)) =
let build_ex, ret_typ = replace_atom_return_type ret_typ in
let build_ex = match classify_ex_type (Env.expand_synonyms env (expand_range_type ret_typ)) with
| ExGeneral, _ -> Some "build_ex"
- | ExBool, _ -> Some "build_Bool"
| ExNone, _ -> build_ex
in
let ids_to_avoid = all_ids pexp in