[/] [trunk/] [src/] [maketest/] [clkexprtrans.sml] - Blame information for rev 19

Line No. Rev Author Line
1 4 tbourke
(* $Id: clkexprtrans.sml 19 2007-11-27 00:20:37Z tbourke $ *)
2
 
3
(* TODO:
4
 *   - rename `paritition' to `constraint'
5
 *     more generally it is used to constrain the applicability of
6
 *     a set of transitions and is not affected by negation.
7
 *)
8
 
9
structure ClkExprTrans :> CLK_EXPR_TRANS = let
10
  structure E    = Expression
11
        and ClkE = ClockExpression
12
        and AT   = ActionTrans
13
        and Env  = Environment
14
        and ECVT = ExpressionCvt
15
in struct
16
 
17
  type expr      = Expression.expr
18
   and ty        = Expression.ty
19
   and symbol    = Atom.atom
20
   and symbolset = AtomSet.set
21
 
22
  exception SelectIdConflictsWithForAll of symbol list * symbol list
23
 
24 18 tbourke
  infix <+ <- ++ <\ \ =:= ; open Symbol
25 4 tbourke
 
26
  (* Invariants:
27
       - names contains all free names and those bound by select and forall
28
       - the sets of names of the select and forall lists are disjoint
29
   *)
30
  datatype t = CETrans of {actselect: (symbol * E.ty) list,(* SelectSub ids *)
31
                           gselect:   (symbol * E.ty) list,(* Guard selects *)
32
                           forall:    (symbol * E.ty) list,(* in prenex form *)
33
                           partition: Expression.expr,
34
                           guard:     ClkE.t,
35
                           action:    ActionTrans.actionsub list,
36
                           names:     symbolset}
37
 
38
  fun addNameTypes xs = let
39
      fun add ((n, _), s) = s <+ n
40
    in foldl add emptyset xs end
41
 
42
  local (*{{{1*)
43
    fun showCheckedActions []      = ""
44
      | showCheckedActions (AT.SelectSub s::es)   = "[#" ^ Atom.toString s ^ "#]" ^
45
                                                 showCheckedActions es
46
      | showCheckedActions (AT.FreeExprSub e::es) = "[" ^ ECVT.Expr.toString e ^ "]" ^
47
                                                 showCheckedActions es
48
    fun symtyToStr (s, ty) = Atom.toString s ^ " : " ^ ECVT.Ty.toString ty
49
    val symtyList = (ListFormat.fmt {init="(", sep=", ",
50
                                     final=")", fmt=symtyToStr})
51
  in (*}}}1*)
52
  fun toString (CETrans {actselect, gselect, forall,
53
                         partition, guard, action, names}) = let
54
    in
55
      "{actselect: " ^ symtyList actselect          ^ "\n" ^
56
      " gselect: "   ^ symtyList gselect            ^ "\n" ^
57
      " forall: "    ^ symtyList forall             ^ "\n" ^
58
      " partition: " ^ ECVT.Expr.toString partition ^ "\n" ^
59
      " guard: "     ^ ClkE.toString guard          ^ "\n" ^
60
      " action: "    ^ showCheckedActions action    ^ "\n" ^
61
      " names: "     ^ AtomSet.foldl
62
                       (fn (s, str)=> str ^ " " ^ Atom.toString s) "" names ^
63
      " }\n"
64
    end
65
  end (* local *)
66
 
67
(*
68
(*TODO: DEBUG ONLY! *)
69
fun showPartitions showitem partitions = let
70
    fun showClass c = let in
71
        TextIO.print "    class[\n";
72
        map showitem c;
73
        TextIO.print "    class]\n"
74
      end
75
 
76
    fun showPart p = let in
77
        TextIO.print "partition[\n";
78
        map showClass p;
79
        TextIO.print "partition]\n"
80
      end
81
  in app showPart partitions end
82
*)
83
 
84
  fun unionNames cetrans = let
85
      fun f (CETrans {names, ...}, m) = m ++ names
86
    in foldl f emptyset cetrans end
87
 
88
  fun addDisjointForalls newforall
