| 1 |
4 |
tbourke |
(* $Id: clockexpression.sml 35 2008-04-01 02:55:38Z tbourke $ *)
|
| 2 |
|
|
|
| 3 |
|
|
structure ClockExpression :> CLOCK_EXPRESSION =
|
| 4 |
|
|
let structure E = Expression
|
| 5 |
|
|
and Env = Environment
|
| 6 |
|
|
and ECVT = ExpressionCvt
|
| 7 |
|
|
in struct
|
| 8 |
|
|
|
| 9 |
|
|
exception NonClockTerm
|
| 10 |
|
|
|
| 11 |
|
|
type symbol = Atom.atom
|
| 12 |
|
|
and symbolset = AtomSet.set
|
| 13 |
|
|
and var = Expression.var
|
| 14 |
|
|
|
| 15 |
|
|
datatype clockrel = Lt | Leq | Eq | Geq | Gt
|
| 16 |
|
|
|
| 17 |
|
|
datatype clockval = Simple of int
|
| 18 |
|
|
| Complex of E.expr
|
| 19 |
|
|
|
| 20 |
|
|
datatype clockterm = NonClock of E.expr
|
| 21 |
|
|
| CRel of E.var * clockrel * clockval
|
| 22 |
|
|
| CDiff of E.var * var * clockrel * clockval
|
| 23 |
|
|
|
| 24 |
|
|
datatype t = Term of clockterm
|
| 25 |
|
|
| And of t * t
|
| 26 |
|
|
| Or of t * t
|
| 27 |
|
|
|
| 28 |
31 |
tbourke |
val trueExpr = Term (NonClock E.trueExpr)
|
| 29 |
|
|
val falseExpr = Term (NonClock E.falseExpr)
|
| 30 |
|
|
|
| 31 |
4 |
tbourke |
(* shortcuts over Atom and AtomSet *)
|
| 32 |
18 |
tbourke |
infix <+ <- ++ <\ \ =:= ; open Symbol
|
| 33 |
4 |
tbourke |
|
| 34 |
|
|
local (*{{{1*)
|
| 35 |
|
|
(* TODO: fix smlnj-lib and replace with:
|
| 36 |
|
|
fun pad n = Iterate.iterate (fn s=> " " ^ s) n ""*)
|
| 37 |
|
|
fun pad n = let fun iter (s, 0) = s
|
| 38 |
|
|
| iter (s, n) = iter (s ^ " ", n - 1)
|
| 39 |
|
|
in iter ("", n) end
|
| 40 |
|
|
|
| 41 |
|
|
fun clkRelToStr Lt = " < " | clkRelToStr Leq = " <= "
|
| 42 |
|
|
| clkRelToStr Eq = " = " | clkRelToStr Geq = " >= "
|
| 43 |
|
|
| clkRelToStr Gt = " > "
|
| 44 |
|
|
|
| 45 |
|
|
fun clkValToStr (Simple i) = Int.toString i
|
| 46 |
|
|
| clkValToStr (Complex e) = "#" ^ ECVT.Expr.toString e ^ "#"
|
| 47 |
|
|
|
| 48 |
|
|
fun clkTermToStr (NonClock e) = "#" ^ ECVT.Expr.toString e ^ "#"
|
| 49 |
|
|
| clkTermToStr (CRel (s, rel, v)) = ECVT.Var.toString s ^
|
| 50 |
|
|
clkRelToStr rel ^
|
| 51 |
|
|
clkValToStr v
|
| 52 |
|
|
| clkTermToStr (CDiff (s1, s2, rel, v)) = ECVT.Var.toString s1 ^
|
| 53 |
|
|
" - " ^
|
| 54 |
|
|
ECVT.Var.toString s2 ^
|
| 55 |
|
|
clkRelToStr rel ^
|
| 56 |
|
|
clkValToStr v
|
| 57 |
|
|
in (*}}}1*)
|
| 58 |
|
|
fun clkToStr (n, Term t) = pad n ^ clkTermToStr t
|
| 59 |
|
|
| clkToStr (n, And (c1, c2)) = clkEToStr (n, "&&", c1, c2)
|
| 60 |
|
|
| clkToStr (n, Or (c1, c2)) = clkEToStr (n, "||", c1, c2)
|
| 61 |
|
|
|
| 62 |
|
|
and clkEToStr (n, s, c1, c2) = clkToStr (n + 1, c1)
|
| 63 |
|
|
^ "\n" ^ pad n ^ s ^ "\n"
|
| 64 |
|
|
^ clkToStr (n + 1, c2)
|
| 65 |
|
|
fun toString t = clkToStr (0, t)
|
| 66 |
|
|
end (* local *)
|
| 67 |
|
|
|
| 68 |
|
|
local (*{{{1*)
|
| 69 |
|
|
fun negRel Lt = Geq
|
| 70 |
|
|
| negRel Leq = Gt
|
| 71 |
|
|
| negRel Geq = Lt
|
| 72 |
|
|
| negRel Gt = Leq
|
| 73 |
|
|
| negRel Eq = raise Fail "ClockExpression.negRel: Cannot negate Eq"
|
| 74 |
|
|
|
| 75 |
|
|
fun negT (NonClock e) = Term (NonClock (E.negate e))
|
| 76 |
|
|
|
| 77 |
|
|
| negT (CRel (c, Eq, e)) = Or (Term (CRel (c, Lt, e)),
|
| 78 |
|
|
Term (CRel (c, Gt, e)))
|
| 79 |
|
|
| negT (CDiff (c1, c2, Eq, e)) = Or (Term (CDiff (c1, c2, Lt, e)),
|
| 80 |
|
|
Term (CDiff (c1, c2, Gt, e)))
|
| 81 |
|
|
|
| 82 |
|
|
| negT (CRel (c, rel, e)) = Term (CRel (c, negRel rel, e))
|
| 83 |
|
|
| negT (CDiff (c1, c2, rel, e)) = Term (CDiff (c1, c2, negRel rel, e))
|
| 84 |
|
|
in (*}}}1*)
|
| 85 |
|
|
fun negate (Term t) = negT t
|
| 86 |
|
|
| negate (And (e1, e2)) = Or (negate e1, negate e2)
|
| 87 |
|
|
| negate (Or (e1, e2)) = And (negate e1, negate e2)
|
| 88 |
|
|
end
|
| 89 |
|
|
|
| 90 |
|
|
fun getValFree (Simple _) = emptyset
|
| 91 |
|
|
| getValFree (Complex e) = E.getFreeNames e
|
| 92 |
|
|
|
| 93 |
|
|
val getVarFree = E.getFreeNames o E.VarExpr
|
| 94 |
|
|
|
| 95 |
19 |
tbourke |
fun getTermFree (NonClock e) = E.getFreeNames e
|
| 96 |
|
|
| getTermFree (CRel (s, _, cv)) = getVarFree s ++ getValFree cv
|
| 97 |
|
|
| getTermFree (CDiff (s1, s2, _, cv)) = getVarFree s1 ++ getVarFree s2
|
| 98 |
|
|
++ getValFree cv
|
| 99 |
|
|
|
| 100 |
4 |
tbourke |
fun getFree (And (c1, c2)) = getFree c1 ++ getFree c2
|
| 101 |
|
|
| getFree (Or (c1, c2)) = getFree c1 ++ getFree c2
|
| 102 |
19 |
tbourke |
| getFree (Term t) = getTermFree t
|
| 103 |
4 |
tbourke |
|
| 104 |
|
|
local (*{{{1*)
|
| 105 |
|
|
fun isClk (env, v) = case Env.findVarExprType env v
|
| 106 |
|
|
of SOME (E.CLOCK) => true
|
| 107 |
|
|
| NONE => raise NonClockTerm
|
| 108 |
|
|
| _ => false
|
| 109 |
|
|
|
| 110 |
|
|
fun isClkVar (env, E.VarExpr v) = isClk (env, v)
|
| 111 |
|
|
| isClkVar _ = false
|
| 112 |
|
|
|
| 113 |
29 |
tbourke |
fun containsClocks (env, expr) =
|
| 114 |
26 |
tbourke |
not (List.null (Env.filter (fn (env',e)=>isClkVar (env', e)) env expr))
|
| 115 |
4 |
tbourke |
|
| 116 |
|
|
fun notClk (env, e) = if containsClocks (env, e)
|
| 117 |
|
|
then raise NonClockTerm
|
| 118 |
|
|
else Term (NonClock e)
|
| 119 |
|
|
|
| 120 |
|
|
fun toRel E.LtOp = Lt | toRel E.LeOp = Leq
|
| 121 |
|
|
| toRel E.EqOp = Eq | toRel E.NeOp = raise NonClockTerm
|
| 122 |
|
|
| toRel E.GeOp = Geq | toRel E.GtOp = Gt
|
| 123 |
|
|
|
| 124 |
|
|
fun flipRel Lt = Gt | flipRel Leq = Geq
|
| 125 |
|
|
| flipRel Eq = Eq | flipRel Geq = Leq
|
| 126 |
|
|
| flipRel Gt = Lt
|
| 127 |
|
|
|
| 128 |
|
|
val toFlipRel = flipRel o toRel
|
| 129 |
|
|
|
| 130 |
|
|
fun toVal (E.IntCExpr i) = Simple i
|
| 131 |
|
|
| toVal e = Complex e
|
| 132 |
|
|
|
| 133 |
|
|
fun toVar (E.VarExpr v) = v
|
| 134 |
|
|
| toVar _ = raise Fail "toVar: bad call"
|
| 135 |
|
|
|
| 136 |
|
|
in (*}}}1*)
|
| 137 |
|
|
|
| 138 |
35 |
tbourke |
fun rename (r, clockexpr) = let
|
| 139 |
|
|
fun rCVar v = let val E.VarExpr v' = E.renameVar (r, E.VarExpr v)
|
| 140 |
|
|
in v' end
|
| 141 |
|
|
|
| 142 |
|
|
fun rCVal (s as Simple _) = s
|
| 143 |
|
|
| rCVal (Complex e) = Complex (E.renameVar (r, e))
|
| 144 |
|
|
|
| 145 |
|
|
fun rCTerm (NonClock e) = NonClock (E.renameVar (r, e))
|
| 146 |
|
|
| rCTerm (CRel (s, rel, cv)) = CRel (rCVar s, rel, rCVal cv)
|
| 147 |
|
|
| rCTerm (CDiff (s1, s2, rel, cv)) = CDiff (rCVar s1, rCVar s2,
|
| 148 |
|
|
rel, rCVal cv)
|
| 149 |
|
|
|
| 150 |
|
|
fun ren (Term t) = Term (rCTerm t)
|
| 151 |
|
|
| ren (And (c1, c2)) = And (ren c1, ren c2)
|
| 152 |
|
|
| ren (Or (c1, c2)) = Or (ren c1, ren c2)
|
| 153 |
|
|
|
| 154 |
|
|
in ren clockexpr end
|
| 155 |
|
|
|
| 156 |
|
|
local
|
| 157 |
|
|
fun addNameTypes xs = let
|
| 158 |
|
|
fun add ((n, _), s) = s <+ n
|
| 159 |
|
|
in foldl add emptyset xs end
|
| 160 |
|
|
in
|
| 161 |
|
|
fun ensureNoBindingConflict (rb, re) (b, e) = let
|
| 162 |
|
|
val rbn = addNameTypes rb
|
| 163 |
|
|
val bn = addNameTypes b
|
| 164 |
|
|
|
| 165 |
|
|
fun checkName ((n, ty), (bs, e, used)) =
|
| 166 |
|
|
if n <- rbn
|
| 167 |
|
|
then let val n' = getNewName (n, used)
|
| 168 |
|
|
in ((n', ty)::bs,
|
| 169 |
|
|
rename ({old=n, new=n'}, e),
|
| 170 |
|
|
used <+ n')
|
| 171 |
|
|
end
|
| 172 |
|
|
else ((n, ty)::bs, e, used)
|
| 173 |
|
|
|
| 174 |
|
|
val (b', e', _) = foldl checkName ([], e, rbn ++ bn) (rev b)
|
| 175 |
|
|
in (b', e') end
|
| 176 |
|
|
end (* local *)
|
| 177 |
|
|
|
| 178 |
4 |
tbourke |
(* raises NonClockTerm *)
|
| 179 |
|
|
fun fromExpr (usednames, env, expr) = let
|
| 180 |
|
|
|
| 181 |
|
|
val used = ref usednames
|
| 182 |
|
|
val forallbindings = ref ([] : (symbol * E.ty) list)
|
| 183 |
|
|
|
| 184 |
|
|
fun addForAllBinding (s, ty) = let
|
| 185 |
|
|
val newName = getNewName (s, !used)
|
| 186 |
|
|
in
|
| 187 |
|
|
used := (!used <+ newName);
|
| 188 |
|
|
forallbindings := (newName, ty) :: !forallbindings;
|
| 189 |
|
|
newName
|
| 190 |
|
|
end
|
| 191 |
|
|
|
| 192 |
|
|
fun conv (env, e as E.BinBoolExpr {left, bop, right, ...}) = let
|
| 193 |
|
|
(*{{{1*)
|
| 194 |
|
|
val (l, r) = (conv (env, left), conv (env, right))
|
| 195 |
|
|
in case (l, r, bop)
|
| 196 |
|
|
of (Term (NonClock le), Term (NonClock re), _)=> Term (NonClock e)
|
| 197 |
|
|
| (Term (NonClock le), _, E.ImplyOp) => Or (negate l, r)
|
| 198 |
|
|
| (_, _, E.ImplyOp) => raise NonClockTerm
|
| 199 |
|
|
| (_, _, E.OrOp) => Or (l, r)
|
| 200 |
|
|
| (_, _, E.AndOp) => And (l, r)
|
| 201 |
|
|
end
|
| 202 |
|
|
|
| 203 |
|
|
(* possibly: c1 - c2 {<,<=,==,>=,>} e *)
|
| 204 |
|
|
| conv (env, e as E.RelExpr {left=E.BinIntExpr
|
| 205 |
|
|
{left=lclk, bop=E.MinusOp, right=rclk, ...},
|
| 206 |
|
|
rel, right, ...}) =
|
| 207 |
|
|
if isClkVar (env, lclk) andalso isClkVar (env, rclk)
|
| 208 |
|
|
then Term (CDiff (toVar lclk, toVar rclk, toRel rel, toVal right))
|
| 209 |
|
|
else notClk (env, e)
|
| 210 |
|
|
|
| 211 |
|
|
| conv (env, e as E.RelExpr {right=E.BinIntExpr
|
| 212 |
|
|
{left=lclk, bop=E.MinusOp, right=rclk, ...},
|
| 213 |
|
|
rel, left, ...}) =
|
| 214 |
|
|
if isClkVar (env, lclk) andalso isClkVar (env, rclk)
|
| 215 |
|
|
then Term (CDiff (toVar lclk, toVar rclk, toFlipRel rel, toVal left))
|
| 216 |
|
|
else notClk (env, e)
|
| 217 |
|
|
|
| 218 |
|
|
(* possibly: c {<,<=,==,>=,>} e *)
|
| 219 |
|
|
| conv (env, e as E.RelExpr {left, rel, right, ...}) = let in
|
| 220 |
|
|
case (isClkVar (env, left), isClkVar (env, right))
|
| 221 |
|
|
of (true, true) => raise NonClockTerm
|
| 222 |
|
|
| (false, false) => Term (NonClock e)
|
| 223 |
|
|
| (true, false) => Term (CRel (toVar left,toRel rel,toVal right))
|
| 224 |
|
|
| (false, true) => Term (CRel (toVar right, toFlipRel rel,
|
| 225 |
|
|
toVal left))
|
| 226 |
|
|
end
|
| 227 |
|
|
|
| 228 |
|
|
| conv (env, e as E.VarExpr v) = if isClk (env, v) then raise NonClockTerm
|
| 229 |
|
|
else Term (NonClock e)
|
| 230 |
|
|
|
| 231 |
|
|
(* Guard must be side-effect free *)
|
| 232 |
|
|
| conv (env, E.UnaryModExpr _) = raise NonClockTerm
|
| 233 |
|
|
| conv (env, E.Deadlock _) = raise NonClockTerm
|
| 234 |
|
|
|
| 235 |
|
|
| conv (env, e as E.IntCExpr _) = Term (NonClock e)
|
| 236 |
|
|
| conv (env, e as E.BoolCExpr _) = Term (NonClock e)
|
| 237 |
|
|
| conv (env, e as E.AssignExpr _) = notClk (env, e)
|
| 238 |
|
|
| conv (env, e as E.NegExpr _) = notClk (env, e)
|
| 239 |
|
|
| conv (env, e as E.NotExpr _) = notClk (env, e)
|
| 240 |
|
|
| conv (env, e as E.BinIntExpr _) = notClk (env, e)
|
| 241 |
|
|
| conv (env, e as E.CallExpr {args, ...}) = notClk (env, e)
|
| 242 |
|
|
|
| 243 |
|
|
(* tested in Uppaal 4.0.2: (i==1)?(x>2):(x>3) //int i, clock x;
|
| 244 |
|
|
gives: incompatible arguments to inline if *)
|
| 245 |
|
|
| conv (env, e as E.CondExpr _) = notClk (env, e)
|
| 246 |
|
|
| conv (env, e as E.ForAllExpr {id,ty,expr,...}) = let
|
| 247 |
|
|
val env' = Env.addId Env.BoundScope ((id, ty), env)
|
| 248 |
|
|
in
|
| 249 |
|
|
if containsClocks (env', expr)
|
| 250 |
|
|
then let (* lift forall to top-level, i.e. make prenex
|
| 251 |
|
|
the usual proviso on names must be respected *)
|
| 252 |
|
|
val id' = addForAllBinding (id, ty)
|
| 253 |
|
|
in
|
| 254 |
|
|
conv (Env.addId Env.BoundScope ((id', ty), env),
|
| 255 |
|
|
E.renameVar ({old=id, new=id'}, expr))
|
| 256 |
|
|
end
|
| 257 |
|
|
else Term (NonClock e)
|
| 258 |
|
|
end
|
| 259 |
|
|
| conv (env, e as E.ExistsExpr _) = notClk (env, e)
|
| 260 |
|
|
(*}}}1*)
|
| 261 |
26 |
tbourke |
|
| 262 |
4 |
tbourke |
in (conv (env, expr), !forallbindings, !used) end
|
| 263 |
|
|
end (* local *)
|
| 264 |
|
|
|
| 265 |
|
|
local
|
| 266 |
|
|
(*{{{1*)
|
| 267 |
|
|
fun fromCRel Lt = E.LtOp | fromCRel Leq = E.LeOp
|
| 268 |
|
|
| fromCRel Geq = E.GeOp | fromCRel Gt = E.GtOp
|
| 269 |
|
|
| fromCRel Eq = E.EqOp
|
| 270 |
|
|
|
| 271 |
|
|
fun fromCVal (Simple i) = E.IntCExpr i
|
| 272 |
|
|
| fromCVal (Complex e) = e
|
| 273 |
|
|
|
| 274 |
|
|
fun fromClkT (NonClock e) = e
|
| 275 |
|
|
| fromClkT (CRel (v, rel, cv)) = E.RelExpr {left=E.VarExpr v,
|
| 276 |
|
|
rel=fromCRel rel,
|
| 277 |
|
|
right=fromCVal cv,
|
| 278 |
|
|
pos=E.nopos}
|
| 279 |
|
|
| fromClkT (CDiff (v1, v2, rel, cv)) = let
|
| 280 |
|
|
val d = E.BinIntExpr {left=E.VarExpr v1,
|
| 281 |
|
|
bop=E.MinusOp,
|
| 282 |
|
|
right=E.VarExpr v2,
|
| 283 |
|
|
pos=E.nopos}
|
| 284 |
|
|
in
|
| 285 |
|
|
E.RelExpr {left=d, rel=fromCRel rel,
|
| 286 |
|
|
right=fromCVal cv, pos=E.nopos}
|
| 287 |
|
|
end
|
| 288 |
|
|
(*}}}1*)
|
| 289 |
|
|
in
|
| 290 |
|
|
fun toExpr (t, fas) = let
|
| 291 |
|
|
fun toE (Term ct) = fromClkT ct
|
| 292 |
|
|
| toE (And (ce1, ce2)) = E.BinBoolExpr {left=toE ce1, bop=E.AndOp,
|
| 293 |
|
|
right=toE ce2, pos=E.nopos}
|
| 294 |
|
|
| toE (Or (ce1, ce2)) = E.BinBoolExpr {left=toE ce1, bop=E.OrOp,
|
| 295 |
|
|
right=toE ce2, pos=E.nopos}
|
| 296 |
|
|
fun wrapForall ((s, ty), e)=E.ForAllExpr {id=s,ty=ty,expr=e,pos=E.nopos}
|
| 297 |
|
|
|
| 298 |
|
|
in foldl wrapForall (toE t) fas end
|
| 299 |
|
|
end (* local *)
|
| 300 |
|
|
|
| 301 |
19 |
tbourke |
(* see tech. report: canswap predicate *)
|
| 302 |
|
|
fun conflictExists (sE, sA, psi) = let
|
| 303 |
|
|
exception ConflictingQuantifiers
|
| 304 |
4 |
tbourke |
|
| 305 |
19 |
tbourke |
fun termToPairs ct = let
|
| 306 |
|
|
val f = getTermFree ct
|
| 307 |
|
|
val e = AtomSet.intersection (f, sE)
|
| 308 |
|
|
val a = AtomSet.intersection (f, sA)
|
| 309 |
|
|
in
|
| 310 |
|
|
if not (AtomSet.isEmpty e) andalso not (AtomSet.isEmpty a)
|
| 311 |
|
|
then raise ConflictingQuantifiers else (e, a)
|
| 312 |
|
|
end
|
| 313 |
4 |
tbourke |
|
| 314 |
19 |
tbourke |
fun pairUnion ((e1,a1), (e2,a2)) = (e1 ++ e2, a1 ++ a2)
|
| 315 |
|
|
val emptyPair = (emptyset, emptyset)
|
| 316 |
4 |
tbourke |
|
| 317 |
19 |
tbourke |
fun findCommon ((e,a), (se,sa)) = let
|
| 318 |
|
|
val ei = if AtomSet.isEmpty a then se ++ e else se
|
| 319 |
|
|
val ai = if AtomSet.isEmpty e then sa ++ a else sa
|
| 320 |
|
|
in (ei, ai) end
|
| 321 |
4 |
tbourke |
|
| 322 |
19 |
tbourke |
val termPairs = map (fn cl=>map termToPairs cl) psi
|
| 323 |
|
|
(* [ [(E,A), ..., (E,A)], ..., [(E,A), ..., (E,A)] ] *)
|
| 324 |
|
|
val clausePairs = map (fn cl=>foldl pairUnion emptyPair cl) termPairs
|
| 325 |
|
|
(* [ (E,A), ..., (E,A) ] *)
|
| 326 |
|
|
|
| 327 |
|
|
val (sEf, sAf) = foldl findCommon emptyPair clausePairs
|
| 328 |
|
|
|
| 329 |
|
|
fun conflict ([], _) = false
|
| 330 |
|
|
| conflict ((e, a)::xs, (confE, confA)) =
|
| 331 |
|
|
if (AtomSet.isSubset (e, sEf) andalso AtomSet.isEmpty (a))
|
| 332 |
|
|
orelse (AtomSet.isSubset (a, sAf) andalso AtomSet.isEmpty (e))
|
| 333 |
|
|
then conflict (xs, (confE, confA))
|
| 334 |
|
|
else if not (AtomSet.isEmpty (AtomSet.intersection (e, confE)))
|
| 335 |
|
|
orelse not (AtomSet.isEmpty (AtomSet.intersection (a, confA)))
|
| 336 |
|
|
then true else conflict (xs, (confE ++ e, confA ++ a))
|
| 337 |
|
|
|
| 338 |
|
|
in conflict (clausePairs, (sEf, sAf)) end
|
| 339 |
|
|
handle ConflictingQuantifiers => true
|
| 340 |
|
|
|
| 341 |
4 |
tbourke |
local (*{{{1*)
|
| 342 |
|
|
datatype termchoice =
|
| 343 |
|
|
KeepLeft (* M |- (l && r) <=> M |- l *)
|
| 344 |
|
|
| KeepRight (* M |- (l && r) <=> M |- r *)
|
| 345 |
|
|
| MergeEqual (* M |- (le >= c && re <= c) <=> M |- (le = c) *)
|
| 346 |
|
|
| Contra (* M |- (l && r) <==> M |- false *)
|
| 347 |
|
|
| KeepBoth (* none of the above *)
|
| 348 |
|
|
|
| 349 |
|
|
(* Guards are integer-valued, but the clocks themselves are real-valued. *)
|
| 350 |
|
|
fun chooseFromSimpleRel ((Lt, i), r) = (case r
|
| 351 |
|
|
of (Lt , j) => if i <= j then KeepLeft else KeepRight
|
| 352 |
|
|
| (Leq, j) => if i <= j then KeepLeft else KeepRight
|
| 353 |
|
|
| (Eq , j) => if i > j then KeepRight else Contra
|
| 354 |
|
|
| (Geq, j) => if i > j then KeepBoth else Contra
|
| 355 |
|
|
| (Gt , j) => if i > j then KeepBoth else Contra
|
| 356 |
|
|
)
|
| 357 |
|
|
| chooseFromSimpleRel ((Leq, i), r) = (case r (*{{{2*)
|
| 358 |
|
|
of (Lt , j) => if i < j then KeepLeft else KeepRight
|
| 359 |
|
|
| (Leq, j) => if i < j then KeepLeft else KeepRight
|
| 360 |
|
|
| (Eq , j) => if i >= j then KeepRight else Contra
|
| 361 |
|
|
| (Geq, j) => if i = j then MergeEqual else
|
| 362 |
|
|
if i > j then KeepBoth else Contra
|
| 363 |
|
|
| (Gt , j) => if i > j then KeepBoth else Contra
|
| 364 |
|
|
)
|
| 365 |
|
|
| chooseFromSimpleRel ((Eq , i), r) = (case r
|
| 366 |
|
|
of (Lt , j) => if i < j then KeepLeft else Contra
|
| 367 |
|
|
| (Leq, j) => if i <= j then KeepLeft else Contra
|
| 368 |
|
|
| (Eq , j) => if i = j then KeepLeft else Contra
|
| 369 |
|
|
| (Geq, j) => if i >= j then KeepLeft else Contra
|
| 370 |
|
|
| (Gt , j) => if i > j then KeepLeft else Contra
|
| 371 |
|
|
)
|
| 372 |
|
|
| chooseFromSimpleRel ((Geq, i), r) = (case r
|
| 373 |
|
|
of (Lt , j) => if i < j then KeepBoth else Contra
|
| 374 |
|
|
| (Leq, j) => if i = j then MergeEqual else
|
| 375 |
|
|
if i < j then KeepBoth else Contra
|
| 376 |
|
|
| (Eq , j) => if i <= j then KeepRight else Contra
|
| 377 |
|
|
| (Geq, j) => if i > j then KeepLeft else KeepRight
|
| 378 |
|
|
| (Gt , j) => if i > j then KeepLeft else KeepRight
|
| 379 |
|
|
)
|
| 380 |
|
|
| chooseFromSimpleRel ((Gt , i), r) = (case r
|
| 381 |
|
|
of (Lt , j) => if i < j then KeepBoth else Contra
|
| 382 |
|
|
| (Leq, j) => if i < j then KeepBoth else Contra
|
| 383 |
|
|
| (Eq , j) => if i < j then KeepRight else Contra
|
| 384 |
|
|
| (Geq, j) => if i >= j then KeepLeft else KeepRight
|
| 385 |
|
|
| (Gt , j) => if i >= j then KeepLeft else KeepRight
|
| 386 |
|
|
(*}}}2*) )
|
| 387 |
|
|
|
| 388 |
|
|
(* Handle ((el1 ~1 er1) && (el2 ~2 er2)) with el1=er1, er1=er2: *)
|
| 389 |
|
|
fun chooseFromComplexRel (Lt , r) = (case r of Lt => KeepLeft
|
| 390 |
|
|
| Leq => KeepLeft
|
| 391 |
|
|
| _ => Contra)
|
| 392 |
|
|
| chooseFromComplexRel (Leq, r) = (case r of Geq => MergeEqual (*{{{2*)
|
| 393 |
|
|
| Gt => Contra
|
| 394 |
|
|
| _ => KeepRight)
|
| 395 |
|
|
| chooseFromComplexRel (Eq , r) = (case r of Lt => Contra
|
| 396 |
|
|
| Gt => Contra
|
| 397 |
|
|
| _ => KeepLeft)
|
| 398 |
|
|
| chooseFromComplexRel (Geq, r) = (case r of Leq => MergeEqual
|
| 399 |
|
|
| Lt => Contra
|
| 400 |
|
|
| _ => KeepRight)
|
| 401 |
|
|
| chooseFromComplexRel (Gt , r) = (case r of Gt => KeepLeft
|
| 402 |
|
|
| Geq => KeepLeft
|
| 403 |
|
|
(*}}}2*) | _ => Contra)
|
| 404 |
|
|
|
| 405 |
|
|
fun chooseTerm (CRel (c1, rel1, Simple i1),
|
| 406 |
|
|
CRel (c2, rel2, Simple i2))
|
| 407 |
|
|
= if E.varequal (c1, c2)
|
| 408 |
|
|
then chooseFromSimpleRel ((rel1, i1), (rel2, i2))
|
| 409 |
|
|
else KeepBoth
|
| 410 |
|
|
(*{{{2*)
|
| 411 |
|
|
| chooseTerm (CRel (c1, rel1, Complex e1),
|
| 412 |
|
|
CRel (c2, rel2, Complex e2))
|
| 413 |
|
|
= if E.varequal (c1, c2) andalso E.equal (e1, e2)
|
| 414 |
|
|
then chooseFromComplexRel (rel1, rel2)
|
| 415 |
|
|
else KeepBoth
|
| 416 |
|
|
|
| 417 |
|
|
| chooseTerm (CDiff (cl1, cr1, rel1, Simple i1),
|
| 418 |
|
|
CDiff (cl2, cr2, rel2, Simple i2))
|
| 419 |
|
|
= if E.varequal (cl1, cl2) andalso E.varequal (cr1, cr2)
|
| 420 |
|
|
then chooseFromSimpleRel ((rel1, i1), (rel2, i2))
|
| 421 |
|
|
else KeepBoth
|
| 422 |
|
|
|
| 423 |
|
|
| chooseTerm (CDiff (cl1, cr1, rel1, Complex e1),
|
| 424 |
|
|
CDiff (cl2, cr2, rel2, Complex e2))
|
| 425 |
|
|
= if E.varequal (cl1, cl2) andalso E.varequal (cr1, cr2)
|
| 426 |
|
|
andalso E.equal (e1, e2)
|
| 427 |
|
|
then chooseFromComplexRel (rel1, rel2) else KeepBoth
|
| 428 |
|
|
|
| 429 |
|
|
| chooseTerm (NonClock(E.BoolCExpr b),_)= if b then KeepRight else Contra
|
| 430 |
|
|
| chooseTerm (_,NonClock(E.BoolCExpr b)) = if b then KeepLeft else Contra
|
| 431 |
|
|
|
| 432 |
|
|
| chooseTerm (NonClock e1, NonClock e2)
|
| 433 |
|
|
= if E.isNegation (e1, e2) then Contra else KeepBoth
|
| 434 |
|
|
|
| 435 |
|
|
| chooseTerm _ = KeepBoth
|
| 436 |
|
|
(*}}}2*)
|
| 437 |
|
|
|
| 438 |
|
|
exception Contradiction
|
| 439 |
|
|
|
| 440 |
|
|
fun termAndConj (t, cs) = let
|
| 441 |
|
|
fun mergeEqual (CRel (c, _, v)) = CRel (c, Eq, v)
|
| 442 |
|
|
| mergeEqual (CDiff (c1, c2, _, v)) = CDiff (c1, c2, Eq, v)
|
| 443 |
|
|
|
| 444 |
|
|
fun tandc (rs, t, []) = t::rs
|
| 445 |
|
|
| tandc (rs, t, x::xs) = case chooseTerm (t, x)
|
| 446 |
|
|
of KeepLeft => tandc (rs, t, xs)
|
| 447 |
|
|
| KeepRight => List.revAppend (rs, x::xs)
|
| 448 |
|
|
| MergeEqual => List.revAppend (rs, mergeEqual t::xs)
|
| 449 |
|
|
| Contra => raise Contradiction
|
| 450 |
|
|
| KeepBoth => tandc (x::rs, t, xs)
|
| 451 |
|
|
in tandc ([], t, cs) end
|
| 452 |
|
|
|
| 453 |
|
|
fun conjAndConj and1 and2 = SOME (foldl termAndConj and2 and1)
|
| 454 |
|
|
handle Contradiction => NONE
|
| 455 |
|
|
|
| 456 |
|
|
fun andDNFLists (or1, or2) = let
|
| 457 |
|
|
fun throughSecond andx = let
|
| 458 |
|
|
val r = List.mapPartial (conjAndConj andx) or2
|
| 459 |
|
|
in if null r then NONE else SOME r end
|
| 460 |
|
|
in
|
| 461 |
|
|
List.concat (List.mapPartial throughSecond or1)
|
| 462 |
|
|
end
|
| 463 |
|
|
(*}}}1*)
|
| 464 |
|
|
in
|
| 465 |
|
|
fun toDNF (Term ct) = [[ct]]
|
| 466 |
|
|
| toDNF (Or (e1, e2)) = toDNF e1 @ toDNF e2
|
| 467 |
|
|
| toDNF (And (e1, e2)) = andDNFLists (toDNF e1, toDNF e2)
|
| 468 |
|
|
end (* local *)
|
| 469 |
|
|
|
| 470 |
|
|
fun fromDNF xxs = let
|
| 471 |
|
|
fun combineAnd (t, e) = And (e, Term t)
|
| 472 |
|
|
fun makeAnd [] = NONE
|
| 473 |
|
|
| makeAnd (x::xs) = SOME (foldl combineAnd (Term x) xs)
|
| 474 |
|
|
|
| 475 |
|
|
fun combineOr (e1, e2) = Or (e2, e1)
|
| 476 |
|
|
fun makeOr [] = Term (NonClock (E.falseExpr))
|
| 477 |
|
|
| makeOr (x::xs) = foldl combineOr x xs
|
| 478 |
|
|
|
| 479 |
|
|
fun trueExpr (Term (NonClock t)) = E.equal (t, E.trueExpr)
|
| 480 |
|
|
| trueExpr _ = false
|
| 481 |
|
|
|
| 482 |
|
|
val andclauses = List.mapPartial makeAnd xxs
|
| 483 |
|
|
|
| 484 |
|
|
in if List.exists trueExpr andclauses
|
| 485 |
|
|
then Term (NonClock (E.trueExpr))
|
| 486 |
|
|
else makeOr andclauses
|
| 487 |
|
|
end
|
| 488 |
|
|
|
| 489 |
|
|
fun andexpr (e1, e2) = fromDNF (toDNF (And (e1, e2)))
|
| 490 |
|
|
(* exploit the simplification built into toDNF *)
|
| 491 |
|
|
|
| 492 |
|
|
end
|
| 493 |
|
|
end
|
| 494 |
|
|
|