def create_rps_game(n=1, eps=0): assert n >= 1 k = n - 1 delta = 60 / (6 * n) # TODO context = { 'xRock': create_rock(k=k, p1=True, delta=delta, eps=eps), 'xScissors': create_scissors(k=k, p1=True, delta=delta, eps=eps), 'xPaper': create_paper(k=k, p1=True, delta=delta, eps=eps), 'yRock': create_rock(k=k, p1=False, delta=delta), 'yScissors': create_scissors(k=k, p1=False, delta=delta), 'yPaper': create_paper(k=k, p1=False, delta=delta), } context = fn.walk_keys(stl.parse, context) context.update(CONTEXT) spec = G.Specs( obj=stl.parse('G(Rules)', H=H).inline_context(context), learned=stl.TOP, init=stl.parse("Init").inline_context(context), ) return G.Game(specs=spec, model=MODEL)
def test_params1(a, b, c): phi = stl.parse('G[a?, b?](x > c?)') assert {x.name for x in phi.params} == {'a?', 'b?', 'c?'} phi2 = phi.set_params({'a?': a, 'b?': b, 'c?': c}) assert phi2.params == set() assert phi2 == stl.parse(f'G[{a}, {b}](x > {c})')
def test_one_player_rps(): from magnum.examples.rock_paper_scissors import rps as g from magnum.examples.rock_paper_scissors import context from stl.boolean_eval import pointwise_sat res = encode_and_run(g) phi = g.spec_as_stl(discretize=False) dt = g.model.dt assert pointwise_sat(phi, dt=dt)(res.solution) not_rock = stl.parse('~(X(xRock))').inline_context(context) not_paper = stl.parse('~(X(xPaper))').inline_context(context) not_scissors = stl.parse('~(X(xScissors))').inline_context(context) g = bind(g).specs.learned.set(not_rock) res = encode_and_run(g) phi = g.spec_as_stl(discretize=False) dt = g.model.dt assert pointwise_sat(phi, dt=dt)(res.solution) g = bind(g).specs.learned.set(not_rock & not_paper) res = encode_and_run(g) phi = g.spec_as_stl(discretize=False) dt = g.model.dt assert pointwise_sat(phi, dt=dt)(res.solution) g = bind(g).specs.learned.set(not_rock & not_paper & not_scissors) res = encode_and_run(g) phi = g.spec_as_stl(discretize=False) assert res.solution is None
def test_inline_context_rigid(): phi = stl.parse('G(AP1)') phi2 = phi.inline_context(CONTEXT) assert phi2 == stl.parse('G(F(x > 4))') phi = stl.parse('G(AP2)') phi2 = phi.inline_context(CONTEXT) assert phi2 == stl.parse('G((F(x > 4)) U (F(x > 4)))')
def test_rps_counter_examples(): from magnum.examples.rock_paper_scissors import rps as g from stl.boolean_eval import pointwise_sat # Respond to Paper ces = [{'w': traces.TimeSeries([(0, 20 / 60)])}] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible assert pytest.approx(res.cost) == 10 phi = stl.parse('X((x >= 10) & (x <= 50))') assert pointwise_sat(phi, dt=g.model.dt)(res.solution) # Respond to Scissors and Paper ces.append({'w': traces.TimeSeries([(0, 40 / 60)])}) res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible assert pytest.approx(res.cost) == 10 phi = stl.parse('X((x >= 30) & (x <= 50))') assert pointwise_sat(phi, dt=g.model.dt)(res.solution) ces.append({'w': traces.TimeSeries([(0, 0)])}) res = milp.encode_and_run(g, counter_examples=ces) assert not res.feasible assert pytest.approx(res.cost) == 0 phi = stl.parse('X((x = 10) | (x = 30) | (x = 50))') assert pointwise_sat(phi, dt=g.model.dt)(res.solution) g = g.invert() res = milp.encode_and_run(g) assert res.feasible assert pytest.approx(res.cost) == 10 ces = [{'u': traces.TimeSeries([(0, 20 / 60)])}] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible assert pytest.approx(res.cost) == 10 ces = [{'u': traces.TimeSeries([(0, 40 / 60)])}] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible assert pytest.approx(res.cost) == 10 ces = [({'u': traces.TimeSeries([(0, 0)])})] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible ces = [({'u': traces.TimeSeries([(0, 1)])})] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible
def test_create_scissors(): psi = rpsg.create_scissors(k=0) phi0 = stl.parse('(x >= 30) & (x < 50)') assert phi0 == psi psi = rpsg.create_scissors(k=2, p1=False) phi0 = stl.parse('(y >= 30) & (y < 50)') phi1 = stl.parse('(y >= 90) & (y < 110)') phi2 = stl.parse('(y >= 150) & (y < 170)') assert phi0 | phi1 | phi2 == psi
def test_create_paper(): psi = rpsg.create_paper(k=0) phi0 = stl.parse('(x >= 10) & (x < 30)') assert phi0 == psi psi = rpsg.create_paper(k=2, p1=False) phi0 = stl.parse('(y >= 10) & (y < 30)') phi1 = stl.parse('(y >= 70) & (y < 90)') phi2 = stl.parse('(y >= 130) & (y < 150)') assert phi0 | phi1 | phi2 == psi
def create_rock(k=0, p1=True, delta=10, eps=0): itvls = create_intervals( k=k + 1, p1=p1, delta=delta, f1=lambda i: delta * (-1 + 6 * i) + eps, f2=lambda i: delta * (1 + 6 * i) - eps) # Hack: to match other rps encoding, we remove first and last one. name = 'x' if p1 else 'y' start = stl.parse(f'{name} < {delta - eps}') end = stl.parse(f'{name} >= {delta*((k+1)*6 - 1) + eps}') middle = stl.BOT if k == 0 else stl.orf(*itvls.args[1:-1]) return start | middle | end
def _encode_refuted(name_time): u, t = name_time val = refuted_input[u][dt * t] lo, hi = val - radius, val + radius phi = stl.BOT if lo > -1: phi |= stl.utils.next(stl.parse(f'{u} < {lo:f}'), i=t) if hi < 1: phi |= stl.utils.next(stl.parse(f'{u} > {hi:f}'), i=t) if phi == stl.BOT: return stl.TOP else: return phi
def test_scope(): dt = 0.3 phi = stl.parse('X(AP1)') assert stl.utils.scope(phi, dt) == 0.3 phi = stl.parse('X((X(AP1)) | (AP2))') assert stl.utils.scope(phi, dt) == 0.6 phi = stl.parse('G[0.3, 1.2](F[0.6, 1.5](AP1))') assert stl.utils.scope(phi, dt) == 1.2 + 1.5 phi = stl.parse('G[0.3, 1.2](F(AP1))') assert stl.utils.scope(phi, dt) == float('inf') phi = stl.parse('G[0.3, 1.2]((AP1) U (AP2))') assert stl.utils.scope(phi, dt) == float('inf')
def test_encode_refuted_rec(): refuted = { 'u1': traces.TimeSeries([(0, 0), (1, 1)]), 'u2': traces.TimeSeries([(0, 0.5)]) } phi = encode_refuted_rec(refuted, 0.2, [0]) psi1 = stl.parse('(u1 < -0.2) | (u1 > 0.2)') psi2 = stl.parse('(u2 < 0.3) | (u2 > 0.7)') assert phi == psi1 | psi2 psi3 = stl.parse('X(u1 < 0.8)') psi4 = stl.parse('(X(u2 < 0.3)) | (X(u2 > 0.7))') phi = encode_refuted_rec(refuted, 0.2, [1]) assert phi == psi3 | psi4 phi = encode_refuted_rec(refuted, 0.2, [0, 1]) assert set(phi.args) == set((psi1 | psi2 | psi3 | psi4).args)
def test_fastboolean_smoketest(): phi = stl.parse( '(G[0, 4](x > 0)) & ((F[2, 1](AP1)) | (AP2)) & (G[0,0](AP2))') stl_eval = stl.fastboolean_eval.pointwise_sat(phi) assert not stl_eval(x, 0) with raises(NotImplementedError): stl.fastboolean_eval.pointwise_sat(stl.ast.AST())
def create_intervals(f1, f2, k=0, p1=True, delta=10): name = 'x' if p1 else 'y' phi = stl.parse(f'({name} >= a?) & ({name} < b?)') def intvl_to_spec(itvl): return phi.set_params({'a?': itvl[0], 'b?': itvl[1]}) intervals = ((f1(i), f2(i)) for i in range(k + 1)) return stl.orf(*map(intvl_to_spec, intervals))
def test_create_rock(): psi = rpsg.create_rock(k=0) phi0 = stl.parse('(x < 10)') phi1 = stl.parse('(x >= 50)') assert phi0 | phi1 == psi psi = rpsg.create_rock(k=2, p1=False) phi0 = stl.parse('(y < 10)') phi1 = stl.parse('(y >= 50) & (y < 70)') phi2 = stl.parse('(y >= 110) & (y < 130)') phi3 = stl.parse('(y >= 170)') assert phi0 | phi1 | phi2 | phi3 == psi psi = rpsg.create_rock(k=0, eps=1) phi0 = stl.parse('(x < 9)') phi1 = stl.parse('(x >= 51)') assert phi0 | phi1 == psi
def test_discretize(): dt = 0.3 phi = stl.parse('X(AP1)') assert stl.utils.is_discretizable(phi, dt) phi2 = stl.utils.discretize(phi, dt) phi3 = stl.utils.discretize(phi2, dt) assert phi2 == phi3 phi = stl.parse('G[0.3, 1.2](F[0.6, 1.5](AP1))') assert stl.utils.is_discretizable(phi, dt) phi2 = stl.utils.discretize(phi, dt) phi3 = stl.utils.discretize(phi2, dt) assert phi2 == phi3 phi = stl.parse('G[0.3, 1.4](F[0.6, 1.5](AP1))') assert not stl.utils.is_discretizable(phi, dt) phi = stl.parse('G[0.3, 1.2](F(AP1))') assert not stl.utils.is_discretizable(phi, dt) phi = stl.parse('G[0.3, 1.2]((AP1) U (AP2))') assert not stl.utils.is_discretizable(phi, dt) phi = stl.parse('G[0.3, 0.6](~(F[0, 0.3](A)))') assert stl.utils.is_discretizable(phi, dt) phi2 = stl.utils.discretize(phi, dt, distribute=True) phi3 = stl.utils.discretize(phi2, dt, distribute=True) assert phi2 == phi3 assert phi2 == stl.parse( '(~((X(A)) ∨ (X(X(A))))) ∧ (~((X(X(A))) ∨ (X(X(X(A))))))') phi = stl.TOP assert stl.utils.is_discretizable(phi, dt) phi2 = stl.utils.discretize(phi, dt) phi3 = stl.utils.discretize(phi2, dt) assert phi2 == phi3 phi = stl.BOT assert stl.utils.is_discretizable(phi, dt) phi2 = stl.utils.discretize(phi, dt) phi3 = stl.utils.discretize(phi2, dt) assert phi2 == phi3
def test_eval_smoke_tests(phi): stl_eval9 = stl.boolean_eval.pointwise_sat(stl.ast.Next(phi)) stl_eval10 = stl.boolean_eval.pointwise_sat(~stl.ast.Next(phi)) assert stl_eval9(x, 0) != stl_eval10(x, 0) phi4 = stl.parse('~(AP4)') stl_eval11 = stl.boolean_eval.pointwise_sat(phi4) assert stl_eval11(x, 0) phi5 = stl.parse('G[0.1, 0.03](~(AP4))') stl_eval12 = stl.boolean_eval.pointwise_sat(phi5) assert stl_eval12(x, 0) phi6 = stl.parse('G[0.1, 0.03](~(AP5))') stl_eval13 = stl.boolean_eval.pointwise_sat(phi6) assert stl_eval13(x, 0) assert not stl_eval13(x, 0.4) phi7 = stl.parse('G(~(AP4))') stl_eval14 = stl.boolean_eval.pointwise_sat(phi7) assert stl_eval14(x, 0) phi8 = stl.parse('F(AP5)') stl_eval15 = stl.boolean_eval.pointwise_sat(phi8) assert stl_eval15(x, 0) phi9 = stl.parse('(AP1) U (AP2)') stl_eval16 = stl.boolean_eval.pointwise_sat(phi9) assert stl_eval16(x, 0) phi10 = stl.parse('(AP2) U (AP2)') stl_eval17 = stl.boolean_eval.pointwise_sat(phi10) assert not stl_eval17(x, 0) with raises(NotImplementedError): stl.boolean_eval.eval_stl(None, None)
def command_line(): parser = argparse.ArgumentParser() parser.add_argument('file', help='.stl file to slice') parser.add_argument('-T', '--thickness', default=1, type=float, help='thickness of each slice, in mm') parser.add_argument('-W', '--width', default=203, type=float, help='desired output width, in mm') parser.add_argument('-H', '--height', default=279, type=float, help='desired output height, in mm') parser.add_argument('-S', '--scale', type=float, help='scale by a fixed amount') parser.add_argument('-s', '--svg', default=False, action='store_true', help='Output an .svg file instead of a .ps file') parser.add_argument('-d', '--dxf', default=False, action='store_true', help='Output an .dxf file instead of a .ps file') parser.add_argument('-v', '--verbose', default=False, action='store_true') parser.add_argument('-q', '--quiet', default=False, action='store_true') args = parser.parse_args() if args.verbose: logger.setLevel(logging.DEBUG) elif args.quiet: logger.setLevel(0) else: logger.setLevel(logging.INFO) facets = parse(open(args.file, 'rb')) logger.info('Read %d facets from %s' % (len(facets), args.file)) if args.scale: width, height, minz, maxz, facets = scale_to_fit(facets, 0, 0, args.scale) else: width, height, minz, maxz, facets = scale_to_fit(facets, args.width, args.height) maxz_facets = z_sort_facets(facets) if args.svg: ext = '.svg' writer_class = svg.SvgWriter elif args.dxf: import dxf ext = '.dxf' writer_class = dxf.DxfWriter else: ext = '.ps' writer_class = ps.PsWriter out_filename = os.path.splitext(os.path.basename(args.file))[0] + ext layers = math.ceil(maxz - minz / args.thickness) writer = writer_class(out_filename, width, height, layers) z = minz layer = 1 while z <= maxz: i = 0 while maxz_facets[i][0] < z: i += 1 maxz_facets = maxz_facets[i:] logger.debug('Slicing layer %d', layer) lines = slice_shape_at(maxz_facets, z) paths = path_lines(lines) writer.write_layer_paths(paths, layer) z += args.thickness layer += 1 logger.info('Wrote %d layers to %s' % (layer - 1, out_filename)) writer.finish()
import hypothesis.strategies as st from hypothesis_cfg import ContextFreeGrammarStrategy import stl GRAMMAR = { 'phi': (('Unary', '(', 'phi', ')'), ('(', 'phi', ')', 'Binary', '(', 'phi', ')'), ('AP', ), ('LINEQ', ), ('⊥', ), ('⊤', )), 'Unary': (('~', ), ('G', 'Interval'), ('F', 'Interval'), ('X', )), 'Interval': (('', ), ('[1, 3]', )), 'Binary': ((' | ', ), (' & ', ), (' U ', ), (' -> ', ), (' <-> ', ), (' ^ ', )), 'AP': (('AP1', ), ('AP2', ), ('AP3', ), ('AP4', ), ('AP5', )), 'LINEQ': (('x > 4', ), ('y < 2', ), ('y >= 3', ), ('x + 2.0y >= 2', )), } SignalTemporalLogicStrategy = st.builds( lambda term: stl.parse(''.join(term)), ContextFreeGrammarStrategy(GRAMMAR, max_length=14, start='phi'))
import stl from stl.hypothesis import SignalTemporalLogicStrategy from hypothesis import given from pytest import raises CONTEXT = { stl.parse('AP1'): stl.parse('F(x > 4)'), stl.parse('AP2'): stl.parse('(AP1) U (AP1)'), stl.parse('AP3'): stl.parse('y < 4'), stl.parse('AP4'): stl.parse('y < 3'), stl.parse('AP5'): stl.parse('y + x > 4'), } APS = set(CONTEXT.keys()) @given(SignalTemporalLogicStrategy) def test_f_neg_or_canonical_form(phi): phi2 = stl.utils.f_neg_or_canonical_form(phi) phi3 = stl.utils.f_neg_or_canonical_form(phi2) assert phi2 == phi3 assert not any( isinstance(x, (stl.ast.G, stl.ast.And)) for x in phi2.walk()) def test_f_neg_or_canonical_form_not_implemented(): with raises(NotImplementedError): stl.utils.f_neg_or_canonical_form(stl.ast.AST()) def test_inline_context_rigid():
def _lineq(name_t): name, t = name_t return stl.utils.next(stl.parse("(u >= -1) & (u <= 1)"), i=t)
import stl from magnum import game as G import numpy as np # Setup the Model H = 3 model = G.Model(dt=1, vars=G.Vars(state=("x", ), input=("u", ), env=()), dyn=G.Dynamics(A=np.array([[0]]), B=np.array([[10]]), C=np.array([[]]))) # Setup the specification context = { stl.parse("Init"): stl.parse("x = 3"), stl.parse("ReachFive"): stl.parse("(F(x > 5)) & (G((x > 5) -> (F[0,2](x < 3))))", H=H), } spec = G.Specs( obj=stl.parse("ReachFive").inline_context(context), init=stl.parse("Init").inline_context(context), learned=stl.TOP, ) feasible_example = G.Game(specs=spec, model=model)
def test_implicit_validity_domain_rigid(): phi = stl.parse('(G[0, a?](x > b?)) & ((F(AP1)) | (AP2))') vals = {'a?': 3, 'b?': 20} stl_eval = stl.pointwise_sat(phi.set_params(vals)) oracle, order = stl.utils.implicit_validity_domain(phi, x) assert stl_eval(x, 0) == oracle([vals.get(k) for k in order])
def parse(x): return stl.parse(x, H=H)
vars=G.Vars(state=("x", "y"), input=("u", ), env=("w", )), dyn=G.Dynamics( A=np.array([[0, 0], [0, 0]]), B=np.array([60, 0]).reshape((2, 1)), C=np.array([0, 60]).reshape((2, 1)), )) def parse(x): return stl.parse(x, H=H) CONTEXT = { # Init parse("Init"): stl.parse('(x = 0) & (y = 0)'), # Rules parse("PaperBeatsRock"): parse("(yPaper) -> (~(xRock))"), parse("ScissorsBeatsPaper"): parse("(yScissors) -> (~(xPaper))"), parse("RockBeatsScissors"): parse("(yRock) -> (~(xScissors))"), parse("Rules"): parse("(PaperBeatsRock) & (ScissorsBeatsPaper) & (RockBeatsScissors)"), } def create_intervals(f1, f2, k=0, p1=True, delta=10): name = 'x' if p1 else 'y'
def _lineq(var_val): var, val = var_val return stl.parse(f"{var} = {val:f}")
def test_sugar_smoke(): stl.parse('(x) <-> (x)') stl.parse('(x) -> (x)') stl.parse('(x) ^ (x)')
vars=G.Vars(state=("x", "y"), input=("u", ), env=("w", )), dyn=G.Dynamics( A=np.array([[0, 0], [0, 0]]), B=np.array([60, 0]).reshape((2, 1)), C=np.array([0, 60]).reshape((2, 1)), )) def parse(x): return stl.parse(x, H=1) context = { # Init parse("Init"): stl.parse('(x = 0) & (y = 0)'), # Rock parse("xRock"): parse("(x < 9.5) | (x >= 50.5)"), parse("yRock"): parse("(y < 10) | (y >= 50)"), # Paper parse("xPaper"): parse("(x >= 10.5) & (x < 29.5)"), parse("yPaper"): parse("(y >= 10) & (y < 30)"), # Scissors parse("xScissors"):
def test_invertability(): phi = stl.parse('(G[0, 1](x > 4)) | (~(F[0, 1](y < 5)))') psi = stl.utils.discretize(phi, 1) smt_phi, store = encode(psi) psi2 = decode(smt_phi, store) assert psi == psi2
def test_callable_interface(): phi = stl.parse( '(G[0, 4](x > 0)) & ((F[2, 1](AP1)) | (AP2)) & (G[0,0](AP2))') assert not phi(x, 0)
import stl from magnum import game as G import numpy as np # Setup the Model H = 1 model = G.Model( dt=0.5, vars=G.Vars(state=("x", ), input=("u", ), env=("w", )), dyn=G.Dynamics(A=np.array([[0]]), B=np.array([[10]]), C=np.array([[-10]]))) # Setup the specification context = { stl.parse("Init"): stl.parse("x = 0"), stl.parse("ReachFive"): stl.parse("F(x > 5)", H=H), } spec = G.Specs( obj=stl.parse("ReachFive").inline_context(context), init=stl.parse("Init").inline_context(context), learned=stl.TOP, ) feasible_example = G.Game(specs=spec, model=model)
def test_linear_stl_lipschitz_rigid(): phi = stl.parse('(x + 3y - 4z < 3)') assert stl.utils.linear_stl_lipschitz(phi) == (8)
import stl from magnum import game as G import numpy as np # Setup the Model H = 3 model = G.Model( dt=1, vars=G.Vars(state=("x", ), input=("u", ), env=()), dyn=G.Dynamics(A=np.array([[0]]), B=np.array([[10]]), C=np.array([[]]))) # Setup the specification context = { stl.parse("Init"): stl.parse("x = 3"), stl.parse("ReachFive"): stl.parse("(F(x > 5)) & (G((x > 5) -> (F[0,2](x < 3))))", H=H), } spec = G.Specs( obj=stl.parse("ReachFive").inline_context(context), init=stl.parse("Init").inline_context(context), learned=stl.TOP, ) feasible_example = G.Game(specs=spec, model=model)
from magnum import game as G import numpy as np # Setup the Model H = 8 model = G.Model( dt=0.1, vars=G.Vars(state=("x1", "x2"), input=("u", ), env=("w1", "w2")), dyn=G.Dynamics( A=np.array([[0, 1], [-1, -2]]), B=np.array([[20], [0]]), C=np.array([[1, 0], [0, 1]]))) # Setup the specification context = { stl.parse("Init"): stl.parse("(x1 = 4.2) & (x2 = 0)"), stl.parse("Sys"): stl.parse("F[0, 3]((x1 >= 5) & (x1 <= 6))", H=1), } spec = G.Specs( obj=stl.parse("Sys").inline_context(context), init=stl.parse("Init").inline_context(context), learned=stl.TOP, ) g = G.Game(specs=spec, model=model)
def test_hash_stable(phi): assert hash(phi) == hash(stl.parse(str(phi)))
def test_invertable_repr(phi): event(str(phi)) assert str(phi) == str(stl.parse(str(phi)))
def parse(x): return stl.parse(x, H=model.H)