89
      (CETrans {actselect, gselect, forall, partition, guard, action, names}) =
90
    let
91
      fun addAndCheck ((n, _), s) = if n <- s
92
                                    then raise Fail "addDisjointForalls"
93
                                    else s <+ n
94
    in
95
      CETrans {actselect=actselect,
96
               gselect=gselect,
97
               forall=newforall@forall,
98
               partition=partition,
99
               guard=guard,
100
               action=action,
101
               names=foldl addAndCheck names newforall}
102
    end
103
 
104
  fun fromATrans preenv (AT.ActTrans {selectids=sellist,
105
                                      actionsubs, guard, names}) =
106
    let
107
      val senv = List.foldl (Env.addId Env.SelectScope) preenv sellist
108
      val (guard, forall, used) = ClkE.fromExpr (names, senv, guard)
109
        (* Note: ClkE.fromExpr ensures:
110
         *         intersection(selectids, forall) = emptyset
111
         *       as names includes selectids.
112
         *)
113
      val actionNames = AT.addSelectSubNames actionsubs
114
 
115
      fun categorize ([], acts, gs) = (acts, gs)
116
        | categorize ((s as (n, _))::ss, acts, gs) =
117
            if n <- actionNames then categorize (ss, s::acts, gs)
118
                                else categorize (ss, acts, s::gs)
119
 
120
      val (actsels, gsels) = categorize (sellist, [], [])
121
    in
122
       CETrans {actselect=actsels,
123
                gselect=gsels,
124
                forall=forall,
125
                partition=E.trueExpr,
126
                guard=guard,
127
                action=actionsubs,
128
                names=used}
129
    end
130
 
131
 
132
  local (**)
133
    fun toBoundId (s, ty) = E.BoundId (s, ty, E.nopos)
134
  in (**)
135
  fun toTrans (CETrans {actselect, gselect, forall,
136
                        partition, guard, action, ...}) = let
137
      val preguard = ClkE.toExpr (guard, forall)
138
      val guard = if E.equal (partition, E.trueExpr) then preguard
139
                  else E.BinBoolExpr {left=partition, bop=E.AndOp,
140
                                      right=preguard, pos=E.nopos}
141
    in
142
      {selectids=map toBoundId (actselect @ gselect),
143
       actionsubs=map AT.actionsubToExpr action,
144
       guard=guard}
145
    end
146
  end (* local *)
147
 
148
  fun rename (CETrans {actselect, gselect, forall, partition,
149
                       guard, action, names}, r as {old, new}) =
150
    let
151
      val _ = if new <- names
152
              then raise Fail "rename: new name is already bound"
153
              else ()
154
 
155
      fun rsel (sv, sty) = if sv =:= old then (new, sty) else (sv, sty)
156
 
157
      fun renameAction (a as AT.SelectSub n) = if n =:= old
158
                                               then AT.SelectSub new else a
159
        | renameAction (AT.FreeExprSub e) = AT.FreeExprSub (E.renameVar (r, e))
160
    in
161
      CETrans {actselect=map rsel actselect,
162
               gselect=map rsel gselect,
163
               forall=map rsel forall,
164
               partition=E.renameVar (r, partition),
165
               guard=ClkE.rename (r, guard),
166
               action=map renameAction action,
167 18 tbourke
               names=(names <\ old) <+ new}
168 4 tbourke
    end
169
 
170
  local (*{{{1*)
171
    fun pairwiseIntersect ([], i)    = i
172
      | pairwiseIntersect (x::ys, i) = let
173
            fun withEach (y,i) = AtomSet.union (AtomSet.intersection(x,y), i)
174
          in pairwiseIntersect (ys, foldl withEach i ys) end
175
 
176
    fun makeTrans (actselects, potselects, potforalls, part, act) andx = let
177
        fun combineAnd (t, e) = ClkE.And (e, ClkE.Term t)
178
        fun makeAnd []      = ClkE.Term (ClkE.NonClock (E.falseExpr))
179
          | makeAnd (x::xs) = List.foldl combineAnd (ClkE.Term x) xs
180
 
181
        val e=makeAnd andx
182
        val exprNames=ClkE.getFree e
183
        val names=exprNames ++ AT.addActionNames act
184
 
185
        val forAlls=List.filter (fn (nm, _)=> nm<-exprNames) potforalls
186
 
187
      in (CETrans {actselect=actselects,
188
                   gselect=List.filter (fn (nm,_)=> nm<-names) potselects,
189
                   forall=forAlls,
190
                   partition=part,
191
                   guard=e,
192
                   action=act,
193
                   names=names}, addNameTypes forAlls)
194
      end
195
 
196
  in (*}}}1*)
