Project

General

Profile

Download (42.9 KB) Statistics
| Branch: | Tag: | Revision:
1
open Lustre_types
2
open Utils
3
open Seal_utils			
4
open Zustre_data (* Access to Z3 context *)
5
   
6

    
7
(* Switched system extraction: expression are memoized *)
8
(*let expr_mem = Hashtbl.create 13*)
9
    
10
let add_init defs vid =
11
  Hashtbl.add defs vid [[], IsInit]
12

    
13

    
14
(**************************************************************)
15
(* Convert from Lustre expressions to Z3 expressions and back *)
16
(* All (free) variables have to be declared in the Z3 context *)
17
(**************************************************************)
18

    
19
let is_init_name = "__is_init"
20

    
21
let const_defs = Hashtbl.create 13
22
let is_const id = Hashtbl.mem const_defs id
23
let is_enum_const id = Hashtbl.mem Zustre_data.const_tags id  
24
let get_const id = Hashtbl.find const_defs id
25
                 
26
(* expressions are only basic constructs here, no more ite, tuples,
27
   arrows, fby, ... *)
28

    
29
(* Set of hash to support memoization *)
30
let expr_hash: (expr * Utils.tag) list ref = ref []
31
let ze_hash: (Z3.Expr.expr, Utils.tag) Hashtbl.t = Hashtbl.create 13
32
let e_hash: (Utils.tag, Z3.Expr.expr) Hashtbl.t = Hashtbl.create 13
33
let pp_hash pp_key pp_v fmt h = Hashtbl.iter (fun key v -> Format.fprintf fmt "%a -> %a@ " pp_key key pp_v v) h
34
let pp_e_map fmt = List.iter (fun (e,t) -> Format.fprintf fmt "%i -> %a@ " t Printers.pp_expr e) !expr_hash
35
let pp_ze_hash fmt = pp_hash
36
                      (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))
37
                      Format.pp_print_int
38
                      fmt
39
                      ze_hash
40
let pp_e_hash fmt = pp_hash
41
                      Format.pp_print_int
42
                      (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))
43
                      fmt
44
                      e_hash                              
45
let mem_expr e =
46
  (* Format.eprintf "Searching for %a in map: @[<v 0>%t@]"
47
   *   Printers.pp_expr e
48
   *   pp_e_map; *)
