Beispiel #1
0
def test_str_to_int():
    r = parse('a = "hehe"')
    g = tx.Tree.from_recursive_ast(r)
    var_str2int = {'a': ['hehe', 'haha']}
    tx.sub_constants(g, var_str2int)
    f = g.to_recursive_ast()
    s = f.flatten()
    assert s == '( a = 0 )'

    x = '(loc = "s2") -> X((((env_alice = "left") && (env_bob = "bright"))))'
    var_str2int = {
        'loc': ['s0', 's2'],
        'env_alice': ['left', 'right'],
        'env_bob': ['bleft', 'bright']}
    r = parse(x)
    print(repr(r))
    g = tx.Tree.from_recursive_ast(r)
    print(g)
    tx.sub_constants(g, var_str2int)
    print(str(g))
    f = g.to_recursive_ast()
    print(repr(f))
    s = f.flatten()
    print(s)
    assert s == ('( ( loc = 1 ) -> '
                 '( X ( ( env_alice = 0 ) & ( env_bob = 1 ) ) ) )')
Beispiel #2
0
def test_str_to_int():
    r = parse('a = "hehe"')
    g = tx.Tree.from_recursive_ast(r)
    var_str2int = {'a': ['hehe', 'haha']}
    tx.sub_constants(g, var_str2int)
    f = g.to_recursive_ast()
    s = f.flatten()
    assert s == '( a = 0 )'

    x = '(loc = "s2") -> X((((env_alice = "left") && (env_bob = "bright"))))'
    var_str2int = {
        'loc': ['s0', 's2'],
        'env_alice': ['left', 'right'],
        'env_bob': ['bleft', 'bright']
    }
    r = parse(x)
    print(repr(r))
    g = tx.Tree.from_recursive_ast(r)
    print(g)
    tx.sub_constants(g, var_str2int)
    print(str(g))
    f = g.to_recursive_ast()
    print(repr(f))
    s = f.flatten()
    print(s)
    assert s == ('( ( loc = 1 ) -> '
                 '( X ( ( env_alice = 0 ) & ( env_bob = 1 ) ) ) )')
Beispiel #3
0
def parse_parse_test(formula, expected_length):
    # If expected_length is None, then the formula is malformed, and
    # thus we expect parsing to fail.
    if expected_length is not None:
        assert len(parse(formula)) == expected_length
    else:
        with pytest.raises(Exception):
            parse(formula)
Beispiel #4
0
def generate_JTLV_LTL(spec):
    """Return the LTLSPEC for JTLV.

    It takes as input a GRSpec object.  N.B., assumes all variables
    are Boolean (i.e., atomic propositions).
    """
    formula = spec.to_canon()
    parse(formula)  # Raises exception if syntax error

    specLTL = spec.to_jtlv()
    logger.debug(''.join([str(x) for x in specLTL]) )
    
    assumption = specLTL[0]
    guarantee = specLTL[1]
    
    assumption = re.sub(r'\b'+'True'+r'\b', 'TRUE', assumption)
    guarantee = re.sub(r'\b'+'True'+r'\b', 'TRUE', guarantee)
    assumption = re.sub(r'\b'+'False'+r'\b', 'FALSE', assumption)
    guarantee = re.sub(r'\b'+'False'+r'\b', 'FALSE', guarantee)

    assumption = assumption.replace('==', '=')
    guarantee = guarantee.replace('==', '=')
    
    assumption = assumption.replace('&&', '&')
    guarantee = guarantee.replace('&&', '&')
    
    assumption = assumption.replace('||', '|')
    guarantee = guarantee.replace('||', '|')
    
    # Replace any environment variable var in spec with e.var and replace any 
    # system variable var with s.var
    for var in spec.env_vars.keys():
        assumption = re.sub(r'\b'+var+r'\b', 'e.'+var, assumption)
        guarantee = re.sub(r'\b'+var+r'\b', 'e.'+var, guarantee)
    for var in spec.sys_vars.keys():
        assumption = re.sub(r'\b'+var+r'\b', 's.'+var, assumption)
        guarantee = re.sub(r'\b'+var+r'\b', 's.'+var, guarantee)

    # Assumption
    ltl = 'LTLSPEC\n(\n'
    if assumption:
        ltl += assumption
    else:
        ltl += "TRUE"
    ltl += '\n);\n'

    # Guarantee
    ltl += '\nLTLSPEC\n(\n'
    if guarantee:
        ltl += guarantee
    else:
        ltl += "TRUE"
    ltl += '\n);'    

    return ltl