197
  fun negate invariant (CETrans {actselect, gselect, forall,
198
                                 guard, partition, action, names}) =
199 19 tbourke
       let
200
         val g' = ClkE.negate guard
201
         val e  = case invariant of
202
                    ClkE.Term (ClkE.NonClock (E.BoolCExpr true)) => g'
203
                  | _ => ClkE.And (invariant, g')
204
         val dnf = ClkE.toDNF e
205
       in
206
         if ClkE.conflictExists (addNameTypes gselect, addNameTypes forall, dnf)
207
         then raise SelectIdConflictsWithForAll (#1 (ListPair.unzip gselect),
208
                                                 #1 (ListPair.unzip forall))
209
         else let
210
           val (trans, fall)=ListPair.unzip (map
211
                (makeTrans (actselect, forall, gselect, partition, action)) dnf)
212
                (* NB: forall and gselect are switched! (after having ensured
213
                 *     names are disjoint, and `non-conflicting') *)
214 4 tbourke
 
215 19 tbourke
           val splitFAlls=pairwiseIntersect (fall, emptyset)
216
         in
217
            if AtomSet.isEmpty splitFAlls then trans
218
            else (Util.warn ["forall bindings ",
219
                             ListFormat.fmt {init="(", sep=", ", final=")",
220
                                             fmt=Atom.toString}
221
                               (AtomSet.listItems splitFAlls),
222
                         " are shared across disjuncts: likely split zones"];
223
                  [CETrans {actselect=actselect,
224
                            gselect=forall,
225
                            forall=gselect,
226
                            partition=partition,
227
                            guard=e,
228
                            action=action,
229
                            names=names}])
230
            (* An improvement would be to split where possible,
231
               i.e. partition on shared foralls, transitive on overlap. *)
232
         end
233
       end
234 4 tbourke
  end (* local *)
235
 
236
  local (*{{{1*)
237
    fun equateActions ([], [], e) = e
238
      | equateActions (AT.FreeExprSub e1::ss1, AT.FreeExprSub e2::ss2, e) =
239
          if E.equal (e1, e2)
240
          then equateActions (ss1, ss2, e)
241
          else let
242
                 val eq = E.RelExpr {left=e1, rel=E.EqOp, right=e2,
243
                                     pos=E.nopos}
244
                 val e' = if E.equal (e, E.trueExpr) then eq
245
                          else E.BinBoolExpr {left=e, bop=E.AndOp, right=eq,
246
                                              pos=E.nopos}
247
               in equateActions (ss1, ss2, e') end
248
 
249
      | equateActions ((AT.SelectSub _)::ss1, (AT.SelectSub _)::ss2, e) =
250
                equateActions (ss1, ss2, e)
251
 
252
      | equateActions _ = raise Fail "equateActions: assumptions not met"
253
 
254
    fun distinguishActions (ss1, ss2, e) = let
255
        val ne = E.negate (equateActions (ss1, ss2, E.trueExpr))
256
      in
257
        if E.equal (e, E.trueExpr) then ne
258
        else E.BinBoolExpr {left=e, bop=E.AndOp, right=ne, pos=E.nopos}
259
      end
260
 
261
    fun equateClass (x::xs, e) = let
262
        fun equate (x', e) = equateActions (x, x', e)
263
      in foldl equate e xs end
264
 
265
    (* Form an expression that equates all members of the same class.
266
       e.g. given: [ [ [e1, e2], [f1, f2], [g1, g2] ],
267
                     [ [h1, h2], [i1, i2] ] ]
268
 
269
            returns:    (e1 == f1) && (e2 == f2)
270
                     && (e1 == g1) && (e2 == g2)
271
                     && (h1 == i1) && (h2 == i2)                    *)
272
    val equateClasses = foldl equateClass E.trueExpr
273
 
274
    (* Form an expression that distinguish classes across a partition,
275
       e.g. given: [ [ [e1, e2], [f1, f2], [g1, g2] ],
276
                     [ [h1, h2], [i1, i2] ]
277
                     [ [j1, j2], [k1, k2] ] ]
278
 
279
            returns: e && !((e1 == h1) && (e2 == h2))
280
                       && !((e1 == j1) && (e2 == j2))
281
                       && !((h1 == j1) && (h2 == j2))               *)
282
    fun distinguishClasses ([c], e) = e
283
      | distinguishClasses ((cRep::_)::cs, e) = let
284
            fun distinguish (oRep::_, e) = distinguishActions (cRep, oRep, e)
285
          in
286
            distinguishClasses (cs, foldl distinguish e cs)
287
          end
288
 
289
    (* Given a partition of action subscripts, form an expression that
290
       distinguishes the partition from others. *)
291
    fun formPartitionExpr part = distinguishClasses (part, equateClasses part)
292
 
293
    fun projActions partition = let
294
        fun projAction (CETrans {action, ...}) = action
295
      in map (fn class=> map projAction class) partition end
296
 
297
    fun markPartition (CETrans {actselect, gselect, forall, partition,
298
                                guard, action, names}, partexpr) =
299
        CETrans {actselect=actselect, gselect=gselect, forall=forall,
300
               partition=partexpr, guard=guard, action=action, names=names}
301
 
302
  fun renameConflicts ren args = let
303
  (* args: names_to_check * [] * expr_to_rename_in * conflict_set * usednames *)
304
    fun doit ([], done, g, conflicts, used) = (rev done, g, used)
305
      | doit ((s as (n, ty))::ss, done, g, conflicts, used) =
306
      if n <- conflicts
307
        then let val n' = getNewName (n, used)
308
                 val g' = ren ({old=n, new=n'}, g)
309
             in
310
               doit (ss, (n', ty)::done, g', conflicts, used <+ n')
311
             end
312
        else doit (ss, s::done, g, conflicts, used)
313
    in doit args end
314
 
315
    fun mergeTrans partexpr
316
        (CETrans {actselect=asel1, gselect=gsel1, forall=fa1,
317
                  partition=p1, guard=g1, action=act1, names=n1},
318
         CETrans {actselect=asel2, gselect=gsel2, forall=fa2,
319
                  partition=p2, guard=g2, action=act2, names=n2}) =
320
      let
321
        val asel1names = addNameTypes asel1
322
        val clash = asel1names ++ addNameTypes gsel1 ++ addNameTypes fa1
323
        val (gsel2', g2', names') = renameConflicts ClkE.rename
324
                                      (gsel2, [], g2, clash, n1++n2)
325
        val (fa2',   g2', names') = renameConflicts ClkE.rename
326
                                      (fa2, [], g2', clash, names')
327
      in
328
        CETrans {actselect=asel1
329
                     @ List.filter (fn (n,_)=> not (n<- asel1names)) asel2,
330
                     (* probably unnecessary after ATrans.ensureConsistency *)
331
                 gselect=gsel1 @ gsel2',
332
                 forall=fa1 @ fa2',
333
                 partition=partexpr,
334
                 guard=ClkE.Or (g1, g2'),
335
                 action=act1,
336
                 names=names'}
337
      end
338
 
339
  in (*}}}1*)
340
  (* Map each class in a partition to a single transition.
341
     All transitions are stamped with the same partition expression *)
342
  fun formPartitionReps [[]] = []
343
    | formPartitionReps trpart = let
344
          val partexpr = formPartitionExpr (projActions trpart)
345
          val mergeT = mergeTrans partexpr
346
          fun mergeClass (c::cs) = foldl mergeT (markPartition (c, partexpr)) cs
347
        in map mergeClass trpart end
348
  end (* local *)
349
 
350
end
351
end
352