49
  let res = List.exists (fun (e',_) -> Corelang.is_eq_expr e e') !expr_hash in
50
  (* Format.eprintf "found?%b@." res; *)
51
  res
52
  
53
let mem_zexpr ze =
54
  Hashtbl.mem ze_hash ze
55
let get_zexpr e =
56
  let eref, uid = List.find (fun (e',_) -> Corelang.is_eq_expr e e') !expr_hash in
57
  (* Format.eprintf "found expr=%a id=%i@." Printers.pp_expr eref eref.expr_tag; *)
58
  Hashtbl.find e_hash uid
59
let get_expr ze =
60
  let uid = Hashtbl.find ze_hash ze in
61
  let e,_ = List.find (fun (e,t) -> t = uid) !expr_hash in
62
  e
63
  
64
let neg_ze z3e = Z3.Boolean.mk_not !ctx z3e 
65
let is_init_z3e =
66
  Z3.Expr.mk_const_s !ctx is_init_name  Zustre_common.bool_sort 
67

    
68
let get_zid (ze:Z3.Expr.expr) : Utils.tag = 
69
  try
70
    if Z3.Expr.equal ze is_init_z3e then -1 else
71
      if Z3.Expr.equal ze (neg_ze is_init_z3e) then -2 else
72
    Hashtbl.find ze_hash ze
73
  with _ -> (Format.eprintf "Looking for ze %s in Hash %a"
74
               (Z3.Expr.to_string ze)
75
               (fun fmt hash -> Hashtbl.iter (fun ze uid -> Format.fprintf fmt "%s -> %i@ " (Z3.Expr.to_string ze) uid) hash ) ze_hash;
76
             assert false)
77
let add_expr =
78
  let cpt = ref 0 in
79
  fun e ze ->
80
  incr cpt;
81
  let uid = !cpt in
82
  expr_hash := (e, uid)::!expr_hash;
83
  Hashtbl.add e_hash uid ze;
84
  Hashtbl.add ze_hash ze uid
85

    
86
  
87
let expr_to_z3_expr, zexpr_to_expr =
88
  (* List to store converted expression. *)
89
  (* let hash = ref [] in
90
   * let comp_expr e (e', _) = Corelang.is_eq_expr e e' in
91
   * let comp_zexpr ze (_, ze') = Z3.Expr.equal ze ze' in *)
92
  
93
  let rec e2ze e =
94
    if mem_expr e then (
95
      get_zexpr e
96
    )
97
    else (
98
      let res =
99
        match e.expr_desc with
100
        | Expr_const c ->
101
           let z3e = Zustre_common.horn_const_to_expr c in
102
           add_expr e z3e;
103
           z3e
104
        | Expr_ident id -> (
105
          if is_const id then (
106
            let c = get_const id in
107
            let z3e = Zustre_common.horn_const_to_expr c in
108
            add_expr e z3e;
109
            z3e
110
          )
111
          else if is_enum_const id then (
112
            let z3e = Zustre_common.horn_tag_to_expr id in
113
            add_expr e z3e;
114
            z3e
115
          )
116
          else (
117
            let fdecl_id = Zustre_common.get_fdecl id in
118
            let z3e = Z3.Expr.mk_const_f !ctx fdecl_id in
119
            add_expr e z3e;
120
            z3e
121
          )
122
        )
123
        | Expr_appl (id,args, None) (* no reset *) ->
124
           let z3e = Zustre_common.horn_basic_app id e2ze (Corelang.expr_list_of_expr args) in
125
           add_expr e z3e;
126
           z3e
127
        | Expr_tuple [e] ->
128
           let z3e = e2ze e in
129
           add_expr e z3e;
130
           z3e
131
        | _ -> ( match e.expr_desc with Expr_tuple _ -> Format.eprintf "tuple e2ze(%a)@.@?" Printers.pp_expr e
132
                                      | _ -> Format.eprintf "e2ze(%a)@.@?" Printers.pp_expr e)
133
             ; assert false
134
      in
135
      res
136
    )
137
  in
138
  let rec ze2e ze =
139
    let ze_name ze =
140
      let fd = Z3.Expr.get_func_decl ze in
141
      Z3.Symbol.to_string (Z3.FuncDecl.get_name fd)
142
    in
143
    if mem_zexpr ze then
144
      None, Some (get_expr ze)
145
    else
146
      let open Corelang in
147
      let fd = Z3.Expr.get_func_decl ze in
148
      let zel = Z3.Expr.get_args ze in
149
      match Z3.Symbol.to_string (Z3.FuncDecl.get_name fd), zel with
150
      (*      | var, [] -> (* should be in env *) get_e *)
151

    
152
      (* Extracting IsInit status *)
153
      | "not", [ze] when ze_name ze = is_init_name ->
154
         Some false, None
155
      | name, [] when name = is_init_name -> Some true, None
156
      (* Other constructs are converted to a lustre expression *)
157
      | op, _ -> (
158
        
159
        
160
        if Z3.Expr.is_numeral ze then
161
          let e =
162
            if Z3.Arithmetic.is_real ze then
163
              let num =  Num.num_of_ratio (Z3.Arithmetic.Real.get_ratio ze) in
164
              let s = Z3.Arithmetic.Real.numeral_to_string ze in
165
              mkexpr
166
                Location.dummy_loc
167
                (Expr_const
168
                   (Const_real
169
                      (num, 0, s)))
170
            else if Z3.Arithmetic.is_int ze then
171
              mkexpr
172
                Location.dummy_loc
173
                (Expr_const
174
                   (Const_int
175
                      (Big_int.int_of_big_int (Z3.Arithmetic.Integer.get_big_int ze))))
176
            else if Z3.Expr.is_const ze then
177
              match Z3.Expr.to_string ze with
178
              | "true" -> mkexpr Location.dummy_loc
179
                            (Expr_const (Const_tag (tag_true)))
180
              | "false" ->
181
                 mkexpr Location.dummy_loc
182
                   (Expr_const (Const_tag (tag_false)))
183
              | _ -> assert false
184
            else
185
              (
186
                Format.eprintf "Const err: %s %b@." (Z3.Expr.to_string ze) (Z3.Expr.is_const ze);
187
                assert false (* a numeral but no int nor real *)
188
              )
189
          in
190
          None, Some e
191
        else
192
          match op with
193
          | "not" | "=" | "-" | "*" | "/"
194
            | ">=" | "<=" | ">" | "<" 
195
            ->
196
             let args = List.map (fun ze -> Utils.desome (snd (ze2e ze))) zel in
197
             None, Some (mkpredef_call Location.dummy_loc op args)
198
          | "+" -> ( (* Special treatment of + for 2+ args *)
199
            let args = List.map (fun ze -> Utils.desome (snd (ze2e ze))) zel in
200
            let e = match args with
201
                [] -> assert false
202
              | [hd] -> hd
203
              | e1::e2::tl ->
204
                 let first_binary_and = mkpredef_call Location.dummy_loc op [e1;e2] in
205
                 if tl = [] then first_binary_and else
206
                   List.fold_left (fun e e_new ->
207
                       mkpredef_call Location.dummy_loc op [e;e_new]
208
                     ) first_binary_and tl
209
                 
210
            in
211
            None, Some e 
212
          )
213
          | "and" | "or" -> (
214
            (* Special case since it can contain is_init pred *)
215
            let args = List.map (fun ze -> ze2e ze) zel in
216
            let op = if op = "and" then "&&" else if op = "or" then "||" else assert false in 
217
            match args with
218
            | [] -> assert false
219
            | [hd] -> hd
220
            | hd::tl ->
221
               List.fold_left
222
                 (fun (is_init_opt1, expr_opt1) (is_init_opt2, expr_opt2) ->
223
                   (match is_init_opt1, is_init_opt2 with
224
                      None, x | x, None -> x
225
                      | Some _, Some _ -> assert false),
226
                   (match expr_opt1, expr_opt2 with
227
                    | None, x | x, None -> x
228
                    | Some e1, Some e2 ->
229
                       Some (mkpredef_call Location.dummy_loc op [e1; e2])
230
                 ))
231
                 hd tl 
232
          )
233
          | op -> 
234
             let args = List.map (fun ze ->  (snd (ze2e ze))) zel in
235
             Format.eprintf "deal with op %s (nb args: %i). Expr is %s@."  op (List.length args) (Z3.Expr.to_string ze); assert false
236
      )
237
  in
238
  (fun e -> e2ze e), (fun ze -> ze2e ze)
239

    
240
               
241
let zexpr_to_guard_list ze =
242
  let init_opt, expr_opt = zexpr_to_expr ze in
243
  (match init_opt with
244
   | None -> []
245
   |Some b -> [IsInit, b]
246
  ) @ (match expr_opt with
247
       | None -> []
248
       | Some e -> [Expr e, true]
249
      )
250
                
251
               
252
let simplify_neg_guard l =
253
  List.map (fun (g,posneg) ->
254
      match g with
255
      | IsInit -> g, posneg
256
      | Expr g ->
257
          if posneg then
258
            Expr (Corelang.push_negations g),
259
            true
260
          else
261
            (* Pushing the negation in the expression *)
262
            Expr(Corelang.push_negations ~neg:true g),
263
            true
264
    ) l 
265

    
266
(* TODO:
267
individuellement demander si g1 => g2. Si c'est le cas, on peut ne garder que g1 dans la liste
268
*)    
269
(*****************************************************************)
270
(* Checking sat(isfiability) of an expression and simplifying it *)
271
(* All (free) variables have to be declared in the Z3 context    *)
272
(*****************************************************************)
273
(*
274
let goal_simplify zl =
275
  let goal = Z3.Goal.mk_goal !ctx false false false in
276
  Z3.Goal.add goal zl;
277
  let goal' = Z3.Goal.simplify goal None in
278
  (* Format.eprintf "Goal before: %s@.Goal after : %s@.Sat? %s@."
279
   *   (Z3.Goal.to_string goal)
280
   *   (Z3.Goal.to_string goal')
281
   *   (Z3.Solver.string_of_status status_res) 
282
   * ; *)
283
  let ze = Z3.Goal.as_expr goal' in
284
  (* Format.eprintf "as an expr: %s@." (Z3.Expr.to_string ze); *)
285
  zexpr_to_guard_list ze
286
  *)
287
  
288
let implies =
289
  let ze_implies_hash : ((Utils.tag * Utils.tag), bool) Hashtbl.t  = Hashtbl.create 13 in
290
  fun ze1 ze2 ->
291
  let ze1_uid = get_zid ze1 in
292
  let ze2_uid = get_zid ze2 in
293
  if Hashtbl.mem ze_implies_hash (ze1_uid, ze2_uid) then
294
    Hashtbl.find ze_implies_hash (ze1_uid, ze2_uid)
295
  else
296
    begin
297
      if !seal_debug then (
298
        report ~level:6 (fun fmt -> Format.fprintf fmt "Checking implication: %s => %s?@ "
299
          (Z3.Expr.to_string ze1) (Z3.Expr.to_string ze2)
300
      )); 
301
      let solver = Z3.Solver.mk_simple_solver !ctx in
302
      let tgt = Z3.Boolean.mk_not !ctx (Z3.Boolean.mk_implies !ctx ze1 ze2) in
303
      let res =
304
        try
305
          let status_res = Z3.Solver.check solver [tgt] in
306
          match status_res with
307
          | Z3.Solver.UNSATISFIABLE -> if !seal_debug then
308
                                         report ~level:6 (fun fmt -> Format.fprintf fmt "Valid!@ "); 
309
             true
310
          | _ -> if !seal_debug then report ~level:6 (fun fmt -> Format.fprintf fmt "not proved valid@ "); 
311
             false
312
        with Zustre_common.UnknownFunction(id, msg) -> (
313
          report ~level:1 msg;
314
          false
315
        )
316
      in
317
      Hashtbl.add ze_implies_hash (ze1_uid,ze2_uid) res ;
318
      res
319
    end
320
                                               
321
let rec simplify zl =
322
  match zl with
323
  | [] | [_] -> zl
324
  | hd::tl -> (
325
    (* Forall e in tl, checking whether hd => e or e => hd, to keep hd
326
     in the first case and e in the second one *)
327
    let tl = simplify tl in
328
    let keep_hd, tl =
329
      List.fold_left (fun (keep_hd, accu) e ->
330
          if implies hd e then
331
            true, accu (* throwing away e *)
332
          else if implies e hd then
333
            false, e::accu (* throwing away hd *)
334
          else
335
            keep_hd, e::accu (* keeping both *)
336
        ) (true,[]) tl
337
    in
338
    (* Format.eprintf "keep_hd?%b hd=%s, tl=[%a]@."
339
     *   keep_hd
340
     *   (Z3.Expr.to_string hd)
341
     * (Utils.fprintf_list ~sep:"; " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) tl
342
     *   ; *)
343
    if keep_hd then
344
      hd::tl
345
    else
346
      tl
347
  )
348
  
349
let check_sat ?(just_check=false) (l: elem_boolexpr guard) : bool * (elem_boolexpr guard) =
350
  (* Syntactic simplification *)
351
  if false then
352
    Format.eprintf "Before simplify: %a@." (pp_guard_list pp_elem) l; 
353
  let l = simplify_neg_guard l in
354
  if false then (
355
    Format.eprintf "After simplify: %a@." (pp_guard_list pp_elem) l; 
356
    Format.eprintf "@[<v 2>Z3 check sat: [%a]@ " (pp_guard_list pp_elem)l;
357
  );
358
  let solver = Z3.Solver.mk_simple_solver !ctx in
359
  try (
360
    let zl =
361
      List.map (fun (e, posneg) ->
362
          let ze =
363
            match e with
364
            | IsInit -> is_init_z3e
365
            | Expr e -> expr_to_z3_expr e 
366
          in
367
          if posneg then
368
            ze
369
          else
370
            neg_ze ze
371
        ) l
372
    in
373
    if false then Format.eprintf "Z3 exprs1: [%a]@ " (fprintf_list ~sep:",@ " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) zl; 
374
    let zl = simplify zl in
375
        if false then Format.eprintf "Z3 exprs2: [%a]@ " (fprintf_list ~sep:",@ " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) zl; 
376
    let status_res = Z3.Solver.check solver zl in
377
     if false then Format.eprintf "Z3 status: %s@ @]@. " (Z3.Solver.string_of_status status_res); 
378
    match status_res with
379
    | Z3.Solver.UNSATISFIABLE -> false, []
380
    | _ -> (
381
      if false && just_check then
382
        true, l
383
      else
384
        (* TODO: may be reactivate but it may create new expressions *)
385
        (* let l = goal_simplify zl in *)
386
        let l = List.fold_left
387
                  (fun accu ze -> accu @ (zexpr_to_guard_list ze))
388
                  []
389
                  zl
390
        in
391
  (* Format.eprintf "@.@[<v 2>Check_Sat:@ before: %a@ after:
392
       %a@. Goal precise? %b/%b@]@.@. " * pp_guard_list l
393
       pp_guard_list l' * (Z3.Goal.is_precise goal) *
394
       (Z3.Goal.is_precise goal'); *)
395
  
396

    
397
        true, l
398
        
399
         
400
    )
401
         
402
  )
403
  with Zustre_common.UnknownFunction(id, msg) -> (
404
    report ~level:1 msg;
405
    true, l (* keeping everything. *)
406
  )
407
      
408
  
409

    
410

    
411
(**************************************************************)
412

    
413
  
414
let clean_sys sys =
415
  List.fold_left (fun accu (guards, updates) ->
416
      let sat, guards' =  check_sat (List.map (fun (g, pn) -> Expr g, pn) guards) in
417
      (*Format.eprintf "Guard: %a@.Guard cleaned: %a@.Sat? %b@."
418
        (fprintf_list ~sep:"@ " (pp_guard_expr Printers.pp_expr))  guards
419
        (fprintf_list ~sep:"@ " (pp_guard_expr Printers.pp_expr))  guards'
420
        sat
421

    
422
      ;*)
423
        if sat then
424
        (List.map (fun (e, b) -> (deelem e, b)) guards', updates)::accu
425
      else
426
        accu
427
    )
428
    [] sys
429

    
430
(* Most costly function: has the be efficiently implemented.  All
431
   registered guards are initially produced by the call to
432
   combine_guards. We csan normalize the guards to ease the
433
   comparisons.
434

    
435
   We assume that gl1 and gl2 are already both satisfiable and in a
436
   kind of reduced form. Let lshort and llong be the short and long
437
   list of gl1, gl2. We check whether each element elong of llong is
438
   satisfiable with lshort. If no, stop. If yes, we search to reduce
439
   the list. If elong => eshort_i, we can remove eshort_i from
440
   lshort. we can continue with this lshort shortened, lshort'; it is
441
   not necessary to add yet elong in lshort' since we already know
442
   rthat elong is somehow reduced with respect to other elements of
443
   llong. If eshort_i => elong, then we keep ehosrt_i in lshort and do
444
   not store elong.
445

    
446
   After iterating through llong, we have a shortened version of
447
   lshort + some elements of llong that have to be remembered. We add
448
   them to this new consolidated list. 
449

    
450
 *)
451

    
452
(* combine_guards ~fresh:Some(e,b) gl1 gl2 returns ok, gl with ok=true
453
   when (e=b) ang gl1 and gl2 is satisfiable and gl is a consilidated
454
   version of it.  *)
455
let combine_guards ?(fresh=None) gl1 gl2 =
456
  (* Filtering out trivial cases. More semantics ones would have to be
457
     addressed later *)
458
  let check_sat e = (* temp function before we clean the original one *)
459
    let ok, _ = check_sat e in
460
    ok
461
  in
462
  let implies (e1,pn1) (e2,pn2) =
463
    let e2z e pn =
464
      match e with
465
        | IsInit -> if pn then is_init_z3e else neg_ze is_init_z3e
466
        | Expr e -> expr_to_z3_expr (if pn then e else (Corelang.push_negations ~neg:true e))
467
      in
468
    implies (e2z e1 pn1) (e2z e2 pn2)
469
  in
470
  let lshort, llong =
471
    if List.length gl1 > List.length gl2 then gl2, gl1 else gl1, gl2
472
  in
473
  let merge long short =
474
    let short, long_sel, ok = 
475
    List.fold_left (fun (short,long_sel, ok) long_e ->
476
        if not ok then
477
          [],[], false (* Propagating unsat case *)
478
        else if check_sat (long_e::short) then
479
          let short, keep_long_e =
480
            List.fold_left (fun (accu_short, keep_long_e) eshort_i ->
481
                if not keep_long_e then (* shorten the algo *)
482
                  eshort_i :: accu_short, false
483
                else (* keep_long_e = true in the following *)
484
                  if implies eshort_i long_e then
485
                    (* First case is trying to remove long_e!
486

    
487
                     Since short is already normalized, we can remove
488
                     long_e. If later long_e is stronger than another
489
                     element of short, then necessarily eshort_i =>
490
                     long_e ->
491
                     that_other_element_of_short. Contradiction. *)
492
                    eshort_i::accu_short, false
493
                  else if implies long_e eshort_i then 
494
                    (* removing eshort_i, keeping long_e. *)
495
                    accu_short, true
496
                  else (* Not comparable, keeping both *)
497
                    eshort_i::accu_short, true
498
              )
499
              ([],true) (* Initially we assume that we will keep long_e *)
500
              short
501
          in
502
          if keep_long_e then
503
            short, long_e::long_sel, true
504
          else
505
            short, long_sel, true
506
        else
507
          [],[],false
508
      ) (short, [], true) long
509
    in
510
    ok, long_sel@short
511
  in
512
  let ok, l = match fresh with
513
    | None -> true, []
514
    | Some g -> merge [g] []
515
  in
516
  if not ok then
517
    false, []
518
  else
519
    let ok, lshort = merge lshort l in
520
    if not ok then
521
      false, []
522
    else
523
      merge llong lshort
524
    
525

    
526
(* Encode "If gel1=posneg then gel2":
527
   - Compute the combination of guarded exprs in gel1 and gel2:
528
     - Each guarded_expr in gel1 is transformed as a guard: the
529
       expression is associated to posneg.
530
     - Existing guards in gel2 are concatenated to that list of guards
531
     - We keep expr in the ge of gel2 as the legitimate expression 
532
 *)
533
let concatenate_ge gel1 posneg gel2 =
534
  let l, all_invalid =
535
    List.fold_left (
536
        fun (accu, all_invalid) (g2,e2) ->
537
        List.fold_left (
538
            fun (accu, all_invalid) (g1,e1) ->
539
            (* Format.eprintf "@[<v 2>Combining guards: (%a=%b) AND [%a] AND [%a]@ "
540
             *  pp_elem e1
541
             *  posneg
542
             *  pp_guard_list g1
543
             *  pp_guard_list g2; *)
544

    
545
            let ok, gl = combine_guards ~fresh:(Some(e1,posneg)) g1 g2 in
546
            (* Format.eprintf "@]@ Result is [%a]@ "
547
             *   pp_guard_list gl; *)
548

    
549
            if ok then
550
              (gl, e2)::accu, false
551
            else (
552
              accu, all_invalid
553
            )
554
          ) (accu, all_invalid) gel1
555
      ) ([], true) gel2
556
  in
557
  not all_invalid, l
558

    
559
(* Transform the guard expressions ge = [gl1, e1; gl2, e2;...] as
560
   [gl1, e1=id; gl2, e2=id; ...]  *)
561
let mk_ge_eq_id ge id =
562
  List.map
563
    (fun (gl, g_e) ->
564
      gl,
565
      if id = "true" then
566
        g_e
567
      else
568
        match g_e with
569
        | Expr g_e ->
570
           if id = "false" then
571
             Expr (Corelang.push_negations ~neg:true g_e)
572
           else  
573
             let loc = g_e.expr_loc in
574
             Expr(Corelang.mk_eq loc
575
                    g_e
576
                    (Corelang.expr_of_ident id loc))
577
        | _ -> assert false
578
    )  ge 
579

    
580
    (* Rewrite the expression expr, replacing any occurence of a variable
581
   by its definition.
582
     *)
583
let rec rewrite defs expr : elem_guarded_expr list =
584
  let rewrite = rewrite defs in
585
  let res =
586
    match expr.expr_desc with
587
    | Expr_appl (id, args, None) ->
588
       let args = rewrite args in
589
       List.map (fun (guards, e) ->
590
           guards,
591
           Expr (Corelang.mkexpr expr.expr_loc (Expr_appl(id, deelem e, None)))
592
         ) args 
593
    | Expr_const _  -> [[], Expr expr]
594
    | Expr_ident id ->
595
       if Hashtbl.mem defs id then
596
         Hashtbl.find defs id
597
       else
598
         (* id should be an input *)
599
         [[], Expr expr]
600
    | Expr_ite (g, e1, e2) ->
601
       let g = rewrite g and
602
           e1 = rewrite e1 and
603
           e2 = rewrite e2 in
604
       let ok_then, g_then = concatenate_ge g true e1 in
605
       let ok_else, g_else = concatenate_ge g false e2 in
606
       (if ok_then then g_then else [])@
607
         (if ok_else then g_else else [])
608
    | Expr_merge (g_id, branches) ->
609
       if Hashtbl.mem defs g_id then
610
         let g = Hashtbl.find defs g_id in
611
         (* Format.eprintf "Expr_merge %s = %a@." g_id (pp_mdefs pp_elem) g ; *)
612
         List.fold_left (fun accu (id, e) ->
613
             let g = mk_ge_eq_id g id in
614
             let e = rewrite e in
615
             let ok, g_eq_id = concatenate_ge g true e in
616
             if ok then g_eq_id@accu else accu
617
           ) [] branches
618
       else
619
         assert false (* g should be defined already *)
620
    | Expr_when (e, id, l) ->
621
       let e = rewrite e in
622
       let id_def = Hashtbl.find defs id in
623
       let clock = mk_ge_eq_id id_def l in
624
       let ok, new_ge = concatenate_ge clock true e in
625
       if ok then new_ge else []
626
    | Expr_arrow _ -> [[], IsInit] (* At this point the only arrow should be true -> false *)
627
    | Expr_tuple el ->
628
       (* Each expr is associated to its flatten guarded expr list *)
629
       let gell = List.map rewrite el in
630
       (* Computing all combinations: we obtain a list of guarded tuple *)
631
       let rec aux gell : (elem_boolexpr guard * expr list) list =
632
         match gell with
633
         | [] -> assert false (* Not happening *)
634
         | [gel] -> List.map (fun (g,e) -> g, [deelem e]) gel
635
         | gel::getl ->
636
            let getl = aux getl in
637
            List.fold_left (
638
                fun accu (g,e) ->
639
                List.fold_left (
640
                    fun accu (gl, minituple) ->
641
                    let is_compat, guard_comb = combine_guards g gl in
642
                    if is_compat then
643
                      let new_gt : elem_boolexpr guard * expr list = (guard_comb, (deelem e)::minituple) in
644
                      new_gt::accu
645
                    else
646
                      accu
647
                    
648
                  ) accu getl
649
              ) [] gel
650
       in
651
       let gtuples = aux gell in
652
       (* Rebuilding the valid type: guarded expr list (with tuple exprs) *)
653
       List.map
654
         (fun (g,tuple) -> g, Expr (Corelang.mkexpr expr.expr_loc (Expr_tuple tuple)))
655
         gtuples
656
    | Expr_fby _
657
      | Expr_appl _
658
                  (* Should be removed by mormalization and inlining *)
659
      -> Format.eprintf "Pb expr: %a@.@?" Printers.pp_expr expr; assert false
660
    | Expr_array _ | Expr_access _ | Expr_power _
661
                                                (* Arrays not handled here yet *)
662
      -> assert false
663
    | Expr_pre _ -> (* Not rewriting mem assign *)
664
       assert false
665
  in
666
  (* Format.eprintf "Rewriting %a as [@[<v 0>%a@]]@ "
667
   *   Printers.pp_expr expr
668
   *   (Utils.fprintf_list ~sep:"@ "
669
   *        pp_guard_expr) res; *)
670
  res
671
and add_def defs vid expr =
672
  (* Format.eprintf "Add_def: %s = %a@."
673
   *   vid
674
   *   Printers.pp_expr expr; *)
675
  let vid_defs = rewrite defs expr in
676
  (* Format.eprintf "-> @[<v 0>%a@]@."
677
   *   (Utils.fprintf_list ~sep:"@ "
678
   *      (pp_guard_expr pp_elem)) vid_defs;   *)
679
  (* Format.eprintf "Add_def: %s = %a@. -> @[<v 0>%a@]@."
680
   *     vid
681
   *     Printers.pp_expr expr
682
   *     (
683
   *       (Utils.fprintf_list ~sep:"@ "
684
   *          pp_guard_expr)) vid_defs;  *)
685
  Hashtbl.add defs vid vid_defs
686

    
687
(* Takes a list of guarded exprs (ge) and a guard
688
returns the same list of ge splited into the ones where the guard is true and the ones where it is false. In both lists the associated ge do not mention that guard anymore.
689

    
690
When a given ge doesn't mention positively or negatively such guards, it is duplicated in both lists *)
691
let split_mdefs elem (mdefs: elem_guarded_expr list) =
692
  List.fold_left (
693
      fun (selected, left_out)
694
          ((guards, expr) as ge) ->
695
      (* select the element of guards that match the argument elem *)
696
      let sel, others_guards = List.partition (select_elem elem) guards in
697
      match sel with
698
      (* we extract the element from the list and add it to the
699
         appropriate list *)
700
      | [_, sel_status] ->
701
         if sel_status then
702
           (others_guards,expr)::selected, left_out
703
         else selected, (others_guards,expr)::left_out
704
      | [] -> (* no such guard exists, we have to duplicate the
705
              guard_expr in both lists *)
706
         ge::selected, ge::left_out
707
      | _ -> (
708
        Format.eprintf "@.Spliting list on elem %a.@.List:%a@."
709
          pp_elem elem
710
          (pp_mdefs pp_elem) mdefs;
711
        assert false (* more then one element selected. Should
712
                          not happen , or trival dead code like if
713
                              x then if not x then dead code *)
714
      )
715
    ) ([],[]) mdefs
716
    
717
let split_mem_defs
718
      (elem: element)
719
      (mem_defs: (ident * elem_guarded_expr list) list)
720
      :
721
      ((ident * elem_guarded_expr mdef_t) list) * ((ident * elem_guarded_expr mdef_t) list)
722
  
723
  =
724
  List.fold_right (fun (m,mdefs)
725
                       (accu_pos, accu_neg) ->
726
      let pos, neg =
727
        split_mdefs elem mdefs 
728
      in
729
      (m, pos)::accu_pos,
730
      (m, neg)::accu_neg
731
    ) mem_defs ([],[])
732

    
733

    
734
(* Split a list of mem_defs into init and step lists of guarded
735
   expressions per memory. *)
736
let split_init mem_defs =
737
  split_mem_defs IsInit mem_defs 
738

    
739
(* Previous version of the function: way too costly 
740
let pick_guard mem_defs : expr option =  
741
  let gel = List.flatten (List.map snd mem_defs) in
742
  let gl = List.flatten (List.map fst gel) in
743
  let all_guards =
744
    List.map (
745
        (* selecting guards and getting rid of boolean *)
746
        fun (e,b) ->
747
        match e with
748
        | Expr e -> e
749
        | _ -> assert false
750
      (* should have been filtered out
751
                                      yet *)
752
      ) gl
753
  in
754
  (* TODO , one could sort by occurence and provided the most common
755
     one *)
756
  try
757
  Some (List.hd all_guards)  
758
  with _ -> None
759
   *)
760

    
761
(* Returning the first non empty guard expression *)
762
let rec pick_guard mem_defs : expr option =
763
  match mem_defs with
764
  | [] -> None
765
  | (_, gel)::tl -> (
766
    let found =
767
      List.fold_left (fun found (g,_) ->
768
          if found = None then
769
            match g with
770
            | [] -> None
771
            | (Expr e, _)::_ -> Some e
772
            | (IsInit, _)::_ -> assert false (* should be removed already *)
773
          else
774
            found
775
        ) None gel
776
    in
777
    if found = None then pick_guard tl else found
778
  )
779
          
780

    
781
(* Transform a list of variable * guarded exprs into a list of guarded pairs (variable, expressions)
782
*)
783
let rec build_switch_sys
784
          (mem_defs : (Utils.ident * elem_guarded_expr list) list )
785
          prefix
786
        :
787
          ((expr * bool) list * (ident * expr) list ) list =
788
  if !seal_debug then
789
    report ~level:4 (fun fmt -> Format.fprintf fmt "@[<v 2>Build_switch with@ %a@]@."
790
                                  pp_all_defs
791
                                  mem_defs);
792
  (* if all mem_defs have empty guards, we are done, return prefix,
793
     mem_defs expr.
794

    
795
     otherwise pick a guard in one of the mem, eg (g, b) then for each
796
     other mem, one need to select the same guard g with the same
797
     status b, *)
798
  let res =
799
  if List.for_all (fun (m,mdefs) ->
800
         (* All defs are unguarded *)
801
         match mdefs with
802
         | [[], _] -> true (* Regular unguarded expression *)
803
         | [] -> true (* A unbalanced definition of the memory. Here
804
                         we have m_{k+1} -> m_k *)
805
         | _ -> false
806
       ) mem_defs
807
  then
808
    [prefix ,
809
     List.map (fun (m,gel) ->
810
         match gel with
811
         | [_,e] ->
812
            let e =
813
              match e with
814
              | Expr e -> e
815
              | _ -> assert false (* No IsInit expression *)
816
            in
817
            m,e
818
         | [] -> m, Corelang.expr_of_ident m Location.dummy_loc
819
         | _ -> assert false
820
       ) mem_defs]
821
  else
822
    (* Picking a guard *)
823
    let elem_opt : expr option = pick_guard mem_defs in
824
    match elem_opt with
825
      None -> (
826
       Format.eprintf "Issues picking guard in mem_defs: %a@." pp_all_defs mem_defs;
827
       assert false (* Otherwise the first case should have matched *)
828
    )
829
    | Some elem -> (
830
      report ~level:4 (fun fmt -> Format.fprintf fmt "selecting guard %a@." Printers.pp_expr elem);
831
      let pos, neg =
832
        split_mem_defs
833
          (Expr elem)
834
          mem_defs
835
      in
836
  (*    Format.eprintf "Selected item %a in@.%a@.POS=%a@.NEG=%a@."
837
        Printers.pp_expr elem
838
        pp_all_defs mem_defs
839
        pp_all_defs pos
840
        pp_all_defs neg
841
        ;
842
   *)
843
      (* Special cases to avoid useless computations: true, false conditions *)
844
      match elem.expr_desc with
845
      (*| Expr_ident "true"  ->   build_switch_sys pos prefix *)
846
      | Expr_const (Const_tag tag) when tag = Corelang.tag_true
847
        ->   build_switch_sys pos prefix
848
      (*| Expr_ident "false" ->   build_switch_sys neg prefix *)
849
      | Expr_const (Const_tag tag) when tag = Corelang.tag_false 
850
        ->   build_switch_sys neg prefix
851
      | _ -> (* Regular case *)
852
         (* let _ = (
853
          *     Format.eprintf "Expr is %a@." Printers.pp_expr elem;
854
          *     match elem.expr_desc with
855
          *     | Expr_const _ -> Format.eprintf "a const@."
856
          *                     
857
          *     | Expr_ident _ -> Format.eprintf "an ident@."
858
          *     | _ -> Format.eprintf "something else@."
859
          *   )
860
          * in *)
861
         let clean l =
862
           let l = List.map (fun (e,b) -> (Expr e), b) l in
863
           let ok, l = check_sat l in
864
           let l = List.map (fun (e,b) -> deelem e, b) l in
865
           ok, l
866
         in
867
         let pos_prefix = (elem, true)::prefix in
868
         let neg_prefix = (elem, false)::prefix in
869
         let ok_pos, pos_prefix = clean pos_prefix in         
870
         let ok_neg, neg_prefix = clean neg_prefix in
871
         report ~level:4 (fun fmt -> Format.fprintf fmt "Enforcing %a@." Printers.pp_expr elem);
872
         let ok_l = if ok_pos then build_switch_sys pos pos_prefix else [] in
873
         report ~level:4 (fun fmt -> Format.fprintf fmt "Enforcing not(%a)@." Printers.pp_expr elem);
874
         let nok_l = if ok_neg then build_switch_sys neg neg_prefix else [] in
875
         ok_l @ nok_l
876
    )
877
  in
878
    if !seal_debug then (
879
      report ~level:4 (fun fmt ->
880
          Format.fprintf fmt
881
            "@[<v 2>===> @[%t@ @]@]@ @]@ "
882
            (fun fmt -> List.iter (fun (gl,up) ->
883
                            Format.fprintf fmt "[@[%a@]] -> (%a)@ "
884
                              (pp_guard_list Printers.pp_expr) gl pp_up up) res);
885
          
886
    ));
887
    res
888
  
889

    
890
      
891
(* Take a normalized node and extract a list of switches: (cond,
892
   update) meaning "if cond then update" where update shall define all
893
   node memories. Everything as to be expressed over inputs or memories, intermediate variables are removed through inlining *)
894
let node_as_switched_sys consts (mems:var_decl list) nd =
895
  (* rescheduling node: has been scheduled already, no need to protect
896
     the call to schedule_node *)
897
  let nd_report = Scheduling.schedule_node nd in
898
  let schedule = nd_report.Scheduling_type.schedule in
899
  let eqs, auts = Corelang.get_node_eqs nd in
900
  assert (auts = []); (* Automata should be expanded by now *)
901
  let sorted_eqs, unused = Scheduling.sort_equations_from_schedule eqs schedule in
902
  let defs : (ident,  elem_guarded_expr list) Hashtbl.t = Hashtbl.create 13 in
903
  let add_def = add_def defs in
904

    
905
  let vars = Corelang.get_node_vars nd in
906
  (* Filtering out unused vars *)
907
  let vars = List.filter (fun v -> not (List.mem v.var_id unused)) vars in
908
  (* Registering all locals variables as Z3 predicates. Will be use to
909
     simplify the expansion *)
910
  Zustre_common.decl_sorts (); 
911
  let _ =
912
    List.iter (fun v ->
913
        let fdecl = Z3.FuncDecl.mk_func_decl_s
914
                      !ctx
915
                      v.var_id
916
                      []
917
                      (Zustre_common.type_to_sort v.var_type)
918
        in
919
        ignore (Zustre_common.register_fdecl v.var_id fdecl)
920
      ) vars
921
  in
922
  let _ =
923
    List.iter (fun c -> Hashtbl.add const_defs c.const_id c.const_value) consts
924
  in
925

    
926
  
927
  (* Registering node equations: identifying mem definitions and
928
     storing others in the "defs" hashtbl.
929

    
930
     Each assign is stored in a hash tbl as list of guarded
931
     expressions. The memory definition is also "rewritten" as such a
932
     list of guarded assigns.  *)
933
  let mem_defs, output_defs =
934
    List.fold_left (fun (accu_mems, accu_outputs) eq ->
935
        match eq.eq_lhs with
936
        | [vid] ->
937
           (* Only focus on memory definitions *)
938
           if List.exists (fun v -> v.var_id = vid) mems then 
939
             (
940
               match eq.eq_rhs.expr_desc with
941
               | Expr_pre def_m ->
942
                  report ~level:3 (fun fmt ->
943
                      Format.fprintf fmt "Preparing mem %s@." vid);
944
                  (vid, rewrite defs def_m)::accu_mems, accu_outputs
945
               | _ -> assert false
946
             ) 
947
           else if List.exists (fun v -> v.var_id = vid) nd.node_outputs then (
948
             report ~level:3 (fun fmt ->
949
                 Format.fprintf fmt "Output variable %s@." vid);
950
             add_def vid eq.eq_rhs;
951
             accu_mems, (vid, rewrite defs eq.eq_rhs)::accu_outputs
952
             
953
           )
954
           else
955
             (
956
               report ~level:3 (fun fmt ->
957
                   Format.fprintf fmt "Registering variable %s@." vid);
958
               add_def vid eq.eq_rhs;
959
               accu_mems, accu_outputs
960
             )
961
        | _ -> assert false (* should have been removed by normalization *)
962
      ) ([], []) sorted_eqs
963
  in
964

    
965
  
966
  report ~level:2 (fun fmt -> Format.fprintf fmt "Printing out (guarded) memories definitions (may takes time)@.");
967
  (* Printing memories definitions *)
968
  report ~level:3
969
    (fun fmt ->
970
      Format.fprintf fmt
971
        "@[<v 0>%a@]@."
972
        (Utils.fprintf_list ~sep:"@ "
973
           (fun fmt (m,mdefs) ->
974
             Format.fprintf fmt
975
               "%s -> [@[<v 0>%a@] ]@ "
976
               m
977
               (Utils.fprintf_list ~sep:"@ "
978
                  (pp_guard_expr pp_elem)) mdefs
979
        ))
980
        mem_defs);
981
  (* Format.eprintf "Split init@."; *)
982
  let init_defs, update_defs =
983
    split_init mem_defs 
984
  in
985
  let init_out, update_out =
986
    split_init output_defs
987
  in
988
  report ~level:3
989
    (fun fmt ->
990
      Format.fprintf fmt
991
        "@[<v 0>Init:@ %a@]@."
992
        (Utils.fprintf_list ~sep:"@ "
993
           (fun fmt (m,mdefs) ->
994
             Format.fprintf fmt
995
               "%s -> @[<v 0>[%a@] ]@ "
996
               m
997
               (Utils.fprintf_list ~sep:"@ "
998
                  (pp_guard_expr pp_elem)) mdefs
999
        ))
1000
        init_defs);
1001
  report ~level:3
1002
    (fun fmt ->
1003
      Format.fprintf fmt
1004
        "@[<v 0>Step:@ %a@]@."
1005
        (Utils.fprintf_list ~sep:"@ "
1006
           (fun fmt (m,mdefs) ->
1007
             Format.fprintf fmt
1008
               "%s -> @[<v 0>[%a@] ]@ "
1009
               m
1010
               (Utils.fprintf_list ~sep:"@ "
1011
                  (pp_guard_expr pp_elem)) mdefs
1012
        ))
1013
        update_defs);
1014
  (* Format.eprintf "Build init@."; *)
1015
  report ~level:4 (fun fmt -> Format.fprintf fmt "Build init@.");
1016
  let sw_init= 
1017
    build_switch_sys init_defs []
1018
  in
1019
  (* Format.eprintf "Build step@."; *)
1020
  report ~level:4 (fun fmt -> Format.fprintf fmt "Build step@.");
1021
  let sw_sys =
1022
    build_switch_sys update_defs []
1023
  in
1024

    
1025
  report ~level:4 (fun fmt -> Format.fprintf fmt "Build init out@.");
1026
  let init_out =
1027
    build_switch_sys init_out []
1028
  in
1029
  report ~level:4 (fun fmt -> Format.fprintf fmt "Build step out@.");
1030

    
1031
  let update_out =
1032
    build_switch_sys update_out []
1033
  in
1034

    
1035
  let sw_init = clean_sys sw_init in
1036
  let sw_sys = clean_sys sw_sys in
1037
  let init_out = clean_sys init_out in
1038
  let update_out = clean_sys update_out in
1039

    
1040
  (* Some additional checks *)
1041
  
1042
  if false then
1043
    begin
1044
      Format.eprintf "@.@.CHECKING!!!!!!!!!!!@.";
1045
      Format.eprintf "Any duplicate expression in guards?@.";
1046
      
1047
      let sw_sys =
1048
        List.map (fun (gl, up) ->
1049
            let gl = List.sort (fun (e,b) (e',b') ->
1050
                         let res = compare e.expr_tag e'.expr_tag in
1051
                         if res = 0 then (Format.eprintf "Same exprs?@.%a@.%a@.@."
1052
                                            Printers.pp_expr e
1053
                                            Printers.pp_expr e'
1054
                                         );
1055
                         res
1056
                       ) gl in
1057
            gl, up
1058
          ) sw_sys 
1059
      in
1060
      Format.eprintf "Another check for duplicates in guard list@.";
1061
      List.iter (fun (gl, _) ->
1062
          let rec aux hd l =
1063
            match l with
1064
              [] -> ()
1065
            | (e,b)::tl -> let others = hd@tl in
1066
                           List.iter (fun (e',_) -> if Corelang.is_eq_expr e e' then
1067
                                                      (Format.eprintf "Same exprs?@.%a@.%a@.@."
1068
                                                         Printers.pp_expr e
1069
                                                         Printers.pp_expr e'
1070
                             )) others;
1071
                           aux ((e,b)::hd) tl
1072
          in
1073
          aux [] gl
1074
        ) sw_sys;
1075
      Format.eprintf "Checking duplicates in updates@.";
1076
      let rec check_dup_up accu l =
1077
        match l with
1078
        | [] -> ()
1079
        | ((gl, up) as hd)::tl ->
1080
           let others = accu@tl in
1081
           List.iter (fun (gl',up') -> if up = up' then
1082
                                         Format.eprintf "Same updates?@.%a@.%a@.%a@.%a@.@."
1083

    
1084
                                           pp_gl_short gl
1085
                                           pp_up up
1086
                                           pp_gl_short gl'
1087
                                           pp_up up'
1088
                                       
1089
             ) others;
1090
           
1091
           
1092

    
1093
           check_dup_up (hd::accu) tl
1094
           
1095
      in
1096
      check_dup_up [] sw_sys;
1097
      let sw_sys =
1098
        List.sort (fun (gl1, _) (gl2, _) ->
1099
            let glid gl = List.map (fun (e,_) -> e.expr_tag) gl in
1100
            
1101
            let res = compare (glid gl1) (glid gl2) in
1102
            if res = 0 then Format.eprintf "Same guards?@.%a@.%a@.@."
1103
                              pp_gl_short gl1 pp_gl_short gl2
1104
            ;
1105
              res
1106

    
1107
          ) sw_sys
1108

    
1109
      in
1110
      ()
1111
    end;
1112
  
1113

    
1114
  (* Iter through the elements and gather them by updates *)
1115
  let process sys =
1116
    (* The map will associate to each update up the pair (set, set
1117
       list) where set is the share guards and set list a list of
1118
       disjunctive guards. Each set represents a conjunction of
1119
       expressions. *)
1120
    report ~level:3 (fun fmt -> Format.fprintf fmt "%t@."
1121
                                  (fun fmt -> List.iter (fun (gl,up) ->
1122
                                                  Format.fprintf fmt "[@[%a@]] -> (%a)@ "
1123
                                                    (pp_guard_list Printers.pp_expr) gl pp_up up) sw_init));
1124
    
1125
    (* We perform multiple pass to avoid errors *)
1126
    let map =
1127
      List.fold_left (fun map (gl,up) ->
1128
          (* creating a new set to describe gl *)
1129
          let new_set =
1130
            List.fold_left
1131
              (fun set g -> Guards.add g set)
1132
              Guards.empty
1133
              gl
1134
          in
1135
          (* updating the map with up -> new_set *)
1136
          if UpMap.mem up map then
1137
            let guard_set = UpMap.find up map in
1138
            UpMap.add up (new_set::guard_set) map
1139
          else
1140
            UpMap.add up [new_set] map
1141
        ) UpMap.empty sys
1142
    in
1143
    (* Processing the set of guards leading to the same update: return
1144
       conj, disj with conf is a set of guards, and disj a DNF, ie a
1145
       list of set of guards *)
1146
    let map =
1147
      UpMap.map (
1148
          fun guards ->
1149
          match guards with
1150
          | [] -> Guards.empty, [] (* Nothing *)
1151
          | [s]-> s, [] (* basic case *)
1152
          | hd::tl ->
1153
             let shared = List.fold_left (fun shared s -> Guards.inter shared s) hd tl in
1154
             let remaining = List.map (fun s -> Guards.diff s shared) guards in
1155
             (* If one of them is empty, we can remove the others, otherwise keep them *)
1156
             if List.exists Guards.is_empty remaining then
1157
               shared, []
1158
             else
1159
               shared, remaining
1160
        ) map
1161
    in
1162
  let rec mk_binop op l = match l with
1163
      [] -> assert false
1164
    | [e] -> e
1165
    | hd::tl -> Corelang.mkpredef_call hd.expr_loc op [hd; mk_binop op tl]
1166
  in
1167
  let gl_as_expr gl =
1168
    let gl = Guards.elements gl in
1169
    let export (e,b) = if b then e else Corelang.push_negations ~neg:true e in 
1170
    match gl with
1171
      [] -> []
1172
    | [e] -> [export e]
1173
    | _ ->
1174
       [mk_binop "&&"
1175
          (List.map export gl)]
1176
  in
1177
  let rec clean_disj disj =
1178
    match disj with
1179
    | [] -> []
1180
    | [_] -> assert false (* A disjunction was a single case can be ignored *) 
1181
    | _::_::_ -> (
1182
      (* First basic version: producing a DNF One can later, (1)
1183
           simplify it with z3, or (2) build the compact tree with
1184
           maximum shared subexpression (and simplify it with z3) *)
1185
      let elems = List.fold_left (fun accu gl -> (gl_as_expr gl) @ accu) [] disj in
1186
      let or_expr = mk_binop "||" elems in
1187
      [or_expr]
1188

    
1189

    
1190
    (* TODO disj*)
1191
    (* get the item that occurs in most case *)
1192
    (* List.fold_left (fun accu s ->
1193
     *     List.fold_left (fun accu (e,b) ->
1194
     *         if List.mem_assoc (e.expr_tag, b)
1195
     *       ) accu (Guards.elements s)
1196
     *   ) [] disj *)
1197

    
1198
    )
1199
  in
1200
  if !seal_debug then Format.eprintf "Map: %i elements@ " (UpMap.cardinal map);
1201
  UpMap.fold (fun up (common, disj) accu ->
1202
      if !seal_debug then
1203
        Format.eprintf
1204
          "Guards:@.shared: [%a]@.disj: [@[<v 0>%a@ ]@]@.Updates: %a@."
1205
          Guards.pp_short common
1206
          (fprintf_list ~sep:";@ " Guards.pp_long) disj
1207
          UpMap.pp up;
1208
      let disj = clean_disj disj in
1209
      let guard_expr = (gl_as_expr common)@disj in
1210
      
1211
      ((match guard_expr with
1212
        | [] -> None 
1213
        | _ -> Some (mk_binop "&&" guard_expr)), up)::accu
1214
    ) map []
1215
  
1216
    in
1217
    
1218
    
1219
    
1220
    report ~level:3 (fun fmt -> Format.fprintf fmt "Process sw_init:@.");
1221
    let sw_init = process sw_init in
1222
    report ~level:3 (fun fmt -> Format.fprintf fmt "Process sw_sys:@.");
1223
    let sw_sys = process sw_sys in
1224
    report ~level:3 (fun fmt -> Format.fprintf fmt "Process init_out:@.");
1225
    let init_out = process init_out in
1226
    report ~level:3 (fun fmt -> Format.fprintf fmt "Process update_out:@.");
1227
    let update_out = process update_out in
1228
    sw_init , sw_sys, init_out, update_out
(2-2/5)