-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsign.ml
313 lines (280 loc) · 9.29 KB
/
sign.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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
open Type;;
let opposite_comp (comp: comp) :comp = match comp with
| Eq -> Ne
| Ne -> Eq
| Lt -> Ge
| Le -> Gt
| Gt -> Le
| Ge -> Lt
let merge_env m1 m2 =
VarEnv.merge (fun key x y ->
match x,y with
| Some a, None -> Some a
| None, Some b -> Some b
| Some a, Some b ->
begin
let rec aux acc org =
match org with
| [] -> acc@b
| hd :: tl -> if List.mem hd b then aux acc tl else aux (hd::acc) tl
in Some(aux [] a)
end
| None, None -> None)
m1 m2
let equal_contents a b =
List.sort compare a = List.sort compare b
let join (s1 : sign list) (s2 : sign list) : sign list =
let rec aux acc list = match list with
| [] -> acc
| hd :: tl -> if List.mem (hd) (acc) then aux acc tl else aux (hd :: acc) tl
in aux s1 s2
let print_sign (s: sign) = match s with
| Neg -> "-"
| Zero -> "0"
| Pos -> "+"
| Error -> "!"
let pure_print_sign_list l =
let rec aux acc rest = match rest with
| sign :: tl -> aux (acc ^ " " ^ print_sign sign) tl
| _ -> acc
in (aux "" l)
let print_sign_list (env: sign list VarEnv.t) =
let rec aux acc rest = match rest with
| sign :: tl -> aux (acc ^ " " ^ print_sign sign) tl
| _ -> acc
in
VarEnv.iter (fun x y -> print_string x; print_string " -> "; print_string (aux "" y); print_string "\n") env
let sign_int (num: int) : sign =
if num = 0 then Zero
else if num > 0 then Pos
else Neg
(* sign_expression ( Op (Add, Num 0, Num 5)) (Names.empty);; *)
(*
Positif + Positif = tout
Positif + negatif = tout
sign_expression (Op (Add, Num (-2), Num (2))) (Names.empty);;
*)
let opposite_sign (sign : sign) : sign =
match sign with
| Pos -> Neg
| Neg -> Pos
| _ -> sign
let sign_add (l: sign) (r: sign) : sign list =
(*
Pos + Pos = Pos
Neg + Neg = Neg
Any + Zero = Any
*)
match l,r with
| Zero, right -> [right]
| left, Zero -> [left]
| left, right when left = right -> [left]
| _, _ -> [Pos; Neg; Zero]
let sign_sub (l: sign) (r: sign) : sign list =
(*
A - B = A + (-B)
*)
sign_add (l) (opposite_sign r)
let sign_mul (l: sign) (r: sign) : sign list =
(*
A * B = 0 If A or B is Zero
Positive if same sign
Else negative
*)
match l,r with
| Zero, right -> [Zero]
| left, Zero -> [Zero]
| left, right when left = right -> [Pos]
| _, _ -> [Neg]
let sign_div (l: sign) (r: sign) : sign list =
(*
A * B = 0 If A is Zero
If B is Zero Error
Positive if same sign
Else negative
*)
match l,r with
| Zero, right -> [Zero]
| left, Zero -> [Error]
| left, right when left = right -> [Pos]
| _, _ -> [Neg]
let sign_mod (l: sign) (r: sign) : sign list =
(*
Mod is only applicable in these cases
*)
match l,r with
| Zero, Pos -> [Zero]
| Pos, Pos -> [Pos]
| _, _ -> [Error]
let all_pairs (l1 : sign list) (l2 : sign list) : sign list list =
(* print_sign_list l1;
print_string "\n";
print_sign_list l2;
print_string "\n END OF CALL \n"; *)
List.concat
(List.map
(fun a -> List.map (fun b -> [a;b]) l2)
l1)
let sign_operation (op:op) (l_expr: sign list) (r_expr: sign list): sign list =
let possibilities = all_pairs l_expr r_expr in
let rec aux acc list = match list with
| [] -> acc
| hd :: tl ->
let first = List.hd hd in
let second = List.nth hd 1 in
match op with
| Add -> aux (join (sign_add first second) acc) tl
| Sub -> aux (join (sign_sub first second) acc) tl
| Mul -> aux (join (sign_mul first second) acc) tl
| Div -> aux (join (sign_div first second) acc) tl
| Mod -> aux (join (sign_mod first second) acc) tl
in aux [] possibilities
let rec sign_expression (expr) (env: sign list VarEnv.t) : sign list = match expr with
| Num(int) -> [sign_int int]
| Var(x) -> VarEnv.find x env
| Op(op, l_expr, r_expr) ->
let left = (sign_expression l_expr env) in
let right = (sign_expression r_expr env) in
sign_operation op left right
(* Nom associé à une liste de signe *)
(* sign_condition (Num (10), Le, Num (-0)) (VarEnv.empty);; *)
let eq_possible (s1 : sign) (s2 : sign) : bool =
match s1, s2 with
| x, y when x = y -> true
| _, _ -> false
let ne_possible (s1 : sign) (s2 : sign) : bool =
match s1, s2 with
| x, y when x = y -> false
| _, _ -> true
let lt_possible (s1 : sign) (s2 : sign) : bool =
match s1, s2 with
| Zero, Zero -> false
| Pos, Neg -> false
| Pos, Zero -> false
| Zero, Neg -> false
| _, _ -> true
let le_possible (s1 : sign) (s2 : sign) : bool =
match s1, s2 with
| Pos, Neg -> false
| _, _ -> true
let gt_possible (s1 : sign) (s2 : sign) : bool =
match s1, s2 with
| Zero, Zero -> false
| Neg, Pos -> false
| Pos, Zero -> false
| Zero, Neg -> false
| _, _ -> true
let ge_possible (s1 : sign) (s2 : sign) : bool =
match s1, s2 with
| Neg, Pos -> false
| _, _ -> true
let cond_possible (cond: cond)(env: sign list VarEnv.t): bool =
let (l_expr, comp, r_expr) = cond in
let possibilities = all_pairs (sign_expression l_expr env) (sign_expression r_expr env) in
let rec aux list = match list with
| [] -> false
| hd :: tl ->
let first = List.hd hd in
let second = List.nth hd 1 in
match comp with
| Eq -> if(eq_possible first second) then true else aux tl
| Ne -> if(ne_possible first second) then true else aux tl
| Lt -> if(lt_possible first second) then true else aux tl
| Le -> if(le_possible first second) then true else aux tl
| Gt -> if(gt_possible first second) then true else aux tl
| Ge -> if(ge_possible first second) then true else aux tl
in aux possibilities
let rec sign_expression (expr) (env: sign list VarEnv.t) : sign list = match expr with
| Num(int) -> [sign_int int]
| Op(op, l_expr, r_expr) ->
let left = (sign_expression l_expr env) in
let right = (sign_expression r_expr env) in
sign_operation op left right
| Var(name) -> VarEnv.find name env
let rec sign_instr(instru: instr)(env: sign list VarEnv.t) =
begin
match instru with
| Set(name, expr) -> VarEnv.add (name) (sign_expression expr env) (env)
| Read(name) -> VarEnv.add (name) ([Neg;Zero;Pos]) (env)
| Print(expr) -> env
| While(cond, block) ->
let isPossible = cond_possible cond env in
if isPossible then sign_while (cond, block) env
else env
| If(cond, block_g, block_d) ->
let isPossible = cond_possible cond env in
if isPossible then sign_block block_g env
else sign_block block_d env
end
and sign_block (b: block)(env: sign list VarEnv.t): sign list VarEnv.t =
begin
match b with
| [] -> env
| ( _ , instr ) :: tl ->
let env' = sign_instr instr env in
sign_block tl env'
end
and sign_while (cond, block) (env: sign list VarEnv.t) : sign list VarEnv.t =
let propagate_var (c : cond) (e : sign list VarEnv.t) : sign list VarEnv.t =
(*
We are currently inside the while. The condition is verified.
We will propagate condition if it has a better accuracy than actual variable.
Only way we can actually say anything about the variable, is if the expression
is strictly negative, strictly positive, or zero.
*)
match c with
| Var(x), comp, expr -> (
let sign_expr = sign_expression expr e in
match sign_expr with
| [Pos] -> (
match comp with
| Eq -> VarEnv.add x [Pos] e
| Ne -> (* We check better accuracy *)
if List.length(VarEnv.find x e) > 2 then (VarEnv.add x [Zero; Neg] e) else e
| Lt -> e (* [Pos; Neg; Zero] doesn't help accuracy *)
| Le -> e
| Gt -> VarEnv.add x [Pos] e
| Ge -> VarEnv.add x [Pos] e
)
| [Neg] -> (
match comp with
| Eq -> VarEnv.add x [Neg] e
| Ne -> (* We check better accuracy *)
if List.length(VarEnv.find x e) > 2 then (VarEnv.add x [Zero; Pos] e) else e
| Lt -> VarEnv.add x [Neg] e
| Le -> VarEnv.add x [Neg] e
| Gt -> e (* [Pos; Neg; Zero] doesn't help accuracy *)
| Ge -> e
)
| [Zero] -> (
match comp with
| Eq -> VarEnv.add x [Zero] e
| Ne -> (* We check better accuracy *)
if List.length(VarEnv.find x e) > 2 then (VarEnv.add x [Pos; Neg] e) else e
| Lt -> VarEnv.add x [Neg] e (* [Pos; Neg; Zero] doesn't help accuracy *)
| Le -> VarEnv.add x [Zero; Neg] e
| Gt -> VarEnv.add x [Pos] e
| Ge -> VarEnv.add x [Pos; Zero] e
)
| _ -> e
)
| (_, _, _) -> e
in
let rec aux e =
print_string "Old State : \n";
print_sign_list e;
print_string "\n";
let propagated_env = propagate_var cond e in
let new_e = sign_block (block) (propagated_env) in
print_string "New State : \n";
print_sign_list new_e;
print_string "\n";
if (VarEnv.equal equal_contents (e) (merge_env e new_e))
then (
print_string "Propagating reverse condition : \n";
let (e1, comp, e2) = cond in
let op_cond = (e1, opposite_comp comp, e2) in
propagate_var (op_cond) (e)
)
else aux (merge_env e new_e)
in aux env