Beispiel #5
0
def replace_dependent_vars(spec, bool2form):
    logger.debug('replacing dependent variables using map:\n\t' +
                 str(bool2form))
    vs = dict(spec.env_vars)
    vs.update(spec.sys_vars)
    logger.debug('variables:\n\t' + str(vs))
    bool2subtree = dict()
    for boolvar, formula in bool2form.iteritems():
        logger.debug('checking var: ' + str(boolvar))
        if boolvar in vs:
            assert vs[boolvar] == 'boolean'
            logger.debug(str(boolvar) + ' is indeed Boolean')
        else:
            logger.debug('spec does not contain var: ' + str(boolvar))
        tree = parser.parse(formula)
        bool2subtree[boolvar] = tx.Tree.from_recursive_ast(tree)
    for s in {'env_init', 'env_safety', 'env_prog',
              'sys_init', 'sys_safety', 'sys_prog'}:
        part = getattr(spec, s)
        new = []
        for clause in part:
            logger.debug('replacing in clause:\n\t' + clause)
            tree = spec.ast(clause)
            g = tx.Tree.from_recursive_ast(tree)
            tx.sub_bool_with_subtree(g, bool2subtree)
            f = g.to_recursive_ast().flatten()
            new.append(f)
            logger.debug('caluse tree after replacement:\n\t' + f)
        setattr(spec, s, new)
Beispiel #6
0
def parse_parse_check(formula, expected_length):
    # If expected_length is None, then the formula is malformed, and
    # thus we expect parsing to fail.
    if expected_length is not None:
        assert len(parse(formula)) == expected_length
    else:
        nt.assert_raises(Exception, parse, formula)
Beispiel #7
0
def check_var_name_conflict(f, varname):
    t = parser.parse(f)
    g = Tree.from_recursive_ast(t)
    v = {x.value for x in g.variables}
    if varname in v:
        raise ValueError('var name "{v}" already used'.format(v=varname))
    return v
Beispiel #8
0
def replace_dependent_vars(spec, bool2form):
    logger.debug('replacing dependent variables using map:\n\t' +
                 str(bool2form))
    vs = dict(spec.env_vars)
    vs.update(spec.sys_vars)
    logger.debug('variables:\n\t' + str(vs))
    bool2subtree = dict()
    for boolvar, formula in bool2form.items():
        logger.debug('checking var: ' + str(boolvar))
        if boolvar in vs:
            assert vs[boolvar] == 'boolean'
            logger.debug(str(boolvar) + ' is indeed Boolean')
        else:
            logger.debug('spec does not contain var: ' + str(boolvar))
        tree = parser.parse(formula)
        bool2subtree[boolvar] = tx.Tree.from_recursive_ast(tree)
    for s in {'env_init', 'env_safety', 'env_prog',
              'sys_init', 'sys_safety', 'sys_prog'}:
        part = getattr(spec, s)
        new = []
        for clause in part:
            logger.debug('replacing in clause:\n\t' + clause)
            tree = spec.ast(clause)
            g = tx.Tree.from_recursive_ast(tree)
            tx.sub_bool_with_subtree(g, bool2subtree)
            f = g.to_recursive_ast().flatten()
            new.append(f)
            logger.debug('caluse tree after replacement:\n\t' + f)
        setattr(spec, s, new)
