/python/CyclicSymbolicBoundedLTLEvaluation.py

https://github.com/dparalen/cycle-evaluation
Python | 151 lines | 118 code | 19 blank | 14 comment | 11 complexity | d6b2d8db9e52a3d441478d50cb3bd954 MD5 | raw file
  1. #!/usr/bin/env python
  2. # provides Cyclic Symbolic Bounded Evaluation to LTLExpression structures
  3. import LTLExpression as le
  4. import ExpressionEvaluation as ee
  5. from ExpressionEvaluation import NAryOperatorExpression as NOE
  6. from ExpressionEvaluation import UnaryOperatorExpression as UOE
  7. from ExpressionEvaluation import BinaryOperatorExpression as BOE
  8. import ExpressionStructure as ex
  9. import numpy as np
  10. import itertools as it
  11. import logging, os
  12. logger = logging.getLogger(__name__)
  13. # The operators define the bounded Cyclic semantics for an LTL structure
  14. # instance
  15. def _ltl_expressions(Expressions):
  16. return filter(lambda x: isinstance(x, le.LTL), Expressions)
  17. def _split_expressions(Expressions):
  18. # returns a tuple of ltl and other expressions found in Expressions
  19. ltl = _ltl_expressions(Expressions)
  20. ret = ltl, filter(lambda x: not isinstance(x, le.LTL), Expressions)
  21. logger.debug("_split_expressions: %s" % repr(ret))
  22. return ret
  23. def _ltl_expression(Expression):
  24. return isinstance(Expression, le.LTL)
  25. class And(le.And):
  26. def __call__(self, Expressions, position = 0, length = 0, loop = 0):
  27. ltl_expressions, other_expressions = _split_expressions(Expressions)
  28. return NOE(ee.And(), Expressions = map(lambda x: x(position,
  29. length, loop), ltl_expressions) + map(lambda x: EvaluationExpression(x,
  30. position), other_expressions))
  31. class Or(le.Or):
  32. def __call__(self, Expressions, position = 0, length = 0, loop = 0):
  33. ltl_expressions, other_expressions = _split_expressions(Expressions)
  34. return NOE(ee.Or(), Expressions = map(lambda x: x(position,
  35. length, loop), ltl_expressions) + map(lambda x: EvaluationExpression(x,
  36. position), other_expressions))
  37. class Not(le.Not):
  38. def __call__(self, Expression, position = 0, length = 0, loop = 0):
  39. if _ltl_expression(Expression):
  40. return UOE(ee.Not(), Expression(position,
  41. length, loop))
  42. return UOE(ee.Not(), EvaluationExpression(
  43. Expression, position))
  44. class Next(le.Next):
  45. def __call__(self, Expression, position = 0, length = 0, loop = 0):
  46. if _ltl_expression(Expression):
  47. if i < loop:
  48. # before loop
  49. return Expression(i + 1, position, loop)
  50. else:
  51. # in loop
  52. return Expression(loop + ((position - loop + 1)%(length - loop)),
  53. length, loop)
  54. return EvaluationExpression(Expression, position)
  55. class Globally(le.Globally):
  56. def __call__(self, Expression, position = 0, length = 0, loop = 0):
  57. if _ltl_expression(Expression):
  58. return NOE(ee.And(), Expressions = \
  59. [ Expression(j, length, loop) for j in xrange(
  60. min(position, loop), length)]
  61. )
  62. return NOE(ee.And(), Expressions = \
  63. [ EvaluationExpression(Expression, j) for j in xrange(
  64. min(position, loop), length)]
  65. )
  66. class Finally(le.Finally):
  67. def __call__(self, Expression, position = 0, length = 0, loop = 0):
  68. if _ltl_expression(Expression):
  69. return NOE(ee.Or(), Expressions = \
  70. [ Expression(j, length, loop) for j in xrange(
  71. min(position, loop), length)]
  72. )
  73. return NOE(ee.Or(), Expressions = \
  74. [ EvaluationExpression(Expression, j) for j in xrange(
  75. min(position, loop), length)]
  76. )
  77. # these classes define the __call__ method of LTL Expressions for the bounded
  78. # semantics evaluation. Each __call__ method should in turn produce an
  79. # ExpressionEvaluation instance with appropriate operator. The result of the
  80. # expansion may be evaluated on a data object by a result(data) call
  81. class LTLUnaryOperatorExpression(le.LTLUnaryOperatorExpression):
  82. def __call__(self, position = 0, length = 0, loop = 0):
  83. return self.Operator(self.Expression, position, length, loop)
  84. class LTLNAryOperatorExpression(le.LTLNAryOperatorExpression):
  85. def __call__(self, position = 0, length = 0, loop = 0):
  86. return self.Operator(self.Expressions, position, length, loop)
  87. class LTLBinaryOperatorExpression(le.LTLBinaryOperatorExpression):
  88. def __call__(self, position = 0, length = 0, loop = 0):
  89. return self.Operator(self.LeftExpression, self.RightExpression,
  90. position, length, loop)
  91. class EvaluationExpression(ee.Expression):
  92. # terminates the chain of position evaluation to remember data index to
  93. # call
  94. def __init__(self, Expression, position = 0, length = 0, loop = 0):
  95. logger.debug("EvaluationExpression: init: %s, %s, %s" % (str(Expression), position,
  96. length))
  97. self.position = position
  98. self.length = length
  99. self.Expression = Expression
  100. def __call__(self, data):
  101. logger.debug("EvaluationExpression: call: %s(%s)" % (str(self.Expression),
  102. data[...,self.position]))
  103. return self.Expression(data[...,self.position])
  104. def __repr__(self):
  105. return "(%s: %s)" % (str(self.Expression), self.position)
  106. class X:
  107. def __repr__(self):
  108. return "X"
  109. def OscillationFactory(expression):
  110. # G((expression => F(!expression)) && (!expression => F(expression)))
  111. fp = LTLUnaryOperatorExpression(Finally(), expression)
  112. ne = LTLUnaryOperatorExpression(Not(), expression)
  113. fn = LTLUnaryOperatorExpression(Finally(), ne)
  114. oe1 = LTLNAryOperatorExpression(Or(), Expressions = [ne, fn])
  115. oe2 = LTLNAryOperatorExpression(Or(), Expressions = [expression, fp])
  116. ae = LTLNAryOperatorExpression(And(), Expressions = [oe1, oe2])
  117. return LTLUnaryOperatorExpression(Globally(), ae)
  118. if __name__ == "__main__":
  119. logging.basicConfig(level=logging.DEBUG)
  120. data = np.array([1, 2, 3, 4, 5, 6, 7])
  121. gt = ee.Greater()
  122. x = X()
  123. n = ee.NameAtom(x)
  124. v = ee.ValueAtom(3)
  125. ne = ee.AtomExpression(n)
  126. ve = ee.AtomExpression(v)
  127. gte = BOE(gt, ne, ve)
  128. oe = OscillationFactory(gte)
  129. print "The expression: %s" % str(oe)
  130. ev = oe(0, 7, 5)
  131. print "The expression expanded: %s" % str(ev)
  132. print "Evaluation on data: %s" % str(ev(data))