-
Notifications
You must be signed in to change notification settings - Fork 0
/
solve.ml
242 lines (211 loc) · 8.92 KB
/
solve.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
(*
* Copyright © 2009 The Regents of the University of California. All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
* FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION
* TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*)
(** This module implements a fixpoint solver *)
module BS = BNstats
module F = Format
module A = Ast
module Co = Constants
module P = A.Predicate
module E = A.Expression
module So = A.Sort
module Su = A.Subst
module Q = Qualifier
module Sy = A.Symbol
module SM = Sy.SMap
module C = FixConstraint
module Ci = Cindex
module PP = Prepass
module Cg = FixConfig
open Misc.Ops
let mydebug = false
type t = {
sri : Ci.t
; ws : C.wf list
; tt : Timer.t
(* Stats *)
; stat_refines : int ref
; stat_cfreqt : (int * bool, int) Hashtbl.t
}
module type SOLVER = sig
type soln
type bind
val create : bind Cg.cfg -> FixConstraint.soln option -> (t * soln)
val solve : t -> soln -> (soln * (FixConstraint.t list) * Counterexample.cex list)
val save : string -> t -> soln -> unit
val read : soln -> FixConstraint.soln
val min_read : soln -> FixConstraint.soln
val read_bind : soln -> Ast.Symbol.t -> bind
(* val meet : soln -> soln -> soln *)
end
module Make (Dom : Cg.DOMAIN) = struct
type soln = Dom.t
type bind = Dom.bind
let min_read = Dom.min_read
let read = Dom.read
let read_bind = Dom.read_bind
(* let meet = Dom.meet *)
(*************************************************************)
(********************* Stats *********************************)
(*************************************************************)
let hashtbl_incr_frequency t k =
let n = try Hashtbl.find t k with Not_found -> 0 in
Hashtbl.replace t k (n+1)
let hashtbl_print_frequency t =
Misc.hashtbl_to_list t
|> Misc.kgroupby (fun ((k,b),n) -> (n,b))
|> List.map (fun ((n,b), xs) -> (n, b, List.map (fst <+> fst) xs))
|> List.sort compare
|> List.iter begin fun (n, b, xs) ->
Co.logPrintf "ITERFREQ: %d times (ch = %b) %d constraints %s \n"
n b (List.length xs) (Misc.map_to_string string_of_int xs)
end
(***************************************************************)
(************************ Debugging/Stats **********************)
(***************************************************************)
let print_constr_stats ppf cs =
let cn = List.length cs in
let scn = List.length (List.filter C.is_simple cs) in
F.fprintf ppf "#Constraints: %d (simple = %d) \n" cn scn
let print_solver_stats ppf me =
print_constr_stats ppf (Ci.to_list me.sri);
F.fprintf ppf "#Iterations = %d\n" !(me.stat_refines);
F.fprintf ppf "Iteration Frequency: \n";
hashtbl_print_frequency me.stat_cfreqt;
F.fprintf ppf "Iteration Periods: @[%a@] \n" Timer.print me.tt
let dump me s =
Co.cLogPrintf Co.ol_solve_stats "%a \n" print_solver_stats me;
Co.cLogPrintf Co.ol_solve_stats "%a \n" Dom.print_stats s;
Dom.dump s
let log_iter_stats me s =
(if Co.ck_olev Co.ol_insane then Co.logPrintf "%a" Dom.print s);
(if !(me.stat_refines) mod 100 = 0 then
let msg = Printf.sprintf "num refines=%d" !(me.stat_refines) in
let _ = Timer.log_event me.tt (Some msg) in
let _ = Co.logPrintf "%s" msg in
let _ = Co.logPrintf "%a \n" Dom.print_stats s in
let _ = Format.print_flush () in
());
()
(***************************************************************)
(******************** Iterative Refinement *********************)
(***************************************************************)
let refine_constraint s c =
try BS.time "refine" (Dom.refine s) c with ex ->
let _ = F.printf "constraint refinement fails with: %s\n" (Printexc.to_string ex) in
let _ = F.printf "Failed on constraint:\n%a\n" (C.print_t None) c in
assert false
let rec acsolve me w s =
let _ = log_iter_stats me s in
match Ci.wpop me.sri w with
| (None,_) ->
let _ = Timer.log_event me.tt (Some "Finished") in
s
| (Some c, w') ->
let _ = me.stat_refines += 1 in
let (ch, s') = BS.time "refine" (refine_constraint s) c in
let _ = hashtbl_incr_frequency me.stat_cfreqt (C.id_of_t c, ch) in
let _ = Co.bprintf mydebug "iter=%d id=%d ch=%b %a \n"
!(me.stat_refines) (C.id_of_t c) ch C.print_tag (C.tag_of_t c) in
let w'' = if ch then Ci.deps me.sri c |> Ci.wpush me.sri w' else w' in
acsolve me w'' s'
let unsat_constraints me s =
me.sri |> Ci.to_list |> List.filter (Dom.unsat s)
(***************************************************************)
(****************** Pruning Unconstrained Vars *****************)
(***************************************************************)
let rhs_ks cs =
cs |> Misc.flap (Misc.compose C.kvars_of_reft C.rhs_of_t)
|> List.fold_left (fun rhss (_, kv) -> Sy.SSet.add kv rhss) Sy.SSet.empty
let unconstrained_kvars cs =
let rhss = rhs_ks cs in
cs |> Misc.flap C.kvars_of_t
|> List.map snd
|> List.filter (fun kv -> not (Sy.SSet.mem kv rhss))
let true_unconstrained sri s =
sri |> Ci.to_list
>> (fun _ -> Co.logPrintf "Fixpoint: true_unconstrained Step 2 \n")
|> unconstrained_kvars
>> (fun _ -> Co.logPrintf "Fixpoint: true_unconstrained Step 2 \n")
|> Dom.top s
>> (fun _ -> Co.logPrintf "Fixpoint: true_unconstrained Step 3 \n")
(*
let true_unconstrained sri s =
if !Co.true_unconstrained then
let _ = Co.logPrintf "Fixpoint: Pruning unconstrained kvars \n"
in true_unconstrained sri s
else
let _ = Co.logPrintf "Fixpoint: NOT Pruning unconstrained kvars \n"
in s
*)
(* API *)
let solve me s =
let _ = Co.logPrintf "Fixpoint: Validating Initial Solution \n" in
let _ = BS.time "Prepass.profile" PP.profile me.sri in
let _ = Co.logPrintf "Fixpoint: Trueing Unconstrained Variables \n" in
let s = s |> (!Co.true_unconstrained <?> BS.time "Prepass.true_unconstr" (true_unconstrained me.sri)) in
(* let _ = Co.cprintf Co.ol_insane "%a%a" Ci.print me.sri Dom.print s; dump me s in *)
let _ = Co.logPrintf "Fixpoint: Initialize Worklist \n" in
let w = BS.time "Cindex.winit" Ci.winit me.sri in
let _ = Co.logPrintf "Fixpoint: Refinement Loop \n" in
let s = BS.time "Solve.acsolve" (acsolve me w) s in
let _ = BS.time "Solve.dump" (dump me) s in
let _ = Co.logPrintf "Fixpoint: Testing Solution \n" in
let u = BS.time "Solve.unsatcs" (unsat_constraints me) s in
let _ = if u != [] then F.printf "Unsatisfied Constraints:\n %a" (Misc.pprint_many true "\n" (C.print_t None)) u in
let cx = if !Co.cex && Misc.nonnull u then Dom.ctr_examples s (Ci.to_list me.sri) u else [] in
(s, u, cx)
(* API *)
let create cfg kf =
let gts = SM.to_list cfg.Cg.uops in
let sri = cfg.Cg.cs
>> Co.logPrintf "Pre-Simplify Stats\n%a" print_constr_stats
|> BS.time "Constant Env" (List.map (C.add_consts_t gts))
|> BS.time "Simplify" FixSimplify.simplify_ts
>> Co.logPrintf "Post-Simplify Stats\n%a" print_constr_stats
|> BS.time "Ref Index" Ci.create cfg.Cg.ds
|> (!Co.slice <?> BS.time "Slice" Ci.slice) in
let ws = cfg.Cg.ws
|> (!Co.slice <?> BS.time "slice_wf" (Ci.slice_wf sri))
|> BS.time "Constant EnvWF" (List.map (C.add_consts_wf gts))
|> PP.validate_wfs in
let s = if !Constants.dump_simp <> "" then Dom.empty else Dom.create cfg kf in
let _ = print_now "DONE: Dom.create\n" in
let _ = Ci.to_list sri
|> BS.time "Validate" (PP.validate cfg.Cg.a (Dom.read s)) in
let _ = print_now "DONE: PP.validate \n" in
({ sri = sri
; ws = ws
(* stat *)
; tt = Timer.create "fixpoint iters"
; stat_refines = ref 0
; stat_cfreqt = Hashtbl.create 37
}, s)
>> (fun _ -> print_now "DONE: Solve.create\n")
(* API *)
let save fname me s =
let oc = open_out fname in
let ppf = F.formatter_of_out_channel oc in
F.fprintf ppf "@[%a@] \n" Ci.print me.sri;
F.fprintf ppf "@[%a@] \n" (Misc.pprint_many true "\n" (C.print_wf None)) me.ws;
F.fprintf ppf "@[%a@] \n" Dom.print s;
close_out oc
end