Beispiel #9
0
def parse_parse_check(formula, expected_length):
    # If expected_length is None, then the formula is malformed, and
    # thus we expect parsing to fail.
    if expected_length is not None:
        assert len(parse(formula)) == expected_length
    else:
        nt.assert_raises(Exception, parse, formula)
Beispiel #10
0
def check_var_name_conflict(f, varname):
    t = parser.parse(f)
    g = Tree.from_recursive_ast(t)
    v = {x.value for x in g.variables}
    if varname in v:
        raise ValueError('var name "{v}" already used'.format(v=varname))
    return v
Beispiel #11
0
def lexer_token_precedence_test():
    s = 'False'
    r = parse(s)
    assert isinstance(r, ast.nodes.Bool)
    assert r.value == 'False'
    s = 'a'
    r = parse(s)
    assert isinstance(r, ast.nodes.Var)
    assert r.value == 'a'
    s = 'x = "a"'
    r = parse(s)
    assert isinstance(r, ast.nodes.Binary)
    assert r.operator == '='
    x, a = r.operands
    assert isinstance(x, ast.nodes.Var)
    assert x.value == 'x'
    assert isinstance(a, ast.nodes.Str)
    assert a.value == 'a'
    s = 'y = 1'
    r = parse(s)
    assert isinstance(r, ast.nodes.Binary)
    assert r.operator == '='
    y, n = r.operands
    assert isinstance(y, ast.nodes.Var)
    assert y.value == 'y'
    assert isinstance(n, ast.nodes.Num)
    assert n.value == '1'
    s = '[] a'
    r = parse(s)
    assert isinstance(r, ast.nodes.Unary)
    assert r.operator == 'G'
    assert isinstance(r.operands[0], ast.nodes.Var)
    assert r.operands[0].value == 'a'
    s = 'a U b'
    r = parse(s)
    assert isinstance(r, ast.nodes.Binary)
    assert r.operator == 'U'
    assert isinstance(r.operands[0], ast.nodes.Var)
    assert r.operands[0].value == 'a'
    assert isinstance(r.operands[1], ast.nodes.Var)
    assert r.operands[1].value == 'b'
    s = '( a )'
    r = parse(s)
    assert isinstance(r, ast.nodes.Var)
    s = "(a ' = 1)"
    r = parse(s)
    assert isinstance(r, ast.nodes.Comparator)
    assert r.operator == '='
    x = r.operands[0]
    assert isinstance(x, ast.nodes.Unary)
    assert x.operator == 'X'
    assert isinstance(x.operands[0], ast.nodes.Var)
    assert x.operands[0].value == 'a'
    y = r.operands[1]
    assert isinstance(y, ast.nodes.Num)
    assert y.value == '1'
Beispiel #12
0
def lexer_token_precedence_test():
    s = 'False'
    r = parse(s)
    assert isinstance(r, ast.nodes.Bool)
    assert r.value == 'False'
    s = 'a'
    r = parse(s)
    assert isinstance(r, ast.nodes.Var)
    assert r.value == 'a'
    s = 'x = "a"'
    r = parse(s)
    assert isinstance(r, ast.nodes.Binary)
    assert r.operator == '='
    x, a = r.operands
    assert isinstance(x, ast.nodes.Var)
    assert x.value == 'x'
    assert isinstance(a, ast.nodes.Str)
    assert a.value == 'a'
    s = 'y = 1'
    r = parse(s)
    assert isinstance(r, ast.nodes.Binary)
    assert r.operator == '='
    y, n = r.operands
    assert isinstance(y, ast.nodes.Var)
    assert y.value == 'y'
    assert isinstance(n, ast.nodes.Num)
    assert n.value == '1'
    s = '[] a'
    r = parse(s)
    assert isinstance(r, ast.nodes.Unary)
    assert r.operator == 'G'
    assert isinstance(r.operands[0], ast.nodes.Var)
    assert r.operands[0].value == 'a'
    s = 'a U b'
    r = parse(s)
    assert isinstance(r, ast.nodes.Binary)
    assert r.operator == 'U'
    assert isinstance(r.operands[0], ast.nodes.Var)
    assert r.operands[0].value == 'a'
    assert isinstance(r.operands[1], ast.nodes.Var)
    assert r.operands[1].value == 'b'
    s = '( a )'
    r = parse(s)
    assert isinstance(r, ast.nodes.Var)
    s = "(a ' = 1)"
    r = parse(s)
    assert isinstance(r, ast.nodes.Comparator)
    assert r.operator == '='
    x = r.operands[0]
    assert isinstance(x, ast.nodes.Unary)
    assert x.operator == 'X'
    assert isinstance(x.operands[0], ast.nodes.Var)
    assert x.operands[0].value == 'a'
    y = r.operands[1]
    assert isinstance(y, ast.nodes.Num)
    assert y.value == '1'
