@@ -36,34 +36,50 @@ module LR = Uf.LX
3636module Th = Shostak. Adt
3737module SLR = Set. Make (LR )
3838
39+ module TSet = Set. Make
40+ (struct
41+ type t = Uid .t
42+
43+ (* We use a dedicated total order on the constructors to ensure
44+ the termination of the model generation. *)
45+ let compare = Nest. compare
46+ end )
47+
3948let timer = Timers. M_Adt
4049
4150module Domain = struct
4251 (* Set of possible constructors. The explanation justifies that any value
4352 assigned to the semantic value has to use a constructor lying in the
4453 domain. *)
4554 type t = {
46- constrs : Uid.Set .t ;
55+ constrs : TSet .t ;
4756 ex : Ex .t ;
4857 }
4958
5059 exception Inconsistent of Ex. t
5160
61+ let [@ inline always] cardinal { constrs; _ } = TSet. cardinal constrs
62+
63+ let [@ inline always] choose { constrs; _ } =
64+ (* We choose the minimal element to ensure the termination of
65+ model generation. *)
66+ TSet. min_elt constrs
67+
5268 let [@ inline always] as_singleton { constrs; ex } =
53- if Uid.Set . cardinal constrs = 1 then
54- Some (Uid.Set . choose constrs, ex)
69+ if TSet . cardinal constrs = 1 then
70+ Some (TSet . choose constrs, ex)
5571 else
5672 None
5773
5874 let domain ~constrs ex =
59- if Uid.Set . is_empty constrs then
75+ if TSet . is_empty constrs then
6076 raise @@ Inconsistent ex
6177 else
6278 { constrs; ex }
6379
64- let [@ inline always] singleton ~ex c = { constrs = Uid.Set . singleton c; ex }
80+ let [@ inline always] singleton ~ex c = { constrs = TSet . singleton c; ex }
6581
66- let [@ inline always] subset d1 d2 = Uid.Set . subset d1.constrs d2.constrs
82+ let [@ inline always] subset d1 d2 = TSet . subset d1.constrs d2.constrs
6783
6884 let unknown ty =
6985 match ty with
@@ -73,31 +89,31 @@ module Domain = struct
7389 let constrs =
7490 List. fold_left
7591 (fun acc Ty. { constr; _ } ->
76- Uid.Set . add constr acc
77- ) Uid.Set . empty body
92+ TSet . add constr acc
93+ ) TSet . empty body
7894 in
79- assert (not @@ Uid.Set . is_empty constrs);
95+ assert (not @@ TSet . is_empty constrs);
8096 { constrs; ex = Ex. empty }
8197 | _ ->
8298 (* Only ADT values can have a domain. This case shouldn't happen since
8399 we check the type of semantic values in both [add] and [assume]. *)
84100 assert false
85101
86- let equal d1 d2 = Uid.Set . equal d1.constrs d2.constrs
102+ let equal d1 d2 = TSet . equal d1.constrs d2.constrs
87103
88104 let pp ppf d =
89105 Fmt. (braces @@
90- iter ~sep: comma Uid.Set . iter Uid. pp) ppf d.constrs;
106+ iter ~sep: comma TSet . iter Uid. pp) ppf d.constrs;
91107 if Options. (get_verbose () || get_unsat_core () ) then
92108 Fmt. pf ppf " %a" (Fmt. box Ex. print) d.ex
93109
94110 let intersect ~ex d1 d2 =
95- let constrs = Uid.Set . inter d1.constrs d2.constrs in
111+ let constrs = TSet . inter d1.constrs d2.constrs in
96112 let ex = ex |> Ex. union d1.ex |> Ex. union d2.ex in
97113 domain ~constrs ex
98114
99115 let remove ~ex c d =
100- let constrs = Uid.Set . remove c d.constrs in
116+ let constrs = TSet . remove c d.constrs in
101117 let ex = Ex. union ex d.ex in
102118 domain ~constrs ex
103119end
@@ -209,6 +225,8 @@ module Domains = struct
209225 ) t.changed acc
210226 in
211227 acc, { t with changed = SX. empty }
228+
229+ let fold f t = MX. fold f t.domains
212230end
213231
214232let calc_destructor d e uf =
@@ -327,7 +345,7 @@ let assume_th_elt t th_elt _ =
327345 This function alone isn't sufficient to produce a complete decision
328346 procedure for the ADT theory. For instance, let's assume we have three
329347 semantic values [r1], [r2] and [r3] whose the domain is `{C1, C2}`. It's
330- clear that `(distinct r1 r2 r3)` is unsatisfiable but we haven't enough
348+ clear that `(distinct r1 r2 r3)` is unsatisfiable but we have not enough
331349 information to discover this contradiction.
332350
333351 We plan to support model generation for ADT. As a by-product, we will got
@@ -566,45 +584,81 @@ let constr_of_destr ty d =
566584
567585exception Found of X. r * Uid. t
568586
569- (* Pick a delayed destructor application in [env.delayed]. Returns [None]
570- if there is no delayed destructor. *)
571- let pick_delayed_destructor env =
572- try
573- Rel_utils.Delayed. iter_delayed
574- (fun r sy _e ->
575- match sy with
576- | Sy. Destruct d ->
577- raise_notrace @@ Found (r, d)
578- | _ ->
579- ()
580- ) env.delayed;
581- None
582- with Found (r , d ) -> Some (r, d)
587+ let (let * ) = Option. bind
583588
584- (* Do a case-split by choosing a semantic value [r] and constructor [c]
589+ (* Do a cases-plit by choosing a semantic value [r] and constructor [c]
585590 for which there are delayed destructor applications and propagate the
586591 literal [(not (_ is c) r)]. *)
592+ let split_delayed_destructor env =
593+ if not @@ Options. get_enable_adts_cs () then
594+ None
595+ else
596+ try
597+ Rel_utils.Delayed. iter_delayed
598+ (fun r sy _e ->
599+ match sy with
600+ | Sy. Destruct destr -> raise_notrace @@ Found (r, destr)
601+ | _ -> ()
602+ ) env.delayed;
603+ None
604+ with Found (r , d ) ->
605+ let c = constr_of_destr (X. type_info r) d in
606+ Some (LR. mkv_builtin false (Sy. IsConstr c) [r])
607+
608+ (* Pick a constructor in a tracked domain with minimal cardinal.
609+ Returns [None] if there is no such constructor. *)
610+ let pick_best ds =
611+ let * _, r, c =
612+ Domains. fold
613+ (fun r d best ->
614+ let cd = Domain. cardinal d in
615+ match Th. embed r, best with
616+ | Constr _ , _ -> best
617+ | _ , Some (n , _ , _ ) when n < = cd -> best
618+ | _ ->
619+ let c = Domain. choose d in
620+ Some (cd, r, c)
621+ ) ds None
622+ in
623+ Some (r, c)
624+
625+ let split_best_domain ~for_model uf =
626+ if not for_model then
627+ None
628+ else
629+ let ds = Uf. (GlobalDomains. find (module Domains ) @@ domains uf) in
630+ let * r, c = pick_best ds in
631+ let _, cons = Option. get @@ build_constr_eq r c in
632+ (* In the current implementation of `X.make`, we produce
633+ a nonempty context only for interpreted semantic values
634+ of the `Arith` and `Records` theories. The semantic
635+ values `cons` never involves such values. *)
636+ let nr, ctx = X. make cons in
637+ assert (Lists. is_empty ctx);
638+ Some (LR. mkv_eq r nr)
639+
640+ let next_case_split ~for_model env uf =
641+ match split_delayed_destructor env with
642+ | Some _ as r -> r
643+ | None -> split_best_domain ~for_model uf
644+
587645let case_split env uf ~for_model =
588- if Options. get_disable_adts () || not (Options. get_enable_adts_cs() )
589- then
646+ if Options. get_disable_adts () then
590647 []
591648 else begin
592- assert (not for_model);
593- if Options. get_debug_adt () then
594- Debug. pp_domains " before cs"
595- (Uf.GlobalDomains. find (module Domains ) (Uf. domains uf));
596- match pick_delayed_destructor env with
597- | Some (r , d ) ->
598- if Options. get_debug_adt () then
649+ match next_case_split ~for_model env uf with
650+ | Some cs ->
651+ if Options. get_debug_adt () then begin
652+ Debug. pp_domains " before cs"
653+ (Uf.GlobalDomains. find (module Domains ) (Uf. domains uf));
599654 Printer. print_dbg ~flushed: false
600655 ~module_name: " Adt_rel" ~function_name: " case_split"
601- " found r = %a and d = %a@ " X. print r Uid. pp d;
602- (* CS on negative version would be better in general. *)
603- let c = constr_of_destr (X. type_info r) d in
604- let cs = LR. mkv_builtin false (Sy. IsConstr c) [r] in
605- [ cs, true , Th_util. CS (Th_util. Th_adt , two) ]
656+ " Assume %a" (Xliteral. print_view X. print) cs;
657+ end ;
658+ [ cs, true , Th_util. CS (Th_util. Th_adt , two)]
606659 | None ->
607- Debug. no_case_split () ;
660+ if Options. get_debug_adt () then
661+ Debug. no_case_split () ;
608662 []
609663 end
610664
0 commit comments