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

Line No. Rev Author Line
1 4 tbourke
(* $Id: clkexprtrans.sml 43 2008-05-09 06:44:05Z 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 fromATrans preenv (AT.ActTrans {selectids=sellist,
89
                                      actionsubs, guard, names}) =
90
    let
91
      val senv = List.foldl (Env.addId Env.SelectScope) preenv sellist
92
      val (guard, forall, used) = ClkE.fromExpr (names, senv, guard)
93
        (* Note: ClkE.fromExpr ensures:
94
         *         intersection(selectids, forall) = emptyset
95
         *       as names includes selectids.
96
         *)
97
      val actionNames = AT.addSelectSubNames actionsubs
98
 
99
      fun categorize ([], acts, gs) = (acts, gs)
100
        | categorize ((s as (n, _))::ss, acts, gs) =
101
            if n <- actionNames then categorize (ss, s::acts, gs)
102
                                else categorize (ss, acts, s::gs)
103
 
104
      val (actsels, gsels) = categorize (sellist, [], [])
105
    in
106
       CETrans {actselect=actsels,
107
                gselect=gsels,
108
                forall=forall,
109
                partition=E.trueExpr,
110
                guard=guard,
111
                action=actionsubs,
112
                names=used}
113
    end
114
 
115
 
116
  local (**)
117 43 tbourke
    fun toBoundId (s, ty) = E.BoundId (s, ty)
118 4 tbourke
  in (**)
119
  fun toTrans (CETrans {actselect, gselect, forall,
120
                        partition, guard, action, ...}) = let
121
      val preguard = ClkE.toExpr (guard, forall)
122
      val guard = if E.equal (partition, E.trueExpr) then preguard
123 43 tbourke
                  else E.BinBoolExpr {left=partition,bop=E.AndOp,right=preguard}
124 4 tbourke
    in
125
      {selectids=map toBoundId (actselect @ gselect),
126
       actionsubs=map AT.actionsubToExpr action,
127
       guard=guard}
128
    end
129
  end (* local *)
130
 
131
  fun rename (CETrans {actselect, gselect, forall, partition,
132
                       guard, action, names}, r as {old, new}) =
133
    let
134
      val _ = if new <- names
135
              then raise Fail "rename: new name is already bound"
136
              else ()
137
 
138
      fun rsel (sv, sty) = if sv =:= old then (new, sty) else (sv, sty)
139
 
140
      fun renameAction (a as AT.SelectSub n) = if n =:= old
141
                                               then AT.SelectSub new else a
142
        | renameAction (AT.FreeExprSub e) = AT.FreeExprSub (E.renameVar (r, e))
143
    in
144
      CETrans {actselect=map rsel actselect,
145
               gselect=map rsel gselect,
146
               forall=map rsel forall,
147
               partition=E.renameVar (r, partition),
148
               guard=ClkE.rename (r, guard),
149
               action=map renameAction action,
150 18 tbourke
               names=(names <\ old) <+ new}
151 4 tbourke
    end
152
 
153
  local (*{{{1*)
154
    fun pairwiseIntersect ([], i)    = i
155
      | pairwiseIntersect (x::ys, i) = let
156
            fun withEach (y,i) = AtomSet.union (AtomSet.intersection(x,y), i)
157
          in pairwiseIntersect (ys, foldl withEach i ys) end
158
 
159 34 tbourke
    fun makeTrans cinv_fall
160
                  (actselects, potselects, potforalls, part, act)
161
                  andx =
162
      let
163 4 tbourke
        fun combineAnd (t, e) = ClkE.And (e, ClkE.Term t)
164
        fun makeAnd []      = ClkE.Term (ClkE.NonClock (E.falseExpr))
165
          | makeAnd (x::xs) = List.foldl combineAnd (ClkE.Term x) xs
166
 
167
        val e=makeAnd andx
168
        val exprNames=ClkE.getFree e
169 34 tbourke
        val names=exprNames ++ AT.addActionNames act ++ addNameTypes cinv_fall
170 4 tbourke
 
171
        val forAlls=List.filter (fn (nm, _)=> nm<-exprNames) potforalls
172 34 tbourke
      in
173
         (CETrans {actselect=actselects,
174 4 tbourke
                   gselect=List.filter (fn (nm,_)=> nm<-names) potselects,
175 34 tbourke
                   forall=forAlls @ cinv_fall,
176 4 tbourke
                   partition=part,
177
                   guard=e,
178
                   action=act,
179 34 tbourke
                   names=names},
180
          addNameTypes (forAlls @ cinv_fall))
181 4 tbourke
      end
182
 
183
  in (*}}}1*)
184 34 tbourke
  fun negate (cinv_fall, cinv)
185
             (cet as CETrans {actselect, gselect, forall, guard,
186
                              partition, action, names}) =
187 19 tbourke
       let
188
         val g' = ClkE.negate guard
189 34 tbourke
         val e  = case cinv of
190 19 tbourke
                    ClkE.Term (ClkE.NonClock (E.BoolCExpr true)) => g'
191 34 tbourke
                  | _ => ClkE.And (cinv, g')
192 19 tbourke
         val dnf = ClkE.toDNF e
193 34 tbourke
 
194
         val _ = Util.debugVeryDetailed (fn()=>["* CETrans.negate before:\n",
195
                                                toString cet])
196
 
197
         (* Check the assumption of disjointness: *)
198
         fun addAndCheck ((n, _), s) = if n <- s
199
                                       then raise Fail "addDisjointForalls"
200
                                       else s <+ n
201
         val _ = foldl addAndCheck (ClkE.getFree g') cinv_fall
202 19 tbourke
       in
203
         if ClkE.conflictExists (addNameTypes gselect, addNameTypes forall, dnf)
204
         then raise SelectIdConflictsWithForAll (#1 (ListPair.unzip gselect),
205
                                                 #1 (ListPair.unzip forall))
206
         else let
207
           val (trans, fall)=ListPair.unzip (map
208 34 tbourke
                (makeTrans cinv_fall
209
                           (actselect, forall, gselect, partition, action))
210
                dnf)
211 19 tbourke
                (* NB: forall and gselect are switched! (after having ensured
212
                 *     names are disjoint, and `non-conflicting') *)
213 4 tbourke
 
214 34 tbourke
           val _ = Util.debugVeryDetailed (fn()=>
215
                     "* CETrans.negate after (&& with invariant):\n"
216
                     ::map toString trans)
217
 
218 19 tbourke
           val splitFAlls=pairwiseIntersect (fall, emptyset)
219
         in
220
            if AtomSet.isEmpty splitFAlls then trans
221
            else (Util.warn ["forall bindings ",
222
                             ListFormat.fmt {init="(", sep=", ", final=")",
223
                                             fmt=Atom.toString}
224
                               (AtomSet.listItems splitFAlls),
225 35 tbourke
                         " are shared across disjuncts: possible split zones"];
226 19 tbourke
                  [CETrans {actselect=actselect,
227
                            gselect=forall,
228 34 tbourke
                            forall=gselect @ cinv_fall,
229 19 tbourke
                            partition=partition,
230
                            guard=e,
231
                            action=action,
232 34 tbourke
                            names=names ++ addNameTypes cinv_fall}])
233 19 tbourke
            (* An improvement would be to split where possible,
234
               i.e. partition on shared foralls, transitive on overlap. *)
235
         end
236
       end
237 4 tbourke
  end (* local *)
238
 
239
  local (*{{{1*)
240
    fun equateActions ([], [], e) = e
241
      | equateActions (AT.FreeExprSub e1::ss1, AT.FreeExprSub e2::ss2, e) =
242
          if E.equal (e1, e2)
243
          then equateActions (ss1, ss2, e)
244
          else let
245 43 tbourke
                 val eq = E.RelExpr {left=e1, rel=E.EqOp, right=e2}
246 4 tbourke
                 val e' = if E.equal (e, E.trueExpr) then eq
247 43 tbourke
                          else E.BinBoolExpr {left=e, bop=E.AndOp, right=eq}
248 4 tbourke
               in equateActions (ss1, ss2, e') end
249
 
250
      | equateActions ((AT.SelectSub _)::ss1, (AT.SelectSub _)::ss2, e) =
251
                equateActions (ss1, ss2, e)
252
 
253
      | equateActions _ = raise Fail "equateActions: assumptions not met"
254
 
255
    fun distinguishActions (ss1, ss2, e) = let
256
        val ne = E.negate (equateActions (ss1, ss2, E.trueExpr))
257
      in
258
        if E.equal (e, E.trueExpr) then ne
259 43 tbourke
        else E.BinBoolExpr {left=e, bop=E.AndOp, right=ne}
260 4 tbourke
      end
261
 
262
    fun equateClass (x::xs, e) = let
263
        fun equate (x', e) = equateActions (x, x', e)
264
      in foldl equate e xs end
265
 
266
    (* Form an expression that equates all members of the same class.
267
       e.g. given: [ [ [e1, e2], [f1, f2], [g1, g2] ],
268
                     [ [h1, h2], [i1, i2] ] ]
269
 
270
            returns:    (e1 == f1) && (e2 == f2)
271
                     && (e1 == g1) && (e2 == g2)
272
                     && (h1 == i1) && (h2 == i2)                    *)
273
    val equateClasses = foldl equateClass E.trueExpr
274
 
275
    (* Form an expression that distinguish classes across a partition,
276
       e.g. given: [ [ [e1, e2], [f1, f2], [g1, g2] ],
277
                     [ [h1, h2], [i1, i2] ]
278
                     [ [j1, j2], [k1, k2] ] ]
279
 
280
            returns: e && !((e1 == h1) && (e2 == h2))
281
                       && !((e1 == j1) && (e2 == j2))
282
                       && !((h1 == j1) && (h2 == j2))               *)
283
    fun distinguishClasses ([c], e) = e
284
      | distinguishClasses ((cRep::_)::cs, e) = let
285
            fun distinguish (oRep::_, e) = distinguishActions (cRep, oRep, e)
286
          in
287
            distinguishClasses (cs, foldl distinguish e cs)
288
          end
289
 
290
    (* Given a partition of action subscripts, form an expression that
291
       distinguishes the partition from others. *)
292
    fun formPartitionExpr part = distinguishClasses (part, equateClasses part)
293
 
294
    fun projActions partition = let
295
        fun projAction (CETrans {action, ...}) = action
296
      in map (fn class=> map projAction class) partition end
297
 
298
    fun markPartition (CETrans {actselect, gselect, forall, partition,
299
                                guard, action, names}, partexpr) =
300
        CETrans {actselect=actselect, gselect=gselect, forall=forall,
301
               partition=partexpr, guard=guard, action=action, names=names}
302
 
303
  fun renameConflicts ren args = let
304
  (* args: names_to_check * [] * expr_to_rename_in * conflict_set * usednames *)
305
    fun doit ([], done, g, conflicts, used) = (rev done, g, used)
306
      | doit ((s as (n, ty))::ss, done, g, conflicts, used) =
307
      if n <- conflicts
308
        then let val n' = getNewName (n, used)
309
                 val g' = ren ({old=n, new=n'}, g)
310
             in
311
               doit (ss, (n', ty)::done, g', conflicts, used <+ n')
312
             end
313
        else doit (ss, s::done, g, conflicts, used)
314
    in doit args end
315
 
316
    fun mergeTrans partexpr
317
        (CETrans {actselect=asel1, gselect=gsel1, forall=fa1,
318
                  partition=p1, guard=g1, action=act1, names=n1},
319
         CETrans {actselect=asel2, gselect=gsel2, forall=fa2,
320
                  partition=p2, guard=g2, action=act2, names=n2}) =
321
      let
322
        val asel1names = addNameTypes asel1
323
        val clash = asel1names ++ addNameTypes gsel1 ++ addNameTypes fa1
324
        val (gsel2', g2', names') = renameConflicts ClkE.rename
325
                                      (gsel2, [], g2, clash, n1++n2)
326
        val (fa2',   g2', names') = renameConflicts ClkE.rename
327
                                      (fa2, [], g2', clash, names')
328
      in
329
        CETrans {actselect=asel1
330
                     @ List.filter (fn (n,_)=> not (n<- asel1names)) asel2,
331
                     (* probably unnecessary after ATrans.ensureConsistency *)
332
                 gselect=gsel1 @ gsel2',
333
                 forall=fa1 @ fa2',
334
                 partition=partexpr,
335
                 guard=ClkE.Or (g1, g2'),
336
                 action=act1,
337
                 names=names'}
338
      end
339
 
340
  in (*}}}1*)
341
  (* Map each class in a partition to a single transition.
342
     All transitions are stamped with the same partition expression *)
343
  fun formPartitionReps [[]] = []
344
    | formPartitionReps trpart = let
345
          val partexpr = formPartitionExpr (projActions trpart)
346
          val mergeT = mergeTrans partexpr
347
          fun mergeClass (c::cs) = foldl mergeT (markPartition (c, partexpr)) cs
348
        in map mergeClass trpart end
349
  end (* local *)
350
 
351
end
352
end
353