Beispiel #13
0
def test_to_labeled_graph():
    f = ('( ( p & q ) U ( ( q | ( ( p -> w ) & ( ! ( z -> b ) ) ) ) & '
         '( G ( X g ) ) ) )')
    tree = parse(f)
    assert len(tree) == 18
    nodes = {'p', 'q', 'w', 'z', 'b', 'g', 'G', 'U', 'X', '&', '|', '!', '->'}
    g = tx.Tree.from_recursive_ast(tree)
    h = tx.ast_to_labeled_graph(g, detailed=False)
    labels = {d['label'] for u, d in h.nodes(data=True)}
    assert labels == nodes
Beispiel #14
0
def test_to_labeled_graph():
    f = ('( ( p & q ) U ( ( q | ( ( p -> w ) & ( ! ( z -> b ) ) ) ) & '
         '( G ( X g ) ) ) )')
    tree = parse(f)
    assert len(tree) == 18
    nodes = {'p', 'q', 'w', 'z', 'b', 'g', 'G',
             'U', 'X', '&', '|', '!', '->'}
    g = tx.Tree.from_recursive_ast(tree)
    h = tx.ast_to_labeled_graph(g, detailed=False)
    labels = {d['label'] for u, d in h.nodes_iter(data=True)}
    assert labels == nodes
Beispiel #15
0
def full_name_operators_test():
    formulas = {
        'always eventually p': '( G ( F p ) )',
        'ALwaYs EvenTUAlly(p)': '( G ( F p ) )',
        ('(p and q) UNtIl (q or ((p -> w) and '
         'not (z implies b))) and always next g'):
        ('( ( ( p & q ) U ( q | ( ( p -> w ) & '
         '( ! ( z -> b ) ) ) ) ) & ( G ( X g ) ) )')}

    for f, correct in formulas.items():
        tree = parse(f, full_operators=True)
        # g.write('hehe.png')
        assert tree.flatten() == correct, tree.flatten()
Beispiel #16
0
def full_name_operators_test():
    formulas = {
        'always eventually p':
        '( G ( F p ) )',
        'ALwaYs EvenTUAlly(p)':
        '( G ( F p ) )',
        ('(p and q) UNtIl (q or ((p -> w) and '
         'not (z implies b))) and always next g'):
        ('( ( ( p & q ) U ( q | ( ( p -> w ) & '
         '( ! ( z -> b ) ) ) ) ) & ( G ( X g ) ) )')
    }

    for f, correct in formulas.items():
        tree = parse(f, full_operators=True)
        # g.write('hehe.png')
        assert tree.flatten() == correct, tree.flatten()
