package lutin

  1. Overview
  2. Docs

Source file gne.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
(*-----------------------------------------------------------------------
** Copyright (C) - Verimag.
** This file may only be copied under the terms of the CeCill
** Public License
**-----------------------------------------------------------------------
**
** File: gne.ml
** Main author: erwan.jahier@univ-grenoble-alpes.fr
*)

(* ZZZ :

   Never use NeMap.add, but add_ne instead, otherwise the gne.t
   migth be incoherent !!!

   Indeed, I use a map to ease the search of common expression.
   Hence when adding a branch to a gne, I need to merge it 
   if the same expression exists !!
*)

module NeMap = struct
  include Map.Make(struct type t = Ne.t let compare = compare end)
end


(* exported *)	
type t = (Bdd.t * bool) NeMap.t
(* The flag is true iff the [Ne.t] depends on inputs or pre. *)

let (dump : t -> unit) =
  fun gne ->
    ignore (NeMap.fold
       (fun ne (bdd, _dep) acc ->
	       print_string ("\n\t" ^ (Ne.to_string ne) ^ "  -> ");
          flush stdout;
          Bdd.print_mons bdd;
          flush stdout;
          acc
       )
       gne
       ""
    );
    print_string "\n"

(* This one does not manipulate gne that are partitions !!  It just
   adds an element to the partition, merging common expressions if
   necessary.
*)
let (add_ne : Bdd.t -> bool -> Ne.t -> t -> t) =
  fun bdd dep ne gne -> 
	 try 
      let (bdd_gne, dep_gne) = NeMap.find ne gne in
        NeMap.add ne ((Bdd.dor bdd bdd_gne), dep || dep_gne) gne
	 with Not_found ->
		NeMap.add ne (bdd, dep) gne


(* Check that all bbds in gne forms a partition, which should always
   be the case !! *)
let (dyn_check_gne : t  -> bool) =
  fun gne -> 
    let bddl = NeMap.fold
	   (fun _ne (c,_dep) acc -> c::acc)
	   gne
	   []
    in
    let union_ok =
      let union = 
        List.fold_left
          (fun bdd acc -> Bdd.dor acc bdd)
          (Bdd.dfalse())
          bddl
      in
        Bdd.is_true union
    in
    let inter_ok =
      let inter_i_ok = Util.cartesian_product bddl bddl
        (fun x y -> x=y || (Bdd.is_false(Bdd.dand x y)))
      in
        List.fold_left
          (fun x acc -> x && acc)
          true
          inter_i_ok 
    in
      if NeMap.empty <> gne && not union_ok then (
        print_string "BAD GNE: the unions of guards is not equal to true!\n";
        dump gne;
        flush stdout
      );
      if not inter_ok then (
        print_string "BAD GNE: some guards have non-null intersection!\n";
        dump gne;
        flush stdout
      );
      (NeMap.empty = gne) || 
        (union_ok && inter_ok)

(****************************************************************************)


let (apply_op_gn_expr : (Ne.t -> Ne.t) -> t -> t) =
  fun op gne ->
    let res = 
    ( NeMap.fold
	     (fun ne (c,dep) acc -> 
           add_ne c dep (op ne) acc)
	     gne
	     NeMap.empty
    )
    in
      assert(dyn_check_gne res); 
      res


(* exported *)	
let (opposite : t -> t) =
  fun gne -> 
    let res = 
      apply_op_gn_expr (Ne.opposite) gne
    in
      assert(dyn_check_gne res); 
      res



(****************************************************************************)
let (apply_binop_gn_expr : (Ne.t -> Ne.t -> Ne.t) -> t -> t -> t) =
  fun op gne1 gne2 ->
    let res = 
      ( NeMap.fold
	       (fun ne1 (c1, dep1) acc1 ->
	          ( NeMap.fold
	              (fun ne2 (c2, dep2) acc2 ->
		              let c = (Bdd.dand c1 c2)
		              and dep = dep1 || dep2
		              in
		                if Bdd.is_false c
		                then acc2
	                   else
		                  let ne = op ne1 ne2 in
                          add_ne c dep ne acc2
	              )
	              gne2
	              acc1
	          )
	       )
	       gne1
	       NeMap.empty
      )
    in
      assert(dyn_check_gne res); 
      res



    (* exported *)	
