Project

General

Profile

Download (27.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 *)
8
type element = IsInit | Expr of expr
9
type guard = (element * bool) list
10
type guarded_expr = guard * element
11
type mdef_t = guarded_expr list
12

    
13
let pp_elem fmt e =
14
  match e with
15
  | IsInit -> Format.fprintf fmt "init"
16
  | Expr e -> Printers.pp_expr fmt e
17

    
18
let pp_guard_list fmt gl =
19
  (fprintf_list ~sep:"; "
20
     (fun fmt (e,b) -> if b then pp_elem fmt e else Format.fprintf fmt "not(%a)" pp_elem e)) fmt gl
21
  
22
let pp_guard_expr fmt (gl,e) =
23
  Format.fprintf fmt "%a -> %a"
24
    pp_guard_list  gl
25
    pp_elem e
26

    
27
let pp_mdefs fmt gel = fprintf_list ~sep:"@ " pp_guard_expr fmt gel
28

    
29
  
30
let add_init defs vid =
31
  Hashtbl.add defs vid [[], IsInit]
32

    
33
let deelem e =  match e with
34
    Expr e -> e
35
  | IsInit -> assert false (* Wasn't expecting isinit here: we are building values! *)
36

    
37
let is_eq_elem elem elem' =
38
  match elem, elem' with
39
  | IsInit, IsInit -> true
40
  | Expr e, Expr e' ->
41
     Corelang.is_eq_expr e e'
42
  | _ -> false
43

    
44
let select_elem elem (gelem, _) =
45
  is_eq_elem elem gelem
46

    
47

    
48
(**************************************************************)
49
(* Convert from Lustre expressions to Z3 expressions and back *)
50
(* All (free) variables have to be declared in the Z3 context *)
51
(**************************************************************)
52

    
53
let is_init_name = "__is_init"
54

    
55
let const_defs = Hashtbl.create 13
56
let is_const id = Hashtbl.mem const_defs id
57
let get_const id = Hashtbl.find const_defs id
58
                 
59
(* expressions are only basic constructs here, no more ite, tuples,
60
   arrows, fby, ... *)
61
let expr_to_z3_expr, zexpr_to_expr =
62
  (* List to store converted expression. *)
63
  let hash = ref [] in
64
  let comp_expr e (e', _) = Corelang.is_eq_expr e e' in
65
  let comp_zexpr ze (_, ze') = Z3.Expr.equal ze ze' in
66
  let mem_expr e = List.exists (comp_expr e) !hash in
67
  let mem_zexpr ze = List.exists (comp_zexpr ze) !hash in
68
  let get_zexpr e =
69
    let (_, ze) = List.find (comp_expr e) !hash in
70
    ze
71
  in
72
  let get_expr ze =
73
    let (e, _) = List.find (comp_zexpr ze) !hash in
74
    e
75
  in
76
  let add_expr e ze = hash := (e, ze)::!hash in
77
  let rec e2ze e =
78
    if mem_expr e then (
79
      get_zexpr e
80
    )
81
    else (
82
      let res =
83
        match e.expr_desc with
84
        | Expr_const c ->
85
           let z3e = Zustre_common.horn_const_to_expr c in
86
           add_expr e z3e;
87
           z3e
88
        | Expr_ident id -> (
89
          if is_const id then (
90
            let c = get_const id in
91
            let z3e = Zustre_common.horn_const_to_expr c in
92
            add_expr e z3e;
93
            z3e
94
        )
95
        else (
96
          let fdecl_id = Zustre_common.get_fdecl id in
97
          let z3e = Z3.Expr.mk_const_f !ctx fdecl_id in
98
          add_expr e z3e;
99
          z3e
100
          )
101
        )
102
      | Expr_appl (id,args, None) (* no reset *) ->
103
         let z3e = Zustre_common.horn_basic_app id e2ze (Corelang.expr_list_of_expr args) in
104
         add_expr e z3e;
105
         z3e
106
      | Expr_tuple [e] ->
107
         let z3e = e2ze e in
108
         add_expr e z3e;
109
         z3e
110
      | _ -> ( match e.expr_desc with Expr_tuple _ -> Format.eprintf "tuple e2ze(%a)@.@?" Printers.pp_expr e
111
                                    | _ -> Format.eprintf "e2ze(%a)@.@?" Printers.pp_expr e)
112
                 ; assert false
113
      in
114
      res
115
    )
116
  in
117
  let rec ze2e ze =
118
    let ze_name ze =
119
      let fd = Z3.Expr.get_func_decl ze in
120
      Z3.Symbol.to_string (Z3.FuncDecl.get_name fd)
121
    in
122
    if mem_zexpr ze then
123
      None, Some (get_expr ze)
124
    else
125
      let open Corelang in
126
      let fd = Z3.Expr.get_func_decl ze in
127
      let zel = Z3.Expr.get_args ze in
128
      match Z3.Symbol.to_string (Z3.FuncDecl.get_name fd), zel with
129
      (*      | var, [] -> (* should be in env *) get_e *)
130

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

    
219
let is_init_z3e = Z3.Expr.mk_const_s !ctx is_init_name  Zustre_common.bool_sort 
220
let neg_ze z3e = Z3.Boolean.mk_not !ctx z3e 
221

    
222
let zexpr_to_guard_list ze =
223
  let init_opt, expr_opt = zexpr_to_expr ze in
224
  (match init_opt with
225
   | None -> []
226
   |Some b -> [IsInit, b]
227
  ) @ (match expr_opt with
228
       | None -> []
229
       | Some e -> [Expr e, true]
230
      )
231
let simplify_neg_guard l =
232
  List.map (fun (g,posneg) ->
233
      match g with
234
      | IsInit -> g, posneg
235
      | Expr g ->
236
          if posneg then
237
            Expr (Corelang.push_negations g),
238
            true
239
          else
240
            (* Pushing the negation in the expression *)
241
            Expr(Corelang.push_negations ~neg:true g),
242
            true
243
    ) l 
244

    
245
(* TODO:
246
individuellement demander si g1 => g2. Si c'est le cas, on peut ne garder que g1 dans la liste
247
*)    
248
(*****************************************************************)
249
(* Checking sat(isfiability) of an expression and simplifying it *)
250
(* All (free) variables have to be declared in the Z3 context    *)
251
(*****************************************************************)
252
let goal_simplify zl =
253
  let goal = Z3.Goal.mk_goal !ctx false false false in
254
  Z3.Goal.add goal zl;
255
  let goal' = Z3.Goal.simplify goal None in
256
  (* Format.eprintf "Goal before: %s@.Goal after : %s@.Sat? %s@."
257
   *   (Z3.Goal.to_string goal)
258
   *   (Z3.Goal.to_string goal')
259
   *   (Z3.Solver.string_of_status status_res) 
260
   * ; *)
261
  let ze = Z3.Goal.as_expr goal' in
262
  (* Format.eprintf "as an expr: %s@." (Z3.Expr.to_string ze); *)
263
  ze
264

    
265
let implies e1 e2 =
266
  (* Format.eprintf "Checking implication: %s => %s? "
267
   * (Z3.Expr.to_string e1) (Z3.Expr.to_string e2)
268
   * ; *)
269
  let solver = Z3.Solver.mk_simple_solver !ctx in
270
  let tgt = Z3.Boolean.mk_not !ctx (Z3.Boolean.mk_implies !ctx e1 e2) in
271
  try
272
    let status_res = Z3.Solver.check solver [tgt] in
273
    match status_res with
274
    | Z3.Solver.UNSATISFIABLE -> (* Format.eprintf "Valid!@."; *)
275
                                 true
276
    | _ -> (* Format.eprintf "not proved valid@."; *)
277
           false
278
  with Zustre_common.UnknownFunction(id, msg) -> (
279
    report ~level:1 msg;
280
    false
281
  )
282
                                               
283
let rec simplify zl =
284
  match zl with
285
  | [] | [_] -> zl
286
  | hd::tl -> (
287
  (* Forall e in tl, checking whether hd => e or e => hd, to keep hd
288
     in the first case and e in the second one *)
289
    let tl = simplify tl in
290
    let keep_hd, tl =
291
      List.fold_left (fun (keep_hd, accu) e ->
292
          if implies hd e then
293
            true, accu (* throwing away e *)
294
          else if implies e hd then
295
            false, e::accu (* throwing away hd *)
296
          else
297
            keep_hd, e::accu (* keeping both *)
298
        ) (true,[]) tl
299
    in
300
    (* Format.eprintf "keep_hd?%b hd=%s, tl=[%a]@."
301
     *   keep_hd
302
     *   (Z3.Expr.to_string hd)
303
     * (Utils.fprintf_list ~sep:"; " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) tl
304
     *   ; *)
305
    if keep_hd then
306
      hd::tl
307
    else
308
      tl
309
  )
310
  
311
let check_sat ?(just_check=false) (l:guard) : bool * guard =
312
  (* Syntactic simplification *)
313
  (* Format.eprintf "Before simplify: %a@." pp_guard_list l; *)
314
  let l = simplify_neg_guard l in
315
  (* Format.eprintf "After simplify: %a@." pp_guard_list l; *)
316
  (* Format.eprintf "@[<v 2>Z3 check sat: [%a]@ " pp_guard_list l; *)
317
  let solver = Z3.Solver.mk_simple_solver !ctx in
318
  try (
319
    let zl =
320
      List.map (fun (e, posneg) ->
321
          let ze =
322
            match e with
323
            | IsInit -> is_init_z3e
324
            | Expr e -> expr_to_z3_expr e 
325
          in
326
          if posneg then
327
            ze
328
          else
329
            neg_ze ze
330
        ) l
331
    in
332
    (* Format.eprintf "Z3 exprs1: [%a]@ " (fprintf_list ~sep:",@ " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) zl; *)
333
    let zl = simplify zl in
334
       (* Format.eprintf "Z3 exprs2: [%a]@ " (fprintf_list ~sep:",@ " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) zl; *)
335
    let status_res = Z3.Solver.check solver zl in
336
    (* Format.eprintf "Z3 status: %s@ @]@. " (Z3.Solver.string_of_status status_res); *)
337
    match status_res with
338
    | Z3.Solver.UNSATISFIABLE -> false, []
339
    | _ -> (
340
      if false && just_check then
341
        true, l
342
      else
343
        let zl = goal_simplify zl in
344
        let l = zexpr_to_guard_list zl in
345
  (* Format.eprintf "@.@[<v 2>Check_Sat:@ before: %a@ after:
346
       %a@. Goal precise? %b/%b@]@.@. " * pp_guard_list l
347
       pp_guard_list l' * (Z3.Goal.is_precise goal) *
348
       (Z3.Goal.is_precise goal'); *)
349
  
350

    
351
        true, l
352
        
353
         
354
    )
355
         
356
  )
357
  with Zustre_common.UnknownFunction(id, msg) -> (
358
    report ~level:1 msg;
359
    true, l (* keeping everything. *)
360
  )
361
      
362
  
363

    
364

    
365
(**************************************************************)
366

    
367
  
368
let clean_sys sys =
369
  List.fold_left (fun accu (guards, updates) ->
370
      (*let guards' = clean_guard guards in*)
371
      let sat, guards' =  check_sat (List.map (fun (g, pn) -> Expr g, pn) guards) in
372
      (*Format.eprintf "Guard: %a@.Guard cleaned: %a@.Sat? %b@."
373
        (fprintf_list ~sep:"@ " (pp_guard_expr Printers.pp_expr))  guards
374
        (fprintf_list ~sep:"@ " (pp_guard_expr Printers.pp_expr))  guards'
375
        sat
376

    
377
      ;*)
378
        if sat then
379
        (List.map (fun (e, b) -> (deelem e, b)) guards', updates)::accu
380
      else
381
        accu
382
    )
383
    [] sys
384
  
385
let combine_guards ?(fresh=None) gl1 gl2 =
386
  (* Filtering out trivial cases. More semantics ones would have to be
387
     addressed later *)
388
  let check (gexpr, posneg) l =
389
    (* Format.eprintf "Checking %a=%b in %a@ "
390
     *   pp_elem gexpr
391
     *   posneg
392
     *   pp_guard_list l
393
     * ; *)
394
    (* Check if gepxr is part of l *)
395
   let sel_fun = select_elem gexpr in
396
   let ok, res =
397
     if List.exists sel_fun l then (
398
      (* Checking the guard value posneg *)
399
      let _, status = List.find sel_fun l in
400
      (* Format.eprintf "Found %a in %a. @ Checking status (%b).@ "
401
     *     pp_elem gexpr
402
     *     pp_guard_list l
403
     *     (status=posneg)
404
     * ; *)
405
      status=posneg, l
406
    )
407
    else (
408
      (* Format.eprintf "Not found.@ "; *)
409
      (* Valid: no overlap *)
410
      (* Individual checkat *)
411
      let ok, e = check_sat ~just_check:true [gexpr, posneg] in
412
      (* let ok, e = true, [gexpr, posneg] in (* TODO solve the issue with check_sat *) *)
413
      (* Format.eprintf "Check_sat? %b@ " ok; *)
414
      if ok then
415
        let l = e@l in
416
        let ok, l = check_sat ~just_check:true l in
417
        (* let ok, l = true, l in (* TODO solve the issue with check_sat *) *)
418
        ok, l 
419
      else
420
        false, []
421
     )
422
   in
423
   (* Format.eprintf "Check sat res: %a@ "
424
    *   pp_guard_list res; *)
425
   ok, res
426
  in
427
  let ok, gl =
428
    List.fold_left (
429
        fun (ok, l) g ->
430
        (* Bypass for negative output *)
431
        if not ok then false, []
432
        else
433
          check g l 
434
      ) (true, gl2) gl1
435
  in
436
  if ok then
437
    match fresh with
438
      None -> true, gl
439
    | Some fresh_g -> (
440
    (* Checking the fresh element *)
441
      check fresh_g gl
442
    )
443
  else
444
    false, []
445

    
446
(* DEBUG 
447
let combine_guards  ?(fresh=None) gl1 gl2 =
448
  true,
449
  (match fresh with None -> [] | Some (gexpr, posneg) -> [gexpr, posneg])@gl1@gl2
450
 *)
451
(* Encode "If gel1=posneg then gel2":
452
   - Compute the combination of guarded exprs in gel1 and gel2:
453
     - Each guarded_expr in gel1 is transformed as a guard: the
454
       expression is associated to posneg.
455
     - Existing guards in gel2 are concatenated to that list of guards
456
     - We keep expr in the ge of gel2 as the legitimate expression 
457
 *)
458
let concatenate_ge gel1 posneg gel2 =
459
  List.fold_left (
460
      fun accu (g2,e2) ->
461
      List.fold_left (
462
          fun accu (g1,e1) ->
463
           (* Format.eprintf "@[<v 2>Combining guards: (%a=%b) AND [%a] AND [%a]@ "
464
            *  pp_elem e1
465
            *  posneg
466
            *  pp_guard_list g1
467
            *  pp_guard_list g2; *)
468
            
469
          let ok, gl = combine_guards ~fresh:(Some(e1,posneg)) g1 g2 in
470
          (* Format.eprintf "@]@ Result is [%a]@ "
471
           *   pp_guard_list gl; *)
472
            
473
          if ok then
474
            (gl, e2)::accu
475
          else (
476
            
477
            accu
478
          )
479
        ) accu gel1
480
    ) [] gel2
481

    
482
let rec rewrite defs expr : guarded_expr list =
483
  let rewrite = rewrite defs in
484
  let res =
485
    match expr.expr_desc with
486
    | Expr_appl (id, args, None) ->
487
       let args = rewrite args in
488
       List.map (fun (guards, e) ->
489
           guards,
490
           Expr {expr with expr_desc = Expr_appl(id, deelem e, None)}
491
         ) args 
492
    | Expr_const _  -> [[], Expr expr]
493
    | Expr_ident id ->
494
       if Hashtbl.mem defs id then
495
         Hashtbl.find defs id
496
       else
497
         (* id should be an input *)
498
         [[], Expr expr]
499
    | Expr_ite (g, e1, e2) ->
500
       let g = rewrite g and
501
           e1 = rewrite e1 and
502
           e2 = rewrite e2 in
503
       (concatenate_ge g true e1)@
504
         (concatenate_ge g false e2)
505
    | Expr_merge (g, branches) ->
506
       assert false (* TODO: deal with merges *)
507
      
508
    | Expr_when (e, _, _) -> rewrite e
509
    | Expr_arrow _ -> [[], IsInit] (* At this point the only arrow should be true -> false *)
510
    | Expr_tuple el ->
511
       (* Each expr is associated to its flatten guarded expr list *)
512
       let gell = List.map rewrite el in
513
       (* Computing all combinations: we obtain a list of guarded tuple *)
514
       let rec aux gell : (guard * expr list) list =
515
         match gell with
516
         | [] -> assert false (* Not happening *)
517
         | [gel] -> List.map (fun (g,e) -> g, [deelem e]) gel
518
         | gel::getl ->
519
            let getl = aux getl in
520
            List.fold_left (
521
                fun accu (g,e) ->
522
                List.fold_left (
523
                    fun accu (gl, minituple) ->
524
                    let is_compat, guard_comb = combine_guards g gl in
525
                    if is_compat then
526
                      let new_gt : guard * expr list = (guard_comb, (deelem e)::minituple) in
527
                      new_gt::accu
528
                    else
529
                      accu
530
                    
531
                  ) accu getl
532
              ) [] gel
533
       in
534
       let gtuples = aux gell in
535
       (* Rebuilding the valid type: guarded expr list (with tuple exprs) *)
536
       List.map (fun (g,tuple) -> g, Expr {expr with expr_desc = Expr_tuple tuple}) gtuples
537
    | Expr_fby _
538
      | Expr_appl _
539
                  (* Should be removed by mormalization and inlining *)
540
      -> Format.eprintf "Pb expr: %a@.@?" Printers.pp_expr expr; assert false
541
    | Expr_array _ | Expr_access _ | Expr_power _
542
                                                (* Arrays not handled here yet *)
543
      -> assert false
544
    | Expr_pre _ -> (* Not rewriting mem assign *)
545
       assert false
546
  in
547
  (* Format.eprintf "Rewriting %a as [@[<v 0>%a@]]@ "
548
   *   Printers.pp_expr expr
549
   *   (Utils.fprintf_list ~sep:"@ "
550
   *        pp_guard_expr) res; *)
551
  res
552
and add_def defs vid expr =
553
  let vid_defs = rewrite defs expr in
554
  (* Format.eprintf "Add_def: %s = %a@. -> @[<v 0>%a@]@."
555
   *     vid
556
   *     Printers.pp_expr expr
557
   *     (
558
   *       (Utils.fprintf_list ~sep:"@ "
559
   *          pp_guard_expr)) vid_defs;  *)
560
  Hashtbl.add defs vid vid_defs
561

    
562
(* Takes a list of guarded exprs (ge) and a guard
563
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.
564

    
565
When a given ge doesn't mention positively or negatively such guards, it is duplicated in both lists *)
566
let split_mdefs elem (mdefs: guarded_expr list) =
567
  List.fold_left (
568
      fun (selected, left_out)
569
          ((guards, expr) as ge) ->
570
      (* select the element of guards that match the argument elem *)
571
      let sel, others_guards = List.partition (select_elem elem) guards in
572
      match sel with
573
      (* we extract the element from the list and add it to the
574
         appropriate list *)
575
      | [_, sel_status] ->
576
         if sel_status then
577
           (others_guards,expr)::selected, left_out
578
         else selected, (others_guards,expr)::left_out
579
      | [] -> (* no such guard exists, we have to duplicate the
580
              guard_expr in both lists *)
581
         ge::selected, ge::left_out
582
      | _ -> (
583
        Format.eprintf "@.Spliting list on elem %a.@.List:%a@."
584
          pp_elem elem
585
          pp_mdefs mdefs;
586
        assert false (* more then one element selected. Should
587
                          not happen , or trival dead code like if
588
                              x then if not x then dead code *)
589
      )
590
    ) ([],[]) mdefs
591
    
592
let split_mem_defs
593
      (elem: element)
594
      (mem_defs: (ident * guarded_expr list) list)
595
      :
596
      ((ident * mdef_t) list) * ((ident * mdef_t) list)
597
  
598
  =
599
  List.fold_right (fun (m,mdefs)
600
                       (accu_pos, accu_neg) ->
601
      let pos, neg =
602
        split_mdefs elem mdefs 
603
      in
604
      (m, pos)::accu_pos,
605
      (m, neg)::accu_neg
606
    ) mem_defs ([],[])
607

    
608

    
609
(* Split a list of mem_defs into init and step lists of guarded
610
   expressions per memory. *)
611
let split_init mem_defs =
612
  split_mem_defs IsInit mem_defs 
613

    
614
let pick_guard mem_defs : expr option =
615
  let gel = List.flatten (List.map snd mem_defs) in
616
  let gl = List.flatten (List.map fst gel) in
617
  let all_guards =
618
    List.map (
619
        (* selecting guards and getting rid of boolean *)
620
        fun (e,b) ->
621
        match e with
622
        | Expr e -> e
623
        | _ -> assert false
624
      (* should have been filtered out
625
                                      yet *)
626
      ) gl
627
  in
628
  (* TODO , one could sort by occurence and provided the most common
629
     one *)
630
  try
631
  Some (List.hd all_guards)  
632
  with _ -> None
633
(* Transform a list of variable * guarded exprs into a list of guarded pairs (variable, expressions)
634
*)
635
let rec build_switch_sys
636
          (mem_defs : (Utils.ident * guarded_expr list) list )
637
          prefix
638
        :
639
          ((expr * bool) list * (ident * expr) list ) list =
640
  (* if all mem_defs have empty guards, we are done, return prefix,
641
     mem_defs expr.
642

    
643
     otherwise pick a guard in one of the mem, eg (g, b) then for each
644
     other mem, one need to select the same guard g with the same
645
     status b, *)
646
  if List.for_all (fun (m,mdefs) ->
647
         (* All defs are unguarded *)
648
         match mdefs with
649
         | [[], _] -> true
650
         | _ -> false
651
       ) mem_defs
652
  then
653
    [prefix ,
654
     List.map (fun (m,gel) ->
655
         match gel with
656
         | [_,e] ->
657
            let e =
658
              match e with
659
              | Expr e -> e
660
              | _ -> assert false (* No IsInit expression *)
661
            in
662
            m,e
663
         | _ -> assert false
664
       ) mem_defs]
665
  else
666
    (* Picking a guard *)
667
    let elem_opt : expr option = pick_guard mem_defs in
668
    match elem_opt with
669
      None -> []
670
    | Some elem -> (
671
      let pos, neg =
672
        split_mem_defs
673
          (Expr elem)
674
          mem_defs
675
      in
676
      (* Special cases to avoid useless computations: true, false conditions *)
677
      match elem.expr_desc with
678
      | Expr_ident "true"  ->   build_switch_sys pos prefix
679
      | Expr_const (Const_tag tag) when tag = Corelang.tag_true
680
        ->   build_switch_sys pos prefix
681
      | Expr_ident "false" ->   build_switch_sys neg prefix
682
      | Expr_const (Const_tag tag) when tag = Corelang.tag_false 
683
        ->   build_switch_sys neg prefix
684
      | _ -> (* Regular case *)
685
         (* let _ = (
686
          *     Format.eprintf "Expr is %a@." Printers.pp_expr elem;
687
          *     match elem.expr_desc with
688
          *     | Expr_const _ -> Format.eprintf "a const@."
689
          *                     
690
          *     | Expr_ident _ -> Format.eprintf "an ident@."
691
          *     | _ -> Format.eprintf "something else@."
692
          *   )
693
          * in *)
694
         let clean l =
695
           let l = List.map (fun (e,b) -> (Expr e), b) l in
696
           let ok, l = check_sat l in
697
           let l = List.map (fun (e,b) -> deelem e, b) l in
698
           ok, l
699
         in
700
         let pos_prefix = (elem, true)::prefix in
701
         let ok_pos, pos_prefix = clean pos_prefix in         
702
         let neg_prefix = (elem, false)::prefix in
703
         let ok_neg, neg_prefix = clean neg_prefix in         
704
         
705
         (if ok_pos then build_switch_sys pos pos_prefix else [])
706
         @
707
           (if ok_neg then build_switch_sys neg neg_prefix else [])
708
    )
709

    
710

    
711
      
712
(* Take a normalized node and extract a list of switches: (cond,
713
   update) meaning "if cond then update" where update shall define all
714
   node memories. Everything as to be expressed over inputs or memories, intermediate variables are removed through inlining *)
715
let node_as_switched_sys consts (mems:var_decl list) nd =
716
  (* rescheduling node: has been scheduled already, no need to protect
717
     the call to schedule_node *)
718
  let nd_report = Scheduling.schedule_node nd in
719
  let schedule = nd_report.Scheduling_type.schedule in
720
  let eqs, auts = Corelang.get_node_eqs nd in
721
  assert (auts = []); (* Automata should be expanded by now *)
722
  let sorted_eqs = Scheduling.sort_equations_from_schedule eqs schedule in
723
  let defs : (ident,  guarded_expr list) Hashtbl.t = Hashtbl.create 13 in
724
  let add_def = add_def defs in
725

    
726
  let vars = Corelang.get_node_vars nd in
727
  (* Registering all locals variables as Z3 predicates. Will be use to
728
     simplify the expansion *) 
729
  let _ =
730
    List.iter (fun v ->
731
        let fdecl = Z3.FuncDecl.mk_func_decl_s
732
                      !ctx
733
                      v.var_id
734
                      []
735
                      (Zustre_common.type_to_sort v.var_type)
736
        in
737
        ignore (Zustre_common.register_fdecl v.var_id fdecl)
738
      ) vars
739
  in
740
  let _ =
741
    List.iter (fun c -> Hashtbl.add const_defs c.const_id c.const_value) consts
742
  in
743

    
744
  
745
  (* Registering node equations: identifying mem definitions and
746
     storing others in the "defs" hashtbl. *)
747
  let mem_defs =
748
    List.fold_left (fun accu eq ->
749
        match eq.eq_lhs with
750
        | [vid] ->
751
           (* Only focus on non memory definitions *)
752
           if not (List.exists (fun v -> v.var_id = vid) mems) then (
753
             report ~level:3 (fun fmt ->
754
                 Format.fprintf fmt "Registering variable %s@." vid);
755
             add_def vid eq.eq_rhs;
756
             accu
757
           )
758
           else
759
             (
760
               match eq.eq_rhs.expr_desc with
761
               | Expr_pre def_m ->
762
                  report ~level:3 (fun fmt ->
763
                      Format.fprintf fmt "Preparing mem %s@." vid);
764
                  (vid, rewrite defs def_m)::accu
765
               | _ -> assert false
766
             )
767
        | _ -> assert false (* should have been removed by normalization *)
768
      ) [] sorted_eqs
769
  in
770

    
771
  
772
  report ~level:2 (fun fmt -> Format.fprintf fmt "Printing out (guarded) memories definitions (may takes time)@.");
773
  (* Printing memories definitions *)
774
  report ~level:3
775
    (fun fmt ->
776
      Format.fprintf fmt
777
        "@[<v 0>%a@]@ "
778
        (Utils.fprintf_list ~sep:"@ "
779
           (fun fmt (m,mdefs) ->
780
             Format.fprintf fmt
781
               "%s -> [@[<v 0>%a@] ]@ "
782
               m
783
               (Utils.fprintf_list ~sep:"@ "
784
                  pp_guard_expr) mdefs
785
        ))
786
        mem_defs);
787
  (* Format.eprintf "Split init@."; *)
788
  let init_defs, update_defs =
789
    split_init mem_defs 
790
  in
791
  report ~level:3
792
    (fun fmt ->
793
      Format.fprintf fmt
794
        "@[<v 0>Init:@ %a@ Step@ %a@]@ "
795
        (Utils.fprintf_list ~sep:"@ "
796
           (fun fmt (m,mdefs) ->
797
             Format.fprintf fmt
798
               "%s -> @[<v 0>[%a@] ]@ "
799
               m
800
               (Utils.fprintf_list ~sep:"@ "
801
                  pp_guard_expr) mdefs
802
        ))
803
        init_defs
804
        (Utils.fprintf_list ~sep:"@ "
805
           (fun fmt (m,mdefs) ->
806
             Format.fprintf fmt
807
               "%s -> @[<v 0>[%a@] ]@ "
808
               m
809
               (Utils.fprintf_list ~sep:"@ "
810
                  pp_guard_expr) mdefs
811
        ))
812
        update_defs);
813
  (* Format.eprintf "Build init@."; *)
814

    
815
  let sw_init= 
816
    build_switch_sys init_defs []
817
  in
818
  (* Format.eprintf "Build step@."; *)
819
  let sw_sys =
820
    build_switch_sys update_defs []
821
  in
822
  clean_sys sw_init, clean_sys sw_sys
823
 
(1-1/4)