def test_params1(a, b, c): phi = mtfl.parse('G[a, b] x') assert {x.name for x in phi.params} == {'a', 'b'} phi2 = phi[{'a': a, 'b': b}] assert phi2.params == set() assert phi2 == mtfl.parse(f'G[{a}, {b}](x)')
def test_fuzzy_binop(con, a: float, b: float, c: float): x = prepare_values(a, b, c) assert mtfl.parse("(apa & apb)")(x, 0, logic=con) == con.tnorm([a, b]) assert mtfl.parse("(apa & apb & apc)")(x, 0, logic=con) \ == con.tnorm([a, b, c]) assert mtfl.parse("(apa | apb)")(x, 0, logic=con) == con.tconorm([a, b]) assert mtfl.parse("(apa | apb | apc)")(x, 0, logic=con) \ == con.tconorm([a, b, c])
def test_eval_regression_next_neg(): """From issue #219""" d = {"a": [(0, False), (1, True)]} f = mtfl.parse("(a & (X (~a)))") v = f(d, quantitative=False, dt=1, time=None) assert not f(d, quantitative=False, dt=1) assert min(t for t, _ in v) >= 0
def test_eval_regression_until_start(): """From issue #221""" x = { "ap1": [(0, True), (0.1, True), (0.2, False)], } phi = (mtfl.parse("(X TRUE W X TRUE)")) phi(x, 0, quantitative=False)
def test_eval_with_signal(): spec = mtfl.parse('F(above_three)') raw_data = signal([(0, 1), (1, 2), (2, 3)], start=0, end=10, tag='a') processed = raw_data.map(lambda val: val['a'] > 3, tag="above_three") assert not spec(processed, quantitative=False) assert spec(processed, quantitative=True) == 0
def test_scope(): dt = 0.3 phi = mtfl.parse('@ap1') assert utils.scope(phi, dt) == 0.3 phi = mtfl.parse('(@@ap1 | ap2)') assert utils.scope(phi, dt) == 0.6 phi = mtfl.parse('G[0.3, 1.2] F[0.6, 1.5] ap1') assert utils.scope(phi, dt) == 1.2 + 1.5 phi = mtfl.parse('G[0.3, 1.2] F ap1') assert utils.scope(phi, dt) == float('inf') phi = mtfl.parse('G[0.3, 1.2] (ap1 U ap2)') assert utils.scope(phi, dt) == float('inf')
def test_eval_regression_smoke1(): """From issue #215""" d2 = { 'a': [(0, True), (1, True), (3, True), (4, True), (5, False), (6, True)], 'b': [(0, False), (3, True)], } f2 = mtfl.parse('(a U[0,3] b)') f2(d2, quantitative=False)
def test_eval_comparison(): a = mtfl.parse("a") b = mtfl.parse("b") d = { "a": [(0, 5.), (1, 10.), (3, 0.), (4, 10.)], "b": [(0, 15.), (2, 5.), (4, 10.)], } i = a < b assert i(d, time=0, quantitative=False) assert i(d, time=1, quantitative=False) assert not i(d, time=2, quantitative=False) assert i(d, time=3, quantitative=False) assert not i(d, time=4, quantitative=False) i = a.eq(b) assert not i(d, time=0, quantitative=False) assert i(d, time=4, quantitative=False)
def test_eval_regression_timed_until(): """From issue #217""" x = { 'start': [(0, True), (200, False)], 'success': [(0, False), (300, True)] } phi = mtfl.parse('(~start U[0,120] success)') assert phi(x, time=200, quantitative=False, dt=1) y = { 'start': [(0, True), (1, False), (5, True), (6, True)], 'success': [(0, False), (20, True)] } phi1 = mtfl.parse('(start U[0,20] success)') assert phi1(y, time=6, quantitative=False, dt=1) z = { 'start': [(0, True), (200, False)], 'success': [(0, False), (300, True)] } phi2 = mtfl.parse('F[0,120]success') assert phi2(z, time=181, quantitative=False, dt=1)
def test_eval_smoke_tests(phi): assert mtfl.parse('~ap4')(x, 0, quantitative=False) assert mtfl.parse('G[0.1, 0.03] ~ap4')(x, 0, quantitative=False) phi6 = mtfl.parse('G[0.1, 0.03] ~ap5') assert phi6(x, 0, quantitative=False) assert phi6(x, 0.2, quantitative=False) assert mtfl.parse('G ~ap4')(x, 0, quantitative=False) assert mtfl.parse('F ap5')(x, 0, quantitative=False) assert mtfl.parse('(ap1 U ap2)')(x, 0, quantitative=False) assert not mtfl.parse('(ap2 U ap2)')(x, 0, quantitative=False)
def test_discretize(): dt = 0.3 phi = mtfl.parse('@ ap1') assert utils.is_discretizable(phi, dt) phi2 = utils.discretize(phi, dt) phi3 = utils.discretize(phi2, dt) assert phi2 == phi3 phi = mtfl.parse('G[0.3, 1.2] F[0.6, 1.5] ap1') assert utils.is_discretizable(phi, dt) phi2 = utils.discretize(phi, dt) phi3 = utils.discretize(phi2, dt) assert phi2 == phi3 phi = mtfl.parse('G[0.3, 1.4] F[0.6, 1.5] ap1') assert not utils.is_discretizable(phi, dt) phi = mtfl.parse('G[0.3, 1.2] F ap1') assert not utils.is_discretizable(phi, dt) phi = mtfl.parse('G[0.3, 1.2] (ap1 U ap2)') assert not utils.is_discretizable(phi, dt) phi = mtfl.parse('G[0.3, 0.6] ~F[0, 0.3] a') assert utils.is_discretizable(phi, dt) phi2 = utils.discretize(phi, dt, distribute=True) phi3 = utils.discretize(phi2, dt, distribute=True) assert phi2 == phi3 phi = mtfl.TOP assert utils.is_discretizable(phi, dt) phi2 = utils.discretize(phi, dt) phi3 = utils.discretize(phi2, dt) assert phi2 == phi3 phi = mtfl.BOT assert utils.is_discretizable(phi, dt) phi2 = utils.discretize(phi, dt) phi3 = utils.discretize(phi2, dt) assert phi2 == phi3
def test_walk(): phi = mtfl.parse('(([ ][0, 1] ap1 & < >[1,2] ap2) | (@ap1 U ap2))') assert len(list((~phi).walk())) == 18
def test_stablizing_repr(phi): for _ in range(10): phi, phi2 = mtfl.parse(str(phi)), phi assert phi == phi2
def test_output(self): P = World() w = Monitor() print("== Predicates test =====") w += ~P.operator.has_component w += P.operator.has_component w += ~P.operator.has_component w += P.operator.height.eq(5) w += P.operator.height < 42 w += P.operator.height <= 42 w += P.operator.height > 42 w += P.operator.height >= 42 w += P.operator.height.eq(P.constraint.maximum_height) w += P.operator.height < P.constraint.maximum_height w += (P.operator.height > 5) & (P.operator.height < P.constraint.maximum_height) assert len({P.operator.height, P.operator.height}) == 1 assert len({P.operator.height.eq(5), P.operator.height.eq(5)}) == 1 pprint(w.atoms()) print("== Trace insertion test =====") t = Trace() t[P.constraint.maximum_height] = (0, 30) t[P.operator.height] = (5, 42) t[P.operator.height] = (6, 5) t[P.operator.height] = (7, 30) t[P.constraint.maximum_height] = (8, 40) with pytest.raises(Exception): t[P.unknown] = (9, True) pprint({s: list(v.items()) for s, v in t.values.items()}) print("== Trace eval test =====") print("-- Dummy -----") p = mtfl.parse("dummy_predicate") print(p) print(w.evaluate(t, p)) print("-- Op Height == 5 -----") print((P.operator.height.eq(5))) print(t.project({P.operator.height})) print(w.evaluate(t, P.operator.height.eq(5), time=None)) print("== Enum predicates =====") class DummyEnum(enum.Enum): FOO = enum.auto() BAR = enum.auto() BAZ = enum.auto() n = ~(P.operator.position.eq(DummyEnum.FOO)) f = P.operator.position.eq(DummyEnum.FOO) t[P.operator.position] = (0, DummyEnum.FOO) t[P.operator.position] = (10, DummyEnum.BAR) print(n) print(w.evaluate(t, n, time=None)) print(f) print(w.evaluate(t, f, time=None)) print("== Test comparisons =====") i = Monitor() j = Monitor() i += P.props.height.eq(5) j += P.props.height.eq(5) assert i == j i += P.props.height < 5 assert i != j print(hash(i), i) print(hash(j), j) print("== Test merging =====") i = Monitor() j = Monitor() i += P.height.eq(5) j += P.height < 5 print(i, j) assert (j | i).atoms() == j.atoms() j += P.height <= 5 assert (j | i).atoms() == i.atoms() i += P.speed >= 4 assert (j | i).atoms() == i.atoms() print("== Merge =====") u = Monitor() u += P.operator.height > 180 v = Monitor() v += P.operator.position.eq(DummyEnum.FOO) w = Monitor() w += P.operator.position.eq(DummyEnum.FOO) w += P.operator.height < 170 print(w.atoms()) print((v | w).atoms()) print((w | v).atoms()) print((u | v).atoms()) s = Trace() s[P.operator.height] = (0, 170) s[P.operator.height] = (1, 160) print("s:", {n: list(v) for n, v in s.values.items()}) t = Trace() t[P.position] = (0, DummyEnum.BAR) t[P.operator.height] = (0, 210) t[P.position] = (5, DummyEnum.BAZ) t[P.position] = (9, DummyEnum.FOO) print("t:", t.values) print("s|t:", list((s | t).values[P.operator.height].items())) print("t|s:", list((t | s).values[P.operator.height].items())) print("== Out-of-order updates =====") w = Monitor() w += P.operator.height < 170 t = Trace() t[P.operator.height] = (0, 210) t[P.operator.height] = (10, 160) t[P.operator.height] = (50, 200) t[P.operator.height] = (25, 42) t[P.operator.height] = (5, 10) print(list(t.values[P.operator.height].items())) print("== Overlapping updates =====") t = Trace() t[P.operator.height] = (0, 210) t[P.operator.height] = (5, 10) t[P.operator.height] = (10, 160) t[P.operator.height] = (25, 42) t[P.operator.height] = (50, 200) print(list(t.values[P.operator.height].items())) t[P.height] = (0, 100) t[P.height] = (11, 161) t[P.height] = (49, 40) t[P.height] = (50, 150) print(list(t.values[P.height].items())) print(t)
def test_sugar_smoke(): mtfl.parse('(x <-> x)') mtfl.parse('(x -> x)') mtfl.parse('(x ^ x)')
def test_fuzzy_neg(con, a: float, b: float, c: float): x = prepare_values(a, b, c) assert mtfl.parse("~ap1")(x, 0, logic=con) == con.negation(a)
def test_fuzzy_implies(con, a: float, b: float, c: float): x = prepare_values(a, b, c) assert mtfl.parse("(apa -> apb)")(x, 0, logic=con) == con.implication(a, b)
def test_fuzzy_always(con, a: float, b: float, c: float): x = prepare_values(a, b, c) assert mtfl.parse("G ap1")(x, 0, logic=con) == con.tnorm([a, b, c])
import mtfl from mtfl import utils from mtfl import sugar from mtfl.hypothesis import MetricTemporalLogicStrategy from hypothesis import given CONTEXT = { 'ap1': mtfl.parse('x'), 'ap2': mtfl.parse('(y U z)'), 'ap3': mtfl.parse('x'), 'ap4': mtfl.parse('(x -> y -> z)'), 'ap5': mtfl.parse('(ap1 <-> y <-> z)'), } APS = set(CONTEXT.keys()) def test_inline_context_rigid(): phi = mtfl.parse('G ap1') assert phi[CONTEXT] == mtfl.parse('G x') phi = mtfl.parse('G ap5') assert phi[CONTEXT] == mtfl.parse('G(x <-> y <-> z)') @given(MetricTemporalLogicStrategy) def test_inline_context(phi): assert not (APS & phi[CONTEXT].atomic_predicates) @given(MetricTemporalLogicStrategy, MetricTemporalLogicStrategy)
import hypothesis.strategies as st from hypothesis_cfg import ContextFreeGrammarStrategy import mtfl GRAMMAR = { 'phi': (('Unary', 'phi'), ('(', 'phi', 'Binary', 'phi', ')'), ('AP', ), ('FALSE', ), ('TRUE', )), 'Unary': (('~', ), ('G', 'Interval'), ('F', 'Interval'), ('X', )), 'Interval': (('', ), ('[1, 3]', )), 'Binary': ( (' | ', ), (' & ', ), (' -> ', ), (' <-> ', ), (' ^ ', ), (' U ', ), ), 'AP': (('ap1', ), ('ap2', ), ('ap3', ), ('ap4', ), ('ap5', )), } MetricTemporalLogicStrategy = st.builds( lambda term: mtfl.parse(''.join(term)), ContextFreeGrammarStrategy(GRAMMAR, max_length=14, start='phi'))
def test_inline_context_rigid(): phi = mtfl.parse('G ap1') assert phi[CONTEXT] == mtfl.parse('G x') phi = mtfl.parse('G ap5') assert phi[CONTEXT] == mtfl.parse('G(x <-> y <-> z)')