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
243
244
245
246
247
248
249
250
251
252
253
(** This file is an extension for the Abstract1 module from the apron Library.
It is not meant to be used as it is but through the instanciated modules
Abox, Apol and Aoct *)
open Apron
(** Abstract domain signature used by the following functor *)
module type ADomain = sig
(** Abstract element type *)
type t
(** Apron manager *)
val man: t Manager.t
end
(** functor that allows hiding the use of the manager, It also adds
few utilities to the Abstract1 module *)
module Make(D:ADomain) = struct
(** This functor implements all the constraint/generator based
operations over abstract elements. These are generic and stand
for Boxes, Octagons and Polyhedra. *)
(** Conventions :
- functions ending with _s allow to use/return string instead of variables
- functions ending with _f allow to use/return float instead of apron scalar
- functions ending with _fs mix the two
*)
module A = Abstract1
module G = Generatorext
module T = Tconsext
module L = Linconsext
module E = Environmentext
open A
type t = D.t A.t
let man = D.man
(** Set-theoritic operations *)
let bottom = bottom man
let top = top man
let join = join man
let meet = meet man
let widening = widening man
(** predicates *)
let is_bottom = is_bottom man
let is_top = is_top man
let is_leq = is_leq man
let is_eq = is_eq man
(** constraint satisfaction and filter *)
let sat_lincons = sat_lincons man
let sat_tcons = sat_tcons man
let filter_lincons abs l =
let ear = L.array_make abs.env 1 in
L.array_set ear 0 l;
meet_lincons_array man abs ear
let filter_tcons abs l =
let ear = T.array_make abs.env 1 in
T.array_set ear 0 l;
meet_tcons_array man abs ear
(** of and to constraints/generator *)
let to_lincons_array = to_lincons_array man
let to_tcons_array = to_tcons_array man
let to_generator_array = to_generator_array man
let to_lincons_list e = to_lincons_array e |> L.array_to_list
let to_tcons_list e = to_tcons_array e |> T.array_to_list
let to_generator_list e = to_generator_array e |> G.array_to_list
let of_generator_list (e : E.t) (g : Generator1.t list) =
let open Generator1 in
let _,lray = List.partition (fun g -> get_typ g = VERTEX) g in
let ofvertice v =
E.fold (fun acc var ->
let c = Texprext.cst e (get_coeff v var) in
assign_texpr man acc var c None
) (top e) e
in
let closed = join_array man (Array.of_list (List.map ofvertice g)) in
Generatorext.array_of_list lray |> add_ray_array man closed
let of_generator_array (e : E.t) g =
of_generator_list e (G.array_to_list g)
let of_lincons_array = of_lincons_array man
let of_tcons_array = of_tcons_array man
let of_lincons_list env l = of_lincons_array env (L.array_of_list l)
let of_tcons_list env l = of_tcons_array env (T.array_of_list l)
let of_box = of_box man
(** Environment and variable related operations *)
let get_environment a = env a
let change_environment a e = change_environment man a e false
let assign_texpr abs var texpr = assign_texpr man abs var texpr None
let assign_linexpr abs var linexpr = assign_linexpr man abs var linexpr None
let assign_f abs var f =
let texpr = Texprext.cst_f f |> Texprext.of_expr abs.env in
assign_texpr abs var texpr
let assign_fs abs var f = assign_f abs (Var.of_string var) f
let add_var abs typ v =
let e = env abs in
let ints,reals =
if typ = Environment.INT then [|v|],[||]
else [||],[|v|]
in
let env = Environment.add e ints reals in
A.change_environment man abs env false
let add_var_s abs typ v = add_var abs typ (Var.of_string v)
let bound_variable abs v = bound_variable man abs v
let bound_variable_f abs v =
let open Intervalext in
bound_variable abs v |> to_float
let bound_variable_s abs v = bound_variable abs (Var.of_string v)
let bound_variable_fs abs v = bound_variable_f abs (Var.of_string v)
let is_bounded_variable abs v = Intervalext.is_bounded (bound_variable abs v)
let is_bounded_s abs v = is_bounded_variable abs (Var.of_string v)
let is_bounded abs =
let env = env abs in
try
E.iter (fun v -> if is_bounded_variable abs v |> not then raise Exit) env;
true
with Exit -> false
(** Cross-domain conversion *)
let to_box abs =
let env = env abs in
let abs' = A.change_environment man abs env false in
to_tcons_array abs' |> A.of_tcons_array (Box.manager_alloc ()) env
let to_oct abs =
let env = env abs in
to_lincons_array abs |> A.of_lincons_array (Oct.manager_alloc ()) env
let to_poly abs =
let env = env abs in
let abs' = A.change_environment man abs env false in
to_tcons_array abs' |> A.of_tcons_array (Polka.manager_alloc_strict ()) env
(** Printing *)
let print fmt a =
let constraints = to_lincons_list a in
Format.fprintf fmt "{%a}"
(Format.pp_print_list ~pp_sep:(fun fmt () -> Format.fprintf fmt ";")
Linconsext.print) constraints
(** Projection on 2 dimensions *)
let proj2D abs v1 v2 =
let env = env abs in
let new_env = Environmentext.empty in
let new_env =
if Array.exists ((=) v1) (Environmentext.get_ints env) then
Environmentext.add_int v1 new_env
else Environmentext.add_real v1 new_env
in
let new_env =
if Array.exists ((=) v2) (Environmentext.get_ints env) then
Environmentext.add_int v2 new_env
else Environmentext.add_real v2 new_env
in
change_environment abs new_env
(** Projection on 3 dimensions *)
let proj3D abs v1 v2 v3 =
let env = env abs in
let new_env = Environmentext.empty in
let new_env =
if Array.exists ((=) v1) (Environmentext.get_ints env) then
Environmentext.add_int v1 new_env
else Environmentext.add_real v1 new_env
in
let new_env =
if Array.exists ((=) v2) (Environmentext.get_ints env) then
Environmentext.add_int v2 new_env
else Environmentext.add_real v2 new_env
in
let new_env =
if Array.exists ((=) v3) (Environmentext.get_ints env) then
Environmentext.add_int v3 new_env
else Environmentext.add_real v3 new_env
in change_environment abs new_env
(** Projection on 2 dimensions with string as variables *)
let proj2D_s abs v1 v2 =
proj2D abs (Apron.Var.of_string v1) (Apron.Var.of_string v2)
(** Projection on 3 dimensions with string as variables *)
let proj3D_s abs v1 v2 v3 =
proj3D abs (Apron.Var.of_string v1) (Apron.Var.of_string v2) (Apron.Var.of_string v3)
(** returns the vertices of an abstract element projected on 2 dimensions *)
let to_vertices2D abs v1 v2 =
let gen' = to_generator_array abs in
let get_coord l = Apron.Linexpr1.(get_coeff l v1, get_coeff l v2) in
Array.init
(Generatorext.array_length gen')
(fun i -> get_coord
(Generatorext.(get_linexpr1 (array_get gen' i))))
|> Array.to_list
|> List.rev_map (fun(a,b)-> (Coeffext.to_float a, Coeffext.to_float b))
(** returns the vertices of an abstract element projected on 2 dimensions *)
let to_vertices2D_s abs v1 v2 =
to_vertices2D abs (Apron.Var.of_string v1) (Apron.Var.of_string v2)
end