def setUp(self): self.f_un = GRSpec(env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y",sys_safety=["y -> X(!y)","!y -> X(y)"], sys_prog="y && x") self.dcounter = GRSpec(sys_vars={"y": (0,5)}, sys_init=["y=0"], sys_prog=["y=0", "y=5"])
def setUp(self): self.check_realizable = lambda x: slugs.synthesize(x) is not None self.synthesize = slugs.synthesize self.f_un = GRSpec(env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y", sys_safety=["y -> X(!y)", "!y -> X(y)"], sys_prog="y && x", moore=False, plus_one=False, qinit='\A \E') self.f = GRSpec( env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y", sys_prog=["y & x", "!y"], moore=False, plus_one=False, ) self.dcounter = GRSpec(sys_vars={"y": (0, 5)}, sys_init=["y=0"], sys_prog=["y=0", "y=5"], moore=False, plus_one=False, qinit='\A \E')
def setUp(self): self.f = GRSpec(env_vars={"x"}, sys_vars={"y"}, env_init=["x"], sys_safety=["y"], env_prog=["!x", "x"], sys_prog=["y&&!x"]) self.triv = GRSpec(env_vars=["x"], sys_vars=["y"], env_init=["x && !x"]) self.empty = GRSpec()
def setUp(self): self.f_un = GRSpec( env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y", sys_safety=["y -> X(!y)", "!y -> X(y)"], sys_prog="y && x") self.dcounter = GRSpec(sys_vars={"y": (0, 5)}, sys_init=["y=0"], sys_prog=["y=0", "y=5"])
def test_or(self): g = GRSpec(env_vars={"z"}, env_prog=["!z"]) h = self.f | g assert len(h.env_vars) == 2 and h.env_vars.has_key("z") assert len(h.env_prog) == len(self.f.env_prog)+1 and "!z" in h.env_prog # Domain mismatch on system variable y g.sys_vars = {"y": (0,5)} nt.assert_raises(ValueError, self.f.__or__, g) # Domain mismatch on environment variable x g.sys_vars = dict() g.env_vars["x"] = (0,3) nt.assert_raises(ValueError, self.f.__or__, g)
def eventually_to_gr1(p, aux='aux'): """Convert C{<> p} to GR(1). GR(1) form:: !(aux) && [](aux -> X aux) && []<>(aux) && []( (!p && !aux) -> X!(aux) ) @type p: str @param aux: name to use for auxiliary variable @type aux: str @rtype: L{GRSpec} """ a = aux a0 = a p = _paren(p) a = _paren(a) v = tx.check_var_name_conflict(p, a0) sys_vars = v | {a0} sys_init = {'!(' + a + ')'} sys_safe = {'(!' + p + ' && !' + a + ') -> X !' + a, a + ' -> X ' + a} sys_prog = {a} return GRSpec(sys_vars=sys_vars, sys_init=sys_init, sys_safety=sys_safe, sys_prog=sys_prog)
class GRSpec_test: def setUp(self): self.f = GRSpec(env_vars={"x"}, sys_vars={"y"}, env_init=["x"], sys_safety=["y"], env_prog=["!x", "x"], sys_prog=["y&&!x"]) self.triv = GRSpec(env_vars=["x"], sys_vars=["y"], env_init=["x && !x"]) self.empty = GRSpec() def tearDown(self): self.f = None def test_sym_to_prop(self): original_env_vars = copy.copy(self.f.env_vars) original_sys_vars = copy.copy(self.f.sys_vars) self.f.sym_to_prop({"x":"bar", "y":"uber||cat"}) assert self.f.env_vars == original_env_vars and self.f.sys_vars == original_sys_vars assert self.f.env_prog == ["!(bar)", "(bar)"] and self.f.sys_prog == ["(uber||cat)&&!(bar)"] def test_or(self): g = GRSpec(env_vars={"z"}, env_prog=["!z"]) h = self.f | g assert len(h.env_vars) == 2 and h.env_vars.has_key("z") assert len(h.env_prog) == len(self.f.env_prog)+1 and "!z" in h.env_prog # Domain mismatch on system variable y g.sys_vars = {"y": (0,5)} nt.assert_raises(ValueError, self.f.__or__, g) # Domain mismatch on environment variable x g.sys_vars = dict() g.env_vars["x"] = (0,3) nt.assert_raises(ValueError, self.f.__or__, g) def test_to_canon(self): # Fragile! assert self.f.to_canon() == "((x) && []<>(!x) && []<>(x)) -> ([](y) && []<>(y&&!x))" # N.B., for self.triv, to_canon() returns a formula missing # the assumption part not because it detected that the # assumption is false, but rather the guarantee is empty (and # thus interpreted as being "True"). assert self.triv.to_canon() == "True" assert self.empty.to_canon() == "True" def test_init(self): assert len(self.f.env_vars) == 1 and len(self.f.sys_vars) == 1 assert self.f.env_vars["x"] == "boolean" and self.f.sys_vars["y"] == "boolean"
def setUp(self): self.f_un = GRSpec(env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y", sys_safety=["y -> X(!y)", "!y -> X(y)"], sys_prog="y && x", moore=False, plus_one=False, qinit='\A \E') self.dcounter = GRSpec(sys_vars={"y": (0, 5)}, sys_init=["y=0"], sys_prog=["y=0", "y=5"], moore=False, plus_one=False, qinit='\A \E')
def setUp(self): self.check_realizable = jtlv.check_realizable self.synthesize = jtlv.synthesize self.f_un = GRSpec(env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y", sys_safety=["y -> X(!y)", "!y -> X(y)"], sys_prog="y && x") self.f = GRSpec(env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y", sys_prog=["y & x", "!y"]) self.dcounter = GRSpec(sys_vars={"y": (0, 5)}, sys_init=["y=0"], sys_prog=["y=0", "y=5"])
def hash_question_mark_test(): specs = GRSpec(env_vars={'w': ['low', 'medium', 'high']}, sys_vars={'a': (0, 2)}, env_init=['w="low"'], env_safety=['(a=1) -> ((w="low") || (w="medium"))'], env_prog=['(w="high")'], sys_init=['a=2'], sys_safety=['a=2'], sys_prog=['a=2']) with nt.assert_raises(ValueError): jtlv.synthesize(specs)
class basic_test: def setUp(self): self.f_un = GRSpec(env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y",sys_safety=["y -> X(!y)","!y -> X(y)"], sys_prog="y && x") self.dcounter = GRSpec(sys_vars={"y": (0,5)}, sys_init=["y=0"], sys_prog=["y=0", "y=5"]) def tearDown(self): self.f_un = None self.dcounter = None def test_check_syntax(self): assert gr1cint.check_syntax(REFERENCE_SPECFILE) assert not gr1cint.check_syntax("foo") def test_to_gr1c(self): assert gr1cint.check_syntax(self.f_un.to_gr1c() ) assert gr1cint.check_syntax(self.dcounter.to_gr1c() ) def test_check_realizable(self): assert not gr1cint.check_realizable(self.f_un) self.f_un.sys_safety = [] assert gr1cint.check_realizable(self.f_un) assert gr1cint.check_realizable(self.dcounter) def test_synthesize(self): self.f_un.sys_safety = [] # Make it realizable mach = gr1cint.synthesize(self.f_un) assert mach is not None assert len(mach.inputs) == 1 and mach.inputs.has_key("x") assert len(mach.outputs) == 1 and mach.outputs.has_key("y") mach = gr1cint.synthesize(self.dcounter) assert mach is not None assert len(mach.inputs) == 0 assert len(mach.outputs) == 1 and mach.outputs.has_key("y") assert len(mach.states) == 3
def stability_to_gr1(p, aux='aux'): """Convert C{<>[] p} to GR(1). Warning: This conversion is sound, but not complete. See p.2, U{[E10] <https://tulip-control.sourceforge.io/doc/bibliography.html#e10>} GR(1) form:: !(aux) && [](aux -> X aux) && []<>(aux) && [](aux -> p) @type p: str @param aux: name to use for auxiliary variable @type aux: str @rtype: L{GRSpec} """ logging.warning( 'Conversion of stability (<>[]p) to GR(1)' + 'is sound, but NOT complete.' ) a = aux a0 = a p = _paren(p) a = _paren(a) v = tx.check_var_name_conflict(p, a0) sys_vars = v | {a0} sys_init = {'!' + a} sys_safe = {a + ' -> ' + p, a + ' -> X ' + a} sys_prog = {a} return GRSpec(sys_vars=sys_vars, sys_init=sys_init, sys_safety=sys_safe, sys_prog=sys_prog)
def until_to_gr1(p, q, aux='aux'): """Convert C{p U q} to GR(1). GR(1) form:: (!q -> !aux) && [](q -> aux) [](aux -> X aux) && []<>(aux) && []( (!aux && X(!q) ) -> X!(aux) ) && [](!aux -> p) @type p: str @param aux: name to use for auxiliary variable @type aux: str @rtype: L{GRSpec} """ a = aux a0 = a p = _paren(p) q = _paren(q) a = _paren(a) s = p + ' && ' + q v = tx.check_var_name_conflict(s, a0) sys_vars = v | {a0} sys_init = {'!' + q + ' -> !' + a} sys_safe = { q + ' -> ' + a, '( (X !' + q + ') && !' + a + ') -> X !' + a, a + ' -> X ' + a, '(!' + a + ') -> ' + p } sys_prog = {a} return GRSpec(sys_vars=sys_vars, sys_init=sys_init, sys_safety=sys_safe, sys_prog=sys_prog)
def response_to_gr1(p, q, aux='aux'): """Convert C{[](p -> <> q)} to GR(1). GR(1) form:: []<>(aux) && []( (p && !q) -> X ! aux) && []( (! aux && !q) -> X ! aux) @type p: str @type q: str @param aux: name to use for auxiliary variable @type aux: str @rtype: L{GRSpec} """ a = aux a0 = a p = _paren(p) q = _paren(q) a = _paren(a) s = p + ' -> <> ' + q v = tx.check_var_name_conflict(s, a0) sys_vars = v | {a0} # sys_init = {a} sys_safe = { '(' + p + ' && !' + q + ') -> X !' + a, '(!' + a + ' && !' + q + ') -> X !' + a } sys_prog = {a} return GRSpec( sys_vars=sys_vars, # sys_init=sys_init, sys_safety=sys_safe, sys_prog=sys_prog)
def str_to_grspec(f): """Return `GRSpec` from LTL formula `f` as `str`. Formula `f` must be in the form: A -> G where each of A, G is a conjunction of terms: `B`, `[]C`, `[]<>B`. For more details on `B, C`, see [split_gr1]. @type f: `str` @rtype: [GRSpec] """ t = parser.parse(f) assert t.operator == '->' env, sys = t.operands d = {'assume': split_gr1(env), 'assert': split_gr1(sys)} return GRSpec(env_init=d['assume']['init'], env_safety=d['assume']['G'], env_prog=d['assume']['GF'], sys_init=d['assert']['init'], sys_safety=d['assert']['G'], sys_prog=d['assert']['GF'])
def load(): with open(LTL_SPEC, 'r') as f: d = json.load(f) f = lambda x: ' \n '.join(s for s in x) env_init = f(d['env_init']) sys_init = f(d['sys_init']) env_safety = f(d['env_safety']) sys_safety = f(d['sys_safety']) env_prog = f(d['env_prog']) sys_prog = f(d['sys_prog']) dvars = d['vars'] # restore tuples for var, d in dvars.iteritems(): if d['type'] != 'int': continue d['dom'] = tuple(d['dom']) gr1 = GRSpec(variables=dvars, env_init=[env_init], sys_init=[sys_init], env_safety=[env_safety], sys_safety=[sys_safety], env_prog=[env_prog], sys_prog=[sys_prog]) return gr1, vartypes
def synth_init_illegal_test(init_option): with pytest.raises(ValueError): spc = GRSpec(moore=False, plus_one=False, qinit=init_option) gr1c.synthesize(spc)
def realiz_init_illegal_test(init_option): with pytest.raises(ValueError): spc = GRSpec(moore=False, plus_one=False, qinit=init_option) gr1c.check_realizable(spc)
def realiz_init_illegal_check(init_option): spc = GRSpec(moore=False, plus_one=False, qinit=init_option) gr1c.check_realizable(spc)
def synth_init_illegal_check(init_option): spc = GRSpec(moore=False, plus_one=False, qinit=init_option) gr1c.synthesize(spc)
class basic_test: def setUp(self): self.f_un = GRSpec(env_vars="x", sys_vars="y", env_init="x", env_prog="x", sys_init="y",sys_safety=["y -> X(!y)","!y -> X(y)"], sys_prog="y && x") self.dcounter = GRSpec(sys_vars={"y": (0,5)}, sys_init=["y=0"], sys_prog=["y=0", "y=5"]) def tearDown(self): self.f_un = None self.dcounter = None def test_check_syntax(self): assert gr1cint.check_syntax(REFERENCE_SPECFILE) assert not gr1cint.check_syntax("foo") def test_to_gr1c(self): assert gr1cint.check_syntax(self.f_un.to_gr1c() ) assert gr1cint.check_syntax(self.dcounter.to_gr1c() ) def test_check_realizable(self): assert not gr1cint.check_realizable(self.f_un, init_option="ALL_ENV_EXIST_SYS_INIT") self.f_un.sys_safety = [] assert gr1cint.check_realizable(self.f_un, init_option="ALL_ENV_EXIST_SYS_INIT") assert gr1cint.check_realizable(self.f_un, init_option="ALL_INIT") assert gr1cint.check_realizable(self.dcounter, init_option="ALL_ENV_EXIST_SYS_INIT") self.dcounter.sys_init = [] assert gr1cint.check_realizable(self.dcounter, init_option="ALL_INIT") def test_synthesize(self): self.f_un.sys_safety = [] # Make it realizable mach = gr1cint.synthesize(self.f_un, init_option="ALL_ENV_EXIST_SYS_INIT") assert mach is not None assert len(mach.inputs) == 1 and mach.inputs.has_key("x") assert len(mach.outputs) == 1 and mach.outputs.has_key("y") mach = gr1cint.synthesize(self.dcounter, init_option="ALL_ENV_EXIST_SYS_INIT") assert mach is not None assert len(mach.inputs) == 0 assert len(mach.outputs) == 1 and mach.outputs.has_key("y") assert len(mach.states) == 3 # In the notation of gr1c SYSINIT: True;, so the strategy must # account for every initial state, i.e., for y=0, y=1, y=2, ... self.dcounter.sys_init = [] mach = gr1cint.synthesize(self.dcounter, init_option="ALL_INIT") assert mach is not None print mach assert len(mach.inputs) == 0 assert len(mach.outputs) == 1 and mach.outputs.has_key("y") assert len(mach.states) == 7
def realiz_init_illegal_check(init_option): spc = GRSpec() gr1c.check_realizable(spc, init_option=init_option)
def synth_init_illegal_check(init_option): spc = GRSpec() gr1c.synthesize(spc, init_option=init_option)
def load_aut_xml(x, namespace=DEFAULT_NAMESPACE): """Return strategy constructed from output of gr1c. @param x: a string or an instance of xml.etree.ElementTree._ElementInterface @type spec0: L{GRSpec} @param spec0: GR(1) specification with which to interpret the output of gr1c while constructing a MealyMachine, or None if the output from gr1c should be used as is. Note that spec0 may differ from the specification in the given tulipcon XML string x. If you are unsure what to do, try setting spec0 to whatever L{gr1cint.synthesize} was invoked with. @return: if a strategy is given in the XML string, return it as C{networkx.DiGraph}. Else, return (L{GRSpec}, C{None}), where the first element is the specification as read from the XML string. """ if not isinstance(x, str) and not isinstance(x, ET._ElementInterface): raise TypeError("tag to be parsed must be given " + "as a string or ElementTree._ElementInterface.") if isinstance(x, str): elem = ET.fromstring(x) else: elem = x if (namespace is None) or (len(namespace) == 0): ns_prefix = "" else: ns_prefix = "{"+namespace+"}" if elem.tag != ns_prefix+"tulipcon": raise TypeError("root tag should be tulipcon.") if ("version" not in elem.attrib.keys()): raise ValueError("unversioned tulipcon XML string.") if int(elem.attrib["version"]) != 1: raise ValueError("unsupported tulipcon XML version: "+ str(elem.attrib["version"])) # Extract discrete variables and LTL specification (tag_name, env_vardict, env_vars) = _untagdict(elem.find( ns_prefix+"env_vars"), get_order=True) (tag_name, sys_vardict, sys_vars) = _untagdict(elem.find( ns_prefix+"sys_vars"), get_order=True) env_vars = _parse_vars(env_vars, env_vardict) sys_vars = _parse_vars(sys_vars, sys_vardict) s_elem = elem.find(ns_prefix+"spec") spec = GRSpec(env_vars=env_vars, sys_vars=sys_vars) for spec_tag in ["env_init", "env_safety", "env_prog", "sys_init", "sys_safety", "sys_prog"]: if s_elem.find(ns_prefix+spec_tag) is None: raise ValueError("invalid specification in tulipcon XML string.") (tag_name, li) = _untaglist(s_elem.find(ns_prefix+spec_tag), cast_f=str, namespace=namespace) li = [v.replace("<", "<") for v in li] li = [v.replace(">", ">") for v in li] li = [v.replace("&", "&") for v in li] setattr(spec, spec_tag, li) aut_elem = elem.find(ns_prefix+"aut") if aut_elem is None or ( (aut_elem.text is None) and len(aut_elem.getchildren()) == 0): mach = None return (spec, mach) # Assume version 1 of tulipcon XML if aut_elem.attrib["type"] != "basic": raise ValueError("Automaton class only recognizes type \"basic\".") node_list = aut_elem.findall(ns_prefix+"node") id_list = [] # For more convenient searching, and to catch redundancy A = nx.DiGraph() A.env_vars = env_vars A.sys_vars = sys_vars for node in node_list: this_id = int(node.find(ns_prefix+"id").text) #this_name = node.find(ns_prefix+"anno").text # Assume version 1 (tag_name, this_name_list) = _untaglist(node.find(ns_prefix+"anno"), cast_f=int) if len(this_name_list) == 2: (mode, rgrad) = this_name_list else: (mode, rgrad) = (-1, -1) (tag_name, this_child_list) = _untaglist( node.find(ns_prefix+"child_list"), cast_f=int ) if tag_name != ns_prefix+"child_list": # This really should never happen and may not even be # worth checking. raise ValueError("failure of consistency check " + "while processing aut XML string.") (tag_name, this_state) = _untagdict(node.find(ns_prefix+"state"), cast_f_values=int, namespace=namespace) if tag_name != ns_prefix+"state": raise ValueError("failure of consistency check " + "while processing aut XML string.") if this_id in id_list: logger.warn("duplicate nodes found: "+str(this_id)+"; ignoring...") continue id_list.append(this_id) logger.info('loaded from gr1c result:\n\t' +str(this_state) ) A.add_node(this_id, state=copy.copy(this_state), mode=mode, rgrad=rgrad) for next_node in this_child_list: A.add_edge(this_id, next_node) return A