Newer
Older
(**************************************************************************)
(* *)
(* This file is part of WP plug-in of Frama-C. *)
(* *)
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
(* CEA (Commissariat a l'energie atomique et aux energies *)
(* 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). *)
(* *)
(**************************************************************************)
(* -------------------------------------------------------------------------- *)
(* --- Built-in Tactics --- *)
(* -------------------------------------------------------------------------- *)
open Lang
open Lang.F
let (^) a b =
if a="" then b else
if b="" then a else
Printf.sprintf "%s ; %s" a b
let t_id s = ["",s]
let t_absurd s = [ "Absurd" , (fst s,p_false) ]
let t_descr d0 p s = List.map (fun (d,s) -> (d0 ^ d) , s) (p s)
let t_finally d0 s = [ d0 , s ]
let t_chain (p : Tactical.process) (q : Tactical.process) s =
let pool = ref [] in
List.iter
(fun (d,s) ->
List.iter
(fun (d',s') ->
pool := (d ^ d' , s') :: !pool
) (q s)
) (p s) ;
List.rev !pool
let t_split ?(pos="") ?(neg="") p (hs,g) =
[ pos , (hs,p_imply p g) ; neg , (hs,p_imply (p_not p) g) ]
let t_cut ?(by="") (p : F.pred) (pi : Tactical.process) (hs,g) =
( by , (hs,p) ) :: (pi (hs,p_imply p g))
let t_case (p : F.pred) (a : Tactical.process) (b : Tactical.process) =
fun (hs,g) ->
List.append
(a (hs,F.p_imply p g))
(b (hs,F.p_imply (F.p_not p) g))
let t_cases ?(complete = "complete") (dps : (pred * Tactical.process) list) =
fun (hs,g) ->
let pool = ref [] in
List.iter
(fun (p,pi) ->
List.iter
(fun u -> pool := u :: !pool)
(pi (hs , p_imply p g))
) dps ;
( complete , (hs , p_any fst dps) ) :: List.rev !pool
let t_range e a b ~upper ~lower ~range s =
if (not (a <= b)) then raise (Invalid_argument "Wp.Auto.t_range") ;
let cases = ref [] in
for i = a to b do
cases := (Printf.sprintf "Value %d" i , p_equal e (e_int i)) :: !cases ;
done ;
List.concat [
upper (fst s , p_lt e (e_int a)) ;
lower (fst s , p_lt (e_int b) e) ;
t_chain (Tactical.insert !cases) range s ;
]
let t_replace ?(equal="equal") ~src ~tgt (pi : Tactical.process) s =
let s' =
Conditions.subst
(fun e -> if e == src then tgt else raise Not_found)
s
in
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
(equal , (fst s, p_equal src tgt)) :: (pi s')
(* -------------------------------------------------------------------------- *)
(* --- Built-in Strategies --- *)
(* -------------------------------------------------------------------------- *)
let array = TacArray.strategy
let choice = TacChoice.Choice.strategy
let absurd = TacChoice.Absurd.strategy
let contrapose = TacChoice.Contrapose.strategy
let compound = TacCompound.strategy
let cut = TacCut.strategy
let filter = TacFilter.strategy
let havoc = TacHavoc.Havoc.strategy
let separated = TacHavoc.Separated.strategy
let intuition = TacNormalForm.strategy
let range = TacRange.strategy
let split = TacSplit.strategy
let definition = TacUnfold.strategy
let instance = TacInstance.strategy
let lemma = TacLemma.strategy
(* -------------------------------------------------------------------------- *)
(* --- Auto-Range --- *)
(* -------------------------------------------------------------------------- *)
module Range =
struct
open Repr
let update merge x v ofs map =
match Repr.term v with
| Int v ->
let v0 = Integer.add v ofs in
let v1 = try merge v0 (Tmap.find x map) with Not_found -> v0 in
Tmap.add x v1 map
| _ -> map
type rg = {
mutable vmin : Integer.t F.Tmap.t ;
mutable vmax : Integer.t F.Tmap.t ;
}
let set_vmin rg x v ofs =
rg.vmin <- update Integer.max x v ofs rg.vmin
let set_vmax rg x v ofs =
rg.vmax <- update Integer.min x v ofs rg.vmax
let rec add_bound rg p =
match Repr.term p with
| And ps -> List.iter (add_bound rg) ps
| Lt(a,b) when Lang.F.is_int a && Lang.F.is_int b ->
set_vmax rg a b Integer.minus_one ;
set_vmin rg b a Integer.one ;
| Leq(a,b) when Lang.F.is_int a && Lang.F.is_int b ->
set_vmax rg a b Integer.zero ;
set_vmin rg b a Integer.zero ;
| _ -> ()
let compute hs =
let rg = { vmin = F.Tmap.empty ; vmax = F.Tmap.empty } in
Conditions.iter
(fun s ->
let open Conditions in
match s.condition with
| Have p | When p | Core p -> add_bound rg (F.e_prop p)
| _ -> ())
hs ;
rg
let ranges rg =
Tmap.interf
(fun _ a b ->
try Some(Integer.to_int_exn a,Integer.to_int_exn b)
) rg.vmin rg.vmax
let small = function
| None -> None
| Some z -> try Some(Integer.to_int_exn z) with Z.Overflow -> None
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
let bounds rg =
Tmap.merge
(fun _ a b -> Some(small a,small b))
rg.vmin rg.vmax
end
(* -------------------------------------------------------------------------- *)
(* --- Heuristics: Auto-Range --- *)
(* -------------------------------------------------------------------------- *)
class autorange =
object
method id = "wp:range"
method title = "Auto Range"
method descr = "Iterate over term constrained by a finite interval"
method search push (hyps,goal) =
let ranged = Range.ranges (Range.compute hyps) in
Tmap.iter
(fun e (a,b) ->
if Strategy.occurs_p e goal && b-a <= 1024 then
let selection = Tactical.(Inside(Goal goal,e)) in
push (range selection ~vmin:a ~vmax:b)
) ranged
end
let auto_range = Strategy.export (new autorange)
(* -------------------------------------------------------------------------- *)
(* --- Heuristics: Auto-Split --- *)
(* -------------------------------------------------------------------------- *)
class autosplit =
object(self)
method id = "wp:split"
method title = "Auto Split"
method descr = "Split on goal or any branch (priority to goal variables)"
method private search_goal push seq =
let goal = snd seq in
let is_split =
let open Qed.Logic in
match F.e_expr goal with
| And _ | If _ -> true
| Bind (Exists,_,phi) -> let rec is_split = function
| Bind (Exists,_,phi) -> is_split (F.repr (F.QED.lc_repr phi))
| And _ | Or _ | If _ | Imply _ -> true
| _ -> false
in is_split (F.repr (F.QED.lc_repr phi))
| Neq(x,y) | Eq(x,y) -> (F.is_prop x) && (F.is_prop y)
| _ -> false
in
if is_split then
let selection = Tactical.(Clause (Goal goal)) in
push (split ~priority:2.0 selection)
method private search_branch push seq =
let target = Lang.F.varsp (snd seq) in
Conditions.iter
(fun s ->
let open Lang in
let open Conditions in
match s.condition with
| Branch(_,sa,sb) ->
let priority =
if F.Vars.intersect target (Conditions.vars_hyp sa) ||
F.Vars.intersect target (Conditions.vars_hyp sb)
then 1.0 else 0.5 in
let selection = Tactical.(Clause(Step s)) in
push (split ~priority selection)
| _ -> ()
) (fst seq)
method search push seq =
self#search_goal push seq ;
self#search_branch push seq
end
let auto_split = Strategy.export (new autosplit)
(**************************************************************************)