Beispiel #17
0
def infer_constants(formula, variables):
    """Enclose all non-variable names in quotes.

    @param formula: well-formed LTL formula
    @type formula: C{str} or L{LTL_AST}

    @param variables: domains of variables, or only their names.
        If the domains are given, then they are checked
        for ambiguities as for example a variable name
        duplicated as a possible value in the domain of
        a string variable (the same or another).

        If the names are given only, then a warning is raised,
        because ambiguities cannot be checked in that case,
        since they depend on what domains will be used.
    @type variables: C{dict} as accepted by L{GRSpec} or
        container of C{str}

    @return: C{formula} with all string literals not in C{variables}
        enclosed in double quotes
    @rtype: C{str}
    """
    if isinstance(variables, dict):
        for var in variables:
            other_vars = dict(variables)
            other_vars.pop(var)
            _check_var_conflicts({var}, other_vars)
    else:
        logger.error('infer constants does not know the variable domains.')
        warnings.warn(
            'infer_constants can give an incorrect result '
            'depending on the variable domains.\n'
            'If you give the variable domain definitions as dict, '
            'then infer_constants will check for ambiguities.')
    tree = parser.parse(formula)
    old2new = dict()
    for u in tree:
        if u.type != 'var':
            continue
        if str(u) in variables:
            continue
        # Var (so NAME token) but not a variable
        # turn it into a string constant
        old2new[u] = nodes.Const(str(u))
    nx.relabel_nodes(tree, old2new, copy=False)
    return str(tree)
Beispiel #18
0
def infer_constants(formula, variables):
    """Enclose all non-variable names in quotes.

    @param formula: well-formed LTL formula
    @type formula: C{str} or L{LTL_AST}

    @param variables: domains of variables, or only their names.
        If the domains are given, then they are checked
        for ambiguities as for example a variable name
        duplicated as a possible value in the domain of
        a string variable (the same or another).

        If the names are given only, then a warning is raised,
        because ambiguities cannot be checked in that case,
        since they depend on what domains will be used.
    @type variables: C{dict} as accepted by L{GRSpec} or
        container of C{str}

    @return: C{formula} with all string literals not in C{variables}
        enclosed in double quotes
    @rtype: C{str}
    """
    if isinstance(variables, dict):
        for var in variables:
            other_vars = dict(variables)
            other_vars.pop(var)
            _check_var_conflicts({var}, other_vars)
    else:
        logger.error('infer constants does not know the variable domains.')
        warnings.warn(
            'infer_constants can give an incorrect result '
            'depending on the variable domains.\n'
            'If you give the variable domain definitions as dict, '
            'then infer_constants will check for ambiguities.')
    tree = parser.parse(formula)
    old2new = dict()
    for u in tree:
        if u.type != 'var':
            continue
        if str(u) in variables:
            continue
        # Var (so NAME token) but not a variable
        # turn it into a string constant
        old2new[u] = nodes.Const(str(u))
    nx.relabel_nodes(tree, old2new, copy=False)
    return str(tree)
