Project

General

Profile

Download (45.1 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
                      (Real.create_num num 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
  
359
  let solver = Z3.Solver.mk_simple_solver !ctx in
360
  try (
361
    let zl =
362
      List.map (fun (e, posneg) ->
363
          let ze =
364
            match e with
365
            | IsInit -> is_init_z3e
366
            | Expr e -> expr_to_z3_expr e 
367
          in
368
          if posneg then
369
            ze
370
          else
371
            neg_ze ze
372
        ) l
373
    in
374
    if false then Format.eprintf "Z3 exprs1: [%a]@ " (fprintf_list ~sep:",@ " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) zl; 
375
    let zl = simplify zl in
376
    if false then Format.eprintf "Z3 exprs2: [%a]@ " (fprintf_list ~sep:",@ " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) zl; 
377
    (* Format.eprintf "Calling Z3@."; *)
378
    let status_res = Z3.Solver.check solver zl in
379
    (* Format.eprintf "Z3 done@."; *)
380
     if false then Format.eprintf "Z3 status: %s@ @]@. " (Z3.Solver.string_of_status status_res); 
381
    match status_res with
382
    | Z3.Solver.UNSATISFIABLE -> false, []
383
    | _ -> (
384
      if false && just_check then
385
        true, l
386
      else
387
        (* TODO: may be reactivate but it may create new expressions *)
388
        (* let l = goal_simplify zl in *)
389
        let l = List.fold_left
390
                  (fun accu ze -> accu @ (zexpr_to_guard_list ze))
391
                  []
392
                  zl
393
        in
394
  (* Format.eprintf "@.@[<v 2>Check_Sat:@ before: %a@ after:
395
       %a@. Goal precise? %b/%b@]@.@. " * pp_guard_list l
396
       pp_guard_list l' * (Z3.Goal.is_precise goal) *
397
       (Z3.Goal.is_precise goal'); *)
398
  
399

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

    
413

    
414
(**************************************************************)
415

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

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

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

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

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

    
453
 *)
454

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

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

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

    
550
            let ok, gl = combine_guards ~fresh:(Some(e1,posneg)) g1 g2 in
551
            (* Format.eprintf "@]@ Result is [%a]@ "
552
             *   pp_guard_list gl; *)
553

    
554
            if ok then
555
              (gl, e2)::accu, false
556
            else (
557
              accu, all_invalid
558
            )
559
          ) (accu, all_invalid) gel1
560
      ) ([], true) gel2
561
  in
562
  not all_invalid, l
563

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

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

    
701
(* Takes a list of guarded exprs (ge) and a guard
702
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.
703

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

    
747

    
748
(* Split a list of mem_defs into init and step lists of guarded
749
   expressions per memory. *)
750
let split_init mem_defs =
751
  split_mem_defs IsInit mem_defs 
752

    
753
(* Previous version of the function: way too costly 
754
let pick_guard mem_defs : expr option =  
755
  let gel = List.flatten (List.map snd mem_defs) in
756
  let gl = List.flatten (List.map fst gel) in
757
  let all_guards =
758
    List.map (
759
        (* selecting guards and getting rid of boolean *)
760
        fun (e,b) ->
761
        match e with
762
        | Expr e -> e
763
        | _ -> assert false
764
      (* should have been filtered out
765
                                      yet *)
766
      ) gl
767
  in
768
  (* TODO , one could sort by occurence and provided the most common
769
     one *)
770
  try
771
  Some (List.hd all_guards)  
772
  with _ -> None
773
   *)
774

    
775
(* Returning the first non empty guard expression *)
776
let rec pick_guard mem_defs : expr option =
777
  match mem_defs with
778
  | [] -> None
779
  | (_, gel)::tl -> (
780
    let found =
781
      List.fold_left (fun found (g,_) ->
782
          if found = None then
783
            match g with
784
            | [] -> None
785
            | (Expr e, _)::_ -> Some e
786
            | (IsInit, _)::_ -> assert false (* should be removed already *)
787
          else
788
            found
789
        ) None gel
790
    in
791
    if found = None then pick_guard tl else found
792
  )
793
          
794

    
795
(* Transform a list of variable * guarded exprs into a list of guarded pairs (variable, expressions)
796
*)
797
let rec build_switch_sys
798
          (mem_defs : (Utils.ident * elem_guarded_expr list) list )
799
          prefix
800
        :
801
          ((expr * bool) list * (ident * expr) list ) list =
802
  if !seal_debug then
803
    report ~level:4 (fun fmt -> Format.fprintf fmt "@[<v 2>Build_switch with@ %a@]@."
804
                                  pp_all_defs
805
                                  mem_defs);
806
  (* if all mem_defs have empty guards, we are done, return prefix,
807
     mem_defs expr.
808

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

    
914
      
915
(* Take a normalized node and extract a list of switches: (cond,
916
   update) meaning "if cond then update" where update shall define all
917
   node memories. Everything as to be expressed over inputs or memories, intermediate variables are removed through inlining *)
918
let node_as_switched_sys consts (mems:var_decl list) nd =
919
   Z3.Params.update_param_value !ctx "timeout" "10000";
920

    
921
 
922
  (* rescheduling node: has been scheduled already, no need to protect
923
     the call to schedule_node *)
924
  let nd_report = Scheduling.schedule_node nd in
925
  let schedule = nd_report.Scheduling_type.schedule in
926
  let eqs, auts = Corelang.get_node_eqs nd in
927
  assert (auts = []); (* Automata should be expanded by now *)
928
  let sorted_eqs, unused = Scheduling.sort_equations_from_schedule eqs schedule in
929
  let defs : (ident,  elem_guarded_expr list) Hashtbl.t = Hashtbl.create 13 in
930
  let add_def = add_def defs in
931

    
932
  let vars = Corelang.get_node_vars nd in
933
  (* Filtering out unused vars *)
934
  let vars = List.filter (fun v -> not (List.mem v.var_id unused)) vars in
935
  (* Registering all locals variables as Z3 predicates. Will be use to
936
     simplify the expansion *)
937
  Zustre_common.decl_sorts (); 
938
  let _ =
939
    List.iter (fun v ->
940
        let fdecl = Z3.FuncDecl.mk_func_decl_s
941
                      !ctx
942
                      v.var_id
943
                      []
944
                      (Zustre_common.type_to_sort v.var_type)
945
        in
946
        ignore (Zustre_common.register_fdecl v.var_id fdecl)
947
      ) vars
948
  in
949
  let _ =
950
    List.iter (fun c -> Hashtbl.add const_defs c.const_id c.const_value) consts
951
  in
952

    
953
  report ~level:4 (fun fmt -> Format.fprintf fmt "Computing definitions for equations@.%a@."
954
                            Printers.pp_node_eqs sorted_eqs
955
    );
956
  
957
  
958
  (* Registering node equations: identifying mem definitions and
959
     storing others in the "defs" hashtbl.
960

    
961
     Each assign is stored in a hash tbl as list of guarded
962
     expressions. The memory definition is also "rewritten" as such a
963
     list of guarded assigns.  *)
964
  report ~level:1 (fun fmt -> Format.fprintf fmt "registering all definitions in guarded form ...@.");
965
  let mem_defs, output_defs =
966
    List.fold_left (fun (accu_mems, accu_outputs) eq ->
967
        match eq.eq_lhs with
968
        | [vid] ->
969
           (* Only focus on memory definitions *)
970
           if List.exists (fun v -> v.var_id = vid) mems then 
971
             (
972
               match eq.eq_rhs.expr_desc with
973
               | Expr_pre def_m ->
974
                  report ~level:3 (fun fmt ->
975
                      Format.fprintf fmt "Preparing mem %s@." vid);
976
                  let def_vid = rewrite defs def_m in
977
                  report ~level:4 (fun fmt ->
978
                      Format.fprintf fmt "%s = %a@." vid
979
 (
980
        (Utils.fprintf_list ~sep:"@ "
981
           (pp_guard_expr pp_elem))) 
982
                        def_vid);
983
                  (vid, def_vid)::accu_mems, accu_outputs
984
               | _ -> assert false
985
             ) 
986
           else if List.exists (fun v -> v.var_id = vid) nd.node_outputs then (
987
             report ~level:3 (fun fmt ->
988
                 Format.fprintf fmt "Output variable %s@." vid);
989
             let def_vid = add_def vid eq.eq_rhs in
990
             accu_mems, (vid, def_vid)::accu_outputs
991
             
992
           )
993
           else
994
             (
995
               report ~level:3 (fun fmt ->
996
                   Format.fprintf fmt "Registering variable %s@." vid);
997
               let _ = add_def vid eq.eq_rhs in
998
               accu_mems, accu_outputs
999
             )
1000
        | _ -> assert false (* should have been removed by normalization *)
1001
      ) ([], []) sorted_eqs
1002
  in
1003
  report ~level:1 (fun fmt -> Format.fprintf fmt "registering all definitions done@.");
1004

    
1005
  
1006
  report ~level:2 (fun fmt -> Format.fprintf fmt "Printing out (guarded) memories definitions (may takes time)@.");
1007
  (* Printing memories definitions *)
1008
  report ~level:3
1009
    (fun fmt ->
1010
      Format.fprintf fmt
1011
        "@[<v 0>%a@]@."
1012
        (Utils.fprintf_list ~sep:"@ "
1013
           (fun fmt (m,mdefs) ->
1014
             Format.fprintf fmt
1015
               "%s -> [@[<v 0>%a@] ]@ "
1016
               m
1017
               (Utils.fprintf_list ~sep:"@ "
1018
                  (pp_guard_expr pp_elem)) mdefs
1019
        ))
1020
        mem_defs);
1021
  (* Format.eprintf "Split init@."; *)
1022
  let init_defs, update_defs =
1023
    split_init mem_defs 
1024
  in
1025
  let init_out, update_out =
1026
    split_init output_defs
1027
  in
1028
  report ~level:3
1029
    (fun fmt ->
1030
      Format.fprintf fmt
1031
        "@[<v 0>Init:@ %a@]@."
1032
        (Utils.fprintf_list ~sep:"@ "
1033
           (fun fmt (m,mdefs) ->
1034
             Format.fprintf fmt
1035
               "%s -> @[<v 0>[%a@] ]@ "
1036
               m
1037
               (Utils.fprintf_list ~sep:"@ "
1038
                  (pp_guard_expr pp_elem)) mdefs
1039
        ))
1040
        init_defs);
1041
  report ~level:3
1042
    (fun fmt ->
1043
      Format.fprintf fmt
1044
        "@[<v 0>Step:@ %a@]@."
1045
        (Utils.fprintf_list ~sep:"@ "
1046
           (fun fmt (m,mdefs) ->
1047
             Format.fprintf fmt
1048
               "%s -> @[<v 0>[%a@] ]@ "
1049
               m
1050
               (Utils.fprintf_list ~sep:"@ "
1051
                  (pp_guard_expr pp_elem)) mdefs
1052
        ))
1053
        update_defs);
1054
  (* Format.eprintf "Build init@."; *)
1055
  
1056
  report ~level:1 (fun fmt -> Format.fprintf fmt "init/step as a switched system ...@.");
1057
  let sw_init= 
1058
    build_switch_sys init_defs []
1059
  in
1060
  (* Format.eprintf "Build step@."; *)
1061
  let sw_sys =
1062
    build_switch_sys update_defs []
1063
  in
1064
  report ~level:1 (fun fmt -> Format.fprintf fmt "init/step as a switched system ... done@.");
1065

    
1066
  report ~level:1 (fun fmt -> Format.fprintf fmt "output function as a switched system ...@.");
1067
  let init_out =
1068
    build_switch_sys init_out []
1069
  in
1070
  (* report ~level:1 (fun fmt -> Format.fprintf fmt "Build step out@."); *)
1071

    
1072
  let update_out =
1073
    build_switch_sys update_out []
1074
  in
1075
  report ~level:1 (fun fmt -> Format.fprintf fmt "output function as a switched system ... done@.");
1076

    
1077
  report ~level:1 (fun fmt -> Format.fprintf fmt "removing dead branches and merging remaining ...@.");
1078

    
1079
  let sw_init = clean_sys sw_init in
1080
  let sw_sys = clean_sys sw_sys in
1081
  let init_out = clean_sys init_out in
1082
  let update_out = clean_sys update_out in
1083
  report ~level:1 (fun fmt -> Format.fprintf fmt "removing dead branches and merging remaining ... done@.");
1084

    
1085
  (* Some additional checks *)
1086
  
1087
  if false then
1088
    begin
1089
      Format.eprintf "@.@.CHECKING!!!!!!!!!!!@.";
1090
      Format.eprintf "Any duplicate expression in guards?@.";
1091
      
1092
      let sw_sys =
1093
        List.map (fun (gl, up) ->
1094
            let gl = List.sort (fun (e,b) (e',b') ->
1095
                         let res = compare e.expr_tag e'.expr_tag in
1096
                         if res = 0 then (Format.eprintf "Same exprs?@.%a@.%a@.@."
1097
                                            Printers.pp_expr e
1098
                                            Printers.pp_expr e'
1099
                                         );
1100
                         res
1101
                       ) gl in
1102
            gl, up
1103
          ) sw_sys 
1104
      in
1105
      Format.eprintf "Another check for duplicates in guard list@.";
1106
      List.iter (fun (gl, _) ->
1107
          let rec aux hd l =
1108
            match l with
1109
              [] -> ()
1110
            | (e,b)::tl -> let others = hd@tl in
1111
                           List.iter (fun (e',_) -> if Corelang.is_eq_expr e e' then
1112
                                                      (Format.eprintf "Same exprs?@.%a@.%a@.@."
1113
                                                         Printers.pp_expr e
1114
                                                         Printers.pp_expr e'
1115
                             )) others;
1116
                           aux ((e,b)::hd) tl
1117
          in
1118
          aux [] gl
1119
        ) sw_sys;
1120
      Format.eprintf "Checking duplicates in updates@.";
1121
      let rec check_dup_up accu l =
1122
        match l with
1123
        | [] -> ()
1124
        | ((gl, up) as hd)::tl ->
1125
           let others = accu@tl in
1126
           List.iter (fun (gl',up') -> if up = up' then
1127
                                         Format.eprintf "Same updates?@.%a@.%a@.%a@.%a@.@."
1128

    
1129
                                           pp_gl_short gl
1130
                                           pp_up up
1131
                                           pp_gl_short gl'
1132
                                           pp_up up'
1133
                                       
1134
             ) others;
1135
           
1136
           
1137

    
1138
           check_dup_up (hd::accu) tl
1139
           
1140
      in
1141
      check_dup_up [] sw_sys;
1142
      let _ (* sw_sys *) =
1143
        List.sort (fun (gl1, _) (gl2, _) ->
1144
            let glid gl = List.map (fun (e,_) -> e.expr_tag) gl in
1145
            
1146
            let res = compare (glid gl1) (glid gl2) in
1147
            if res = 0 then Format.eprintf "Same guards?@.%a@.%a@.@."
1148
                              pp_gl_short gl1 pp_gl_short gl2
1149
            ;
1150
              res
1151

    
1152
          ) sw_sys
1153

    
1154
      in
1155
      ()
1156
    end;
1157
  
1158

    
1159
  (* Iter through the elements and gather them by updates *)
1160
  let process sys =
1161
    (* The map will associate to each update up the pair (set, set
1162
       list) where set is the share guards and set list a list of
1163
       disjunctive guards. Each set represents a conjunction of
1164
       expressions. *)
1165
    report ~level:3 (fun fmt -> Format.fprintf fmt "%t@."
1166
                                  (fun fmt -> List.iter (fun (gl,up) ->
1167
                                                  Format.fprintf fmt "[@[%a@]] -> (%a)@ "
1168
                                                    (pp_guard_list Printers.pp_expr) gl pp_up up) sw_init));
1169
    
1170
    (* We perform multiple pass to avoid errors *)
1171
    let map =
1172
      List.fold_left (fun map (gl,up) ->
1173
          (* creating a new set to describe gl *)
1174
          let new_set =
1175
            List.fold_left
1176
              (fun set g -> Guards.add g set)
1177
              Guards.empty
1178
              gl
1179
          in
1180
          (* updating the map with up -> new_set *)
1181
          if UpMap.mem up map then
1182
            let guard_set = UpMap.find up map in
1183
            UpMap.add up (new_set::guard_set) map
1184
          else
1185
            UpMap.add up [new_set] map
1186
        ) UpMap.empty sys
1187
    in
1188
    (* Processing the set of guards leading to the same update: return
1189
       conj, disj with conf is a set of guards, and disj a DNF, ie a
1190
       list of set of guards *)
1191
    let map =
1192
      UpMap.map (
1193
          fun guards ->
1194
          match guards with
1195
          | [] -> Guards.empty, [] (* Nothing *)
1196
          | [s]-> s, [] (* basic case *)
1197
          | hd::tl ->
1198
             let shared = List.fold_left (fun shared s -> Guards.inter shared s) hd tl in
1199
             let remaining = List.map (fun s -> Guards.diff s shared) guards in
1200
             (* If one of them is empty, we can remove the others, otherwise keep them *)
1201
             if List.exists Guards.is_empty remaining then
1202
               shared, []
1203
             else
1204
               shared, remaining
1205
        ) map
1206
    in
1207
  let rec mk_binop op l = match l with
1208
      [] -> assert false
1209
    | [e] -> e
1210
    | hd::tl -> Corelang.mkpredef_call hd.expr_loc op [hd; mk_binop op tl]
1211
  in
1212
  let gl_as_expr gl =
1213
    let gl = Guards.elements gl in
1214
    let export (e,b) = if b then e else Corelang.push_negations ~neg:true e in 
1215
    match gl with
1216
      [] -> []
1217
    | [e] -> [export e]
1218
    | _ ->
1219
       [mk_binop "&&"
1220
          (List.map export gl)]
1221
  in
1222
  let rec clean_disj disj =
1223
    match disj with
1224
    | [] -> []
1225
    | [_] -> assert false (* A disjunction was a single case can be ignored *) 
1226
    | _::_::_ -> (
1227
      (* First basic version: producing a DNF One can later, (1)
1228
           simplify it with z3, or (2) build the compact tree with
1229
           maximum shared subexpression (and simplify it with z3) *)
1230
      let elems = List.fold_left (fun accu gl -> (gl_as_expr gl) @ accu) [] disj in
1231
      let or_expr = mk_binop "||" elems in
1232
      [or_expr]
1233

    
1234

    
1235
    (* TODO disj*)
1236
    (* get the item that occurs in most case *)
1237
    (* List.fold_left (fun accu s ->
1238
     *     List.fold_left (fun accu (e,b) ->
1239
     *         if List.mem_assoc (e.expr_tag, b)
1240
     *       ) accu (Guards.elements s)
1241
     *   ) [] disj *)
1242

    
1243
    )
1244
  in
1245
  if !seal_debug then Format.eprintf "Map: %i elements@ " (UpMap.cardinal map);
1246
  UpMap.fold (fun up (common, disj) accu ->
1247
      if !seal_debug then
1248
        report ~level:6 (fun fmt -> Format.fprintf fmt 
1249
          "Guards:@.shared: [%a]@.disj: [@[<v 0>%a@ ]@]@.Updates: %a@."
1250
          Guards.pp_short common
1251
          (fprintf_list ~sep:";@ " Guards.pp_long) disj
1252
          UpMap.pp up);
1253
      let disj = clean_disj disj in
1254
      let guard_expr = (gl_as_expr common)@disj in
1255
      
1256
      ((match guard_expr with
1257
        | [] -> None 
1258
        | _ -> Some (mk_binop "&&" guard_expr)), up)::accu
1259
    ) map []
1260
  
1261
    in
1262
    
1263
    
1264
    
1265
    report ~level:3 (fun fmt -> Format.fprintf fmt "Process sw_init:@.");
1266
    let sw_init = process sw_init in
1267
    report ~level:3 (fun fmt -> Format.fprintf fmt "Process sw_sys:@.");
1268
    let sw_sys = process sw_sys in
1269
    report ~level:3 (fun fmt -> Format.fprintf fmt "Process init_out:@.");
1270
    let init_out = process init_out in
1271
    report ~level:3 (fun fmt -> Format.fprintf fmt "Process update_out:@.");
1272
    let update_out = process update_out in
1273
    sw_init , sw_sys, init_out, update_out
(2-2/5)