let (add : t -> t -> t) =
  fun gne1 gne2 -> apply_binop_gn_expr (Ne.add) gne1 gne2

(* exported *)	
let (diff : t -> t -> t) =
  fun gne1 gne2 -> apply_binop_gn_expr (Ne.diff) gne1 gne2

(* exported *)	
let (mult : t -> t -> t) =
  fun gne1 gne2 -> apply_binop_gn_expr (Ne.mult) gne1 gne2

(* exported *)	
let (quot : t -> t -> t) =
  fun gne1 gne2 -> apply_binop_gn_expr (Ne.quot) gne1 gne2

(* exported *)	
let (modulo : t -> t -> t) =
  fun gne1 gne2 -> apply_binop_gn_expr (Ne.modulo) gne1 gne2

(* exported *)	
let (div : t -> t -> t) =
  fun gne1 gne2 -> apply_binop_gn_expr (Ne.div) gne1 gne2

(****************************************************************************)

(* exported *)	
let (empty : unit -> t) =
  fun _ ->
    NeMap.empty

(* exported *)	
let (make : Ne.t -> bool -> t) =
  fun  ne b ->
    let res = 
      (* it is ok to us NeMap.add instead of add_ne on an empty Gne.t *)
      NeMap.add ne (Bdd.dtrue (), b) NeMap.empty
    in
      res

(* exported *)	
let (fold : (Ne.t -> Bdd.t * bool -> 'acc -> 'acc) -> t -> 'acc -> 'acc) =
  fun f gne acc0 ->
    NeMap.fold f gne acc0

let (_find : Ne.t -> t -> Bdd.t * bool) =
  fun ne gne ->
    NeMap.find ne gne


(* exported *)	
let (of_ite : Bdd.t -> bool -> t -> t -> t) =
  fun bdd b gne_t gne_e ->
    let bdd_not = Bdd.dnot bdd in
    let gne = 
      if Bdd.is_true  bdd then gne_t else
      if Bdd.is_false bdd then gne_e else
        let gne =
          NeMap.fold
            (fun ne (g, dep) acc -> 
               let bdd = Bdd.dand g bdd in
                 if not (Bdd.is_false bdd) then 
                   add_ne bdd (dep||b) ne acc
                 else
                   acc
            )
            gne_t
            NeMap.empty
        in         
        let gne = 
          NeMap.fold
            (fun ne (g, dep) acc -> 
               let bdd = Bdd.dand g bdd_not in
                 if not (Bdd.is_false bdd) then 
                   add_ne bdd (dep||b) ne acc
                 else
                   acc
            )
            gne_e
            gne
        in
          gne
    in
      assert(dyn_check_gne gne); 
      gne
      
(* exported *)	
let (get_constant : t -> Value.num option) =
  fun gne ->
    match
      (NeMap.fold
	      (fun ne (bdd, _) acc -> (bdd, ne)::acc)
	      gne
	      []
      )
    with
	     [(bdd, ne)] ->
	       if
	         (Bdd.is_true bdd) && (Ne.is_a_constant ne)
	       then
	         Ne.find "" ne
	       else
	         None
      | _ -> None


(****************************************************************************)
(****************************************************************************)

(* exported *)	
let (to_string : t -> string) =
  fun gne ->
    (NeMap.fold
       (fun ne (_bdd, _dep) acc ->
	       ("\n\t" ^ (Ne.to_string ne) ^ "  -> << a bdd >>  ;" ^ acc ))
       gne
       "\n"
    )




OCaml

Innovation. Community. Security.