Beispiel #19
0
    def to_gr1c(self):
        """Dump to gr1c specification string.

        Cf. L{interfaces.gr1c}.
        """

        def _to_gr1c_print_vars(vardict):
            output = ""
            for variable, domain in vardict.items():
                if domain == "boolean":
                    output += " " + variable
                elif isinstance(domain, tuple) and len(domain) == 2:
                    output += " " + variable + " [" + str(domain[0]) + ", " + str(domain[1]) + "]"
                else:
                    raise ValueError("Domain type unsupported by gr1c: " + str(domain))
            return output

        tmp = finite_domain2ints(self)
        if tmp is not None:
            return tmp.to_gr1c()

        output = "ENV:" + _to_gr1c_print_vars(self.env_vars) + ";\n"
        output += "SYS:" + _to_gr1c_print_vars(self.sys_vars) + ";\n"

        output += "ENVINIT: " + "\n& ".join(["(" + parser.parse(s).to_gr1c() + ")" for s in self.env_init]) + ";\n"
        if len(self.env_safety) == 0:
            output += "ENVTRANS:;\n"
        else:
            output += (
                "ENVTRANS: " + "\n& ".join(["[](" + parser.parse(s).to_gr1c() + ")" for s in self.env_safety]) + ";\n"
            )
        if len(self.env_prog) == 0:
            output += "ENVGOAL:;\n\n"
        else:
            output += (
                "ENVGOAL: " + "\n& ".join(["[]<>(" + parser.parse(s).to_gr1c() + ")" for s in self.env_prog]) + ";\n\n"
            )

        output += "SYSINIT: " + "\n& ".join(["(" + parser.parse(s).to_gr1c() + ")" for s in self.sys_init]) + ";\n"
        if len(self.sys_safety) == 0:
            output += "SYSTRANS:;\n"
        else:
            output += (
                "SYSTRANS: " + "\n& ".join(["[](" + parser.parse(s).to_gr1c() + ")" for s in self.sys_safety]) + ";\n"
            )
        if len(self.sys_prog) == 0:
            output += "SYSGOAL:;\n"
        else:
            output += (
                "SYSGOAL: " + "\n& ".join(["[]<>(" + parser.parse(s).to_gr1c() + ")" for s in self.sys_prog]) + ";\n"
            )
        return output
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'])
Beispiel #21
0
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'])
Beispiel #22
0
def synthesize(formula, env_vars=None, sys_vars=None):
    """Return Moore transducer if C{formula} is realizable.

    Variable C{dict}s have variable names as keys and their type as
    value. The types should be 'boolean'. These parameters are only
    used if formula is of type C{str}. Else, the variable dictionaries
    associated with the L{LTL} or L{GRSpec} object are used.

    @param formula: linear temporal logic formula
    @type formula: C{str}, L{LTL}, or L{GRSpec}

    @param env_vars: uncontrolled variables (inputs); used only if
        C{formula} is of type C{str}
    @type env_vars: C{dict} or None

    @param sys_vars: controlled variables (outputs); used only if
        C{formula} is of type C{str}
    @type sys_vars: C{dict} or None

    @return: symbolic Moore transducer
        (guards are conjunctions, not sets)
    @rtype: L{MooreMachine}
    """
    if isinstance(formula, GRSpec):
        env_vars = formula.env_vars
        sys_vars = formula.sys_vars
    elif isinstance(formula, LTL):
        env_vars = formula.input_variables
        sys_vars = formula.output_variables

    all_vars = dict(env_vars)
    all_vars.update(sys_vars)
    if not all(v == 'boolean' for v in all_vars.itervalues()):
        raise TypeError(
            'all variables should be Boolean:\n{v}'.format(v=all_vars))

    if isinstance(formula, GRSpec):
        f = translate(formula, 'wring')
    else:
        T = parse(str(formula))
        f = translate_ast(T, 'wring').flatten(env_vars=env_vars,
                                              sys_vars=sys_vars)

    # dump partition file
    s = '.inputs {inp}\n.outputs {out}'.format(
        inp=' '.join(env_vars),
        out=' '.join(sys_vars)
    )
    with open(IO_PARTITION_FILE, 'w') as fid:
        fid.write(s)

    # call lily
    try:
        p = subprocess.Popen([LILY, '-f', f, '-syn', IO_PARTITION_FILE],
                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        out = p.stdout.read()
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            raise Exception(
                'lily.pl not found in path.\n'
                'See the Lily docs for setting PERL5LIB and PATH.')
        else:
            raise

    dotf = open(DOTFILE, 'r')
    fail_msg = 'Formula is not realizable'
    if dotf.read(len(fail_msg)) == fail_msg:
        return None
    dotf.seek(0)
    g = nx.read_dot(dotf)
    dotf.close()
    moore = lily_strategy2moore(g, env_vars, sys_vars)
    return moore
Beispiel #23
0
    def to_jtlv(self):
        """Return specification as list of two strings [assumption, guarantee].

        Format is that of JTLV.  Cf. L{interfaces.jtlv}.
        """
        spec = ['', '']
        desc_added = False
        for env_init in self.env_init:
            if (len(env_init) > 0):
                if (len(spec[0]) > 0):
                    spec[0] += ' && \n'
                if (not desc_added):
                    spec[0] += '-- valid initial env states\n'
                    desc_added = True
                spec[0] += '\t' + parser.parse(env_init).to_jtlv()

        desc_added = False
        for env_safety in self.env_safety:
            if (len(env_safety) > 0):
                if (len(spec[0]) > 0):
                    spec[0] += ' && \n'
                if (not desc_added):
                    spec[0] += '-- safety assumption on environment\n'
                    desc_added = True
                env_safety = parser.parse(env_safety).to_jtlv()
                spec[0] += '\t[](' +re.sub(r"next\s*\(", "next(", env_safety) +')'

        desc_added = False
        for prog in self.env_prog:
            if (len(prog) > 0):
                if (len(spec[0]) > 0):
                    spec[0] += ' && \n'
                if (not desc_added):
                    spec[0] += '-- justice assumption on environment\n'
                    desc_added = True
                spec[0] += '\t[]<>(' + parser.parse(prog).to_jtlv() + ')'

        desc_added = False
        for sys_init in self.sys_init:
            if (len(sys_init) > 0):
                if (len(spec[1]) > 0):
                    spec[1] += ' && \n'
                if (not desc_added):
                    spec[1] += '-- valid initial system states\n'
                    desc_added = True
                spec[1] += '\t' + parser.parse(sys_init).to_jtlv()

        desc_added = False
        for sys_safety in self.sys_safety:
            if (len(sys_safety) > 0):
                if (len(spec[1]) > 0):
                    spec[1] += ' && \n'
                if (not desc_added):
                    spec[1] += '-- safety requirement on system\n'
                    desc_added = True
                sys_safety = parser.parse(sys_safety).to_jtlv()
                spec[1] += '\t[](' +re.sub(r"next\s*\(", "next(", sys_safety) +')'

        desc_added = False
        for prog in self.sys_prog:
            if (len(prog) > 0):
                if (len(spec[1]) > 0):
                    spec[1] += ' && \n'
                if (not desc_added):
                    spec[1] += '-- progress requirement on system\n'
                    desc_added = True
                spec[1] += '\t[]<>(' + parser.parse(prog).to_jtlv() + ')'
        return spec
Beispiel #24
0
def test_has_operator():
    t = parser.parse(' [](x & y) ')
    g = transformation.Tree.from_recursive_ast(t)
    assert gr1.has_operator(t, g, {'&'}) == '&'
    assert gr1.has_operator(t, g, {'G'}) == 'G'
Beispiel #25
0
def test_has_operator():
    t = parser.parse(' [](x & y) ')
    g = transformation.Tree.from_recursive_ast(t)
    assert gr1.has_operator(t, g, {'&'}) == '&'
    assert gr1.has_operator(t, g, {'G'}) == 'G'
def split_gr1(f):
    """Return `dict` of GR(1) subformulae.

    The formula `f` is assumed to be a conjunction of expressions
    of the form:
      `B`, `[]C` or `[]<>B`
    where:
      - `C` can contain "next"
      - `B` cannot contain "next"

    @param f: temporal logic formula
    @type f: `str` or AST

    @return: conjunctions of formulae A, B as `str`, grouped by keys:
        `'init', 'G', 'GF'`
    @rtype: `dict` of `str`: `list` of `str`
    """
    # TODO: preprocess by applying syntactic identities: [][] = [] etc
    try:
        f + 's'
        t = parser.parse(f)
    except TypeError:
        t = f
    g = tx.Tree.from_recursive_ast(t)
    # collect boundary of conjunction operators
    Q = [g.root]
    b = list()  # use lists to preserve as much given syntactic order
    while Q:
        u = Q.pop()
        # terminal ?
        if not g.succ.get(u):
            b.append(u)
            continue
        # operator
        if u.operator == '&':
            # use `u.operands` instead of `g.successors`
            # to preserve original order
            Q.extend(u.operands)
        else:
            b.append(u)
    d = {'init': list(), 'G': list(), 'GF': list()}
    for u in b:
        # terminal ?
        if not g.succ.get(u):
            d['init'].append(u)
            continue
        # some operator
        if u.operator != 'G':
            d['init'].append(u)
            continue
        # G
        (v, ) = u.operands
        # terminal in G ?
        if not g.succ.get(v):
            d['G'].append(v)
            continue
        # some operator in G
        if v.operator == 'F':
            (w, ) = v.operands
            d['GF'].append(w)
        else:
            # not a GF
            d['G'].append(v)
    # assert only admissible temporal operators
    ops = {'G', 'F', 'U', 'V', 'R'}
    operators = {'G': ops}
    ops = set(ops)
    ops.add('X')
    operators.update(init=ops, GF=ops)
    for part, f in d.items():
        ops = operators[part]
        for u in f:
            op = has_operator(u, g, ops)
            if op is None:
                continue
            raise AssertionError(('found inadmissible operator "{op}" '
                                  'in "{f}" formula').format(op=op, f=u))
    # conjoin (except for progress)
    init = ' & '.join(u.flatten() for u in reversed(d['init']))
    d['init'] = [init]
    safe = ' & '.join(u.flatten() for u in reversed(d['G']))
    d['G'] = [safe]
    # flatten individual progress formulae
    d['GF'] = [u.flatten() for u in d['GF']]
    return d
Beispiel #27
0
def split_gr1(f):
    """Return `dict` of GR(1) subformulae.

    The formula `f` is assumed to be a conjunction of expressions
    of the form:
      `B`, `[]C` or `[]<>B`
    where:
      - `C` can contain "next"
      - `B` cannot contain "next"

    @param f: temporal logic formula
    @type f: `str` or AST

    @return: conjunctions of formulae A, B as `str`, grouped by keys:
        `'init', 'G', 'GF'`
    @rtype: `dict` of `str`: `list` of `str`
    """
    # TODO: preprocess by applying syntactic identities: [][] = [] etc
    try:
        f + 's'
        t = parser.parse(f)
    except TypeError:
        t = f
    g = tx.Tree.from_recursive_ast(t)
    # collect boundary of conjunction operators
    Q = [g.root]
    b = list()  # use lists to preserve as much given syntactic order
    while Q:
        u = Q.pop()
        # terminal ?
        if not g.succ.get(u):
            b.append(u)
            continue
        # operator
        if u.operator == '&':
            # use `u.operands` instead of `g.successors`
            # to preserve original order
            Q.extend(u.operands)
        else:
            b.append(u)
    d = {'init': list(), 'G': list(), 'GF': list()}
    for u in b:
        # terminal ?
        if not g.succ.get(u):
            d['init'].append(u)
            continue
        # some operator
        if u.operator != 'G':
            d['init'].append(u)
            continue
        # G
        (v,) = u.operands
        # terminal in G ?
        if not g.succ.get(v):
            d['G'].append(v)
            continue
        # some operator in G
        if v.operator == 'F':
            (w,) = v.operands
            d['GF'].append(w)
        else:
            # not a GF
            d['G'].append(v)
    # assert only admissible temporal operators
    ops = {'G', 'F', 'U', 'V', 'R'}
    operators = {'G': ops}
    ops = set(ops)
    ops.add('X')
    operators.update(init=ops, GF=ops)
    for part, f in d.iteritems():
        ops = operators[part]
        for u in f:
            op = has_operator(u, g, ops)
            if op is None:
                continue
            raise AssertionError((
                'found inadmissible operator "{op}" '
                'in "{f}" formula').format(
                    op=op, f=u))
    # conjoin (except for progress)
    init = ' & '.join(u.flatten() for u in reversed(d['init']))
    d['init'] = [init]
    safe = ' & '.join(u.flatten() for u in reversed(d['G']))
    d['G'] = [safe]
    # flatten individual progress formulae
    d['GF'] = [u.flatten() for u in d['GF']]
    return d