Esempio n. 1
0
def prime(u, fol):
    """Prime state predicate `u`."""
    support = fol.support(u)
    # all identifiers are unprimed ?
    assert not any(stx.isprimed(name) for name in support), support
    # avoid priming constants
    # (no primed identifiers are declared for constants)
    vrs = {name for name in support if is_variable(name, fol)}
    let = {var: stx.prime(var) for var in vrs}
    return fol.let(let, u)
Esempio n. 2
0
def prime(u, fol):
    """Prime state predicate `u`."""
    support = fol.support(u)
    # all identifiers are unprimed ?
    assert not any(stx.isprimed(name) for name in support), support
    # avoid priming constants
    # (no primed identifiers are declared for constants)
    vrs = {name for name in support if is_variable(name, fol)}
    let = {var: stx.prime(var) for var in vrs}
    return fol.let(let, u)
Esempio n. 3
0
def is_action_of_player(action, player, aut):
    """Return `True` if `action` constrains only `player`.

    The `player` is represented by the variables in
    `aut.varlist[player]`.
    """
    support = aut.support(action)
    primed = {var for var in support if stx.isprimed(var)}
    vrs = aut.vars_of_players([player])
    vrs_p = aut.prime_vars(vrs)
    r = primed.issubset(vrs_p)
    return r
Esempio n. 4
0
    def implies_type_hints(self, u, vrs):
        """Return `True` if `u => TypeInv` for all vars.

        All declared variables and constants are taken into
        account.
        """
        # not named `assert_type_invariant` because the
        # assertion is about the state predicate `u`,
        # so a static conclusion.
        vrs = {var for var in self.vars if not stx.isprimed(var)}
        type_hints = _conjoin_type_hints(vrs, self)
        r = type_hints | ~u
        return r == self.true
Esempio n. 5
0
    def implies_type_hints(self, u, vrs):
        """Return `True` if `u => TypeInv` for all vars.

        All declared variables and constants are taken into
        account.
        """
        # not named `assert_type_invariant` because the
        # assertion is about the state predicate `u`,
        # so a static conclusion.
        vrs = {var for var in self.vars
               if not stx.isprimed(var)}
        type_hints = tyh._conjoin_type_hints(vrs, self)
        r = type_hints | ~ u
        return r == self.true
Esempio n. 6
0
    def implies_type_hints(self, u, vrs=None):
        """Return `True` if `u => TypeHints` for `vrs`.

        If `vrs is None`, then all declared variables and constants
        are taken into account.
        """
        # This function is not named `assert_type_invariant`
        # because the assertion is about the state predicate `u`,
        # so a static conclusion.
        #
        if vrs is None:
            vrs = {var for var in self.vars if not stx.isprimed(var)}
        type_hints = tyh._conjoin_type_hints(vrs, self)
        r = type_hints | ~u
        return r == self.true
Esempio n. 7
0
def split_support(u, fol):
    """Return unprimed, primed identifiers `u` depends on.

    This function exists as an optimization over calling
    separately `unprimed_support` and `primed_support`.
    This function calls `fol.support` once, as opposed to
    twice when performing two separate calls.

    If optimization is irrelevant, then call those other
    functions, because readability counts [PEP 20].
    """
    support = fol.support(u)
    primed = {k for k in support if stx.isprimed(k)}
    unprimed = support - primed
    return unprimed, primed
Esempio n. 8
0
def add_primed_too(table):
    """Return table of primed and unprimed vars.

    Assert `table` contains only unprimed vars.
    Return new table with a primed variable for
    each unprimed variable in `table`,
    in addition to the unprimed variables.
    """
    t = dict()
    for var, d in table.items():
        assert not stx.isprimed(var)
        pvar = stx.prime(var)
        t[var] = dict(d)
        t[pvar] = dict(d)
    return t
Esempio n. 9
0
def split_support(u, fol):
    """Return unprimed, primed identifiers `u` depends on.

    This function exists as an optimization over calling
    separately `unprimed_support` and `primed_support`.
    This function calls `fol.support` once, as opposed to
    twice when performing two separate calls.

    If optimization is irrelevant, then call those other
    functions, because readability counts [PEP 20].
    """
    support = fol.support(u)
    primed = {k for k in support if stx.isprimed(k)}
    unprimed = support - primed
    return unprimed, primed
Esempio n. 10
0
def add_primed_too(table):
    """Return table of primed and unprimed vars.

    Assert `table` contains only unprimed vars.
    Return new table with a primed variable for
    each unprimed variable in `table`,
    in addition to the unprimed variables.
    """
    t = dict()
    for var, d in table.items():
        assert not stx.isprimed(var)
        pvar = stx.prime(var)
        t[var] = dict(d)
        t[pvar] = dict(d)
    return t
Esempio n. 11
0
def vars_in_support(u, fol):
    """Return variables that `u` depends on.

    Returns unprimed identifiers for all variables
    that occur (primed or not) in the support of `u`.
    """
    vrs = set()
    for k in fol.support(u):
        if stx.isprimed(k):
            vrs.add(stx.unprime(k))
        elif is_variable(k, fol):
            vrs.add(k)
    assert vrs == (flexible_support(u, fol)
                   | {stx.unprime(s)
                      for s in primed_support(u, fol)})
    return vrs
Esempio n. 12
0
    def prime_varlists(self, keys=None):
        """Map primed `keys` to lists of primed variables.

        For each `k in keys`, add `"{k}'".format(k=k)` to
        `self.varlist`, with value the `list` that results
        from priming the variables in `self.varlist[k]`.

        If `keys is None`, prime all unprimed variable lists.
        """
        if keys is None:
            keys = set(self.varlist)
        for k in keys:
            if stx.isprimed(k):
                continue
            pk = stx.prime(k)
            pvrs = stx.prime_vars(self.varlist[k])
            self.varlist[pk] = pvrs
Esempio n. 13
0
    def prime_varlists(self, keys=None):
        """Map primed `keys` to lists of primed variables.

        For each `k in keys`, add `"{k}'".format(k=k)` to
        `self.varlist`, with value the `list` that results
        from priming the variables in `self.varlist[k]`.

        If `keys is None`, prime all unprimed variable lists.
        """
        if keys is None:
            keys = set(self.varlist)
        for k in keys:
            if stx.isprimed(k):
                continue
            pk = stx.prime(k)
            pvrs = stx.prime_vars(self.varlist[k])
            self.varlist[pk] = pvrs
Esempio n. 14
0
 def assert_consistent(self, moore=True):
     """Assert that `init` and `win` contain state predicates."""
     varlists = list(self.varlist.values())
     assert pairwise_disjoint(varlists)
     for u in self.init.values():
         assert sym_bdd.is_state_predicate(u)
     # Moore actions
     for player, action in self.action.items():
         primed = {
             stx.unprime(var)
             for var in self.support(action) if stx.isprimed(var)
         }
         # applicable only after unzip
         # assert primed.issubset(self.varlist[player]), (
         #     (player, primed))
     for d in self.win.values():
         for v in d.values():
             for u in v:
                 assert sym_bdd.is_state_predicate(u)
Esempio n. 15
0
def _add_bitnames(t):
    """Map each integer to a list of bit variables."""
    for var, d in t.items():
        if d['type'] != 'int':
            continue
        assert d['type'] == 'int', d['type']
        if stx.isprimed(var):
            name = stx.unprime(var)
            prime = stx.PRIME
        else:
            name = var
            prime = ''
        bits = [
            '{name}_{i}{prime}'.format(
                name=name, i=i, prime=prime)
            for i in range(d['width'])]
        are_booleans = list(filter(t.__contains__, bits))
        assert not are_booleans, (bits, t)
        d['bitnames'] = bits
Esempio n. 16
0
def _add_bitnames(t):
    """Map each integer to a list of bit variables."""
    for var, d in t.items():
        if d['type'] != 'int':
            continue
        assert d['type'] == 'int', d['type']
        if stx.isprimed(var):
            name = stx.unprime(var)
            prime = stx.PRIME
        else:
            name = var
            prime = ''
        bits = [
            '{name}_{i}{prime}'.format(name=name, i=i, prime=prime)
            for i in range(d['width'])
        ]
        are_booleans = list(filter(t.__contains__, bits))
        assert not are_booleans, (bits, t)
        d['bitnames'] = bits
Esempio n. 17
0
def plot_machines(asm):
    """Plot machine behaviors over a finite number of steps."""
    nrows = len(asm.machines)
    history = asm.past + [asm.state]
    n_steps = len(history)  # missing last state
    t = range(n_steps)
    plt.subplots(nrows=nrows, ncols=1)
    styles = ['b-o', 'r--', 'k-', 'g-*']  # def style picker
    for i, (name, stm) in enumerate(asm.machines.items()):
        plt.subplot(nrows, 1, i + 1)
        plt.title(name)
        styles_cp = list(styles)
        # TODO: could instead plot only sys vars and memory
        for var in stm.vars:
            if stx.isprimed(var):
                continue
            x = [steps.omit_prefix(state, name)[var] for state in history]
            style = styles_cp.pop()
            plt.plot(t, x, style, label=var)
        plt.legend()
        plt.grid()
Esempio n. 18
0
def is_primed_state_predicate(u, fol):
    """Return `True` if `u` depends only on primed variables.

    Only constant parameters (rigid variables) can appear
    unprimed in `u`. Any flexible variables in `u` should
    be primed.

    An identifier that is declared only unprimed is assumed
    to be a rigid variables. If a primed sibling is declared,
    then the identifier is assumed to be a flexible variable.
    """
    support = fol.support(u)
    primed = {name for name in support if stx.isprimed(name)}
    unprimed = support - primed
    any_flexible = False
    for name in unprimed:
        primed = stx.prime(name)
        if primed in fol.vars:
            any_flexible = True
            break
    return not any_flexible
Esempio n. 19
0
def plot_machines(asm):
    """Plot machine behaviors over a finite number of steps."""
    nrows = len(asm.machines)
    history = asm.past + [asm.state]
    n_steps = len(history)  # missing last state
    t = range(n_steps)
    plt.subplots(nrows=nrows, ncols=1)
    styles = ['b-o', 'r--', 'k-', 'g-*']  # def style picker
    for i, (name, stm) in enumerate(asm.machines.items()):
        plt.subplot(nrows, 1, i + 1)
        plt.title(name)
        styles_cp = list(styles)
        # TODO: could instead plot only sys vars and memory
        for var in stm.vars:
            if stx.isprimed(var):
                continue
            x = [steps.omit_prefix(state, name)[var]
                 for state in history]
            style = styles_cp.pop()
            plt.plot(t, x, style, label=var)
        plt.legend()
        plt.grid()
Esempio n. 20
0
def action_to_steps(aut, qinit='\A \A'):
    r"""Return enumerated graph with steps as edges.

    Only `aut.init['env']` considered.
    The predicate `aut.init['sys']` is ignored.

    `qinit` has different meaning that in `omega.games.gr1`.
    Nonetheless, for synthesized `aut.init['env']`,
    the meaning of `qinit` here yields the expected result.

    Enumeration is done based on `qinit`:

    - `'\A \A'`: pick all states that satisfy `aut.init['env']`
    - `'\E \E'`: pick one state that satisfies `aut.init['env']`
    - `'\A \E'`: for all states that satisfy `aut.init['env']`,
      pick a unique state for each env state `x`
    - `'\E \A'`: pick a sys state `u` and enumerate all
      states that satisfy `aut.init['env']` and `y = u`
    """
    assert aut.action['sys'] != aut.false
    primed_vars = _primed_vars_per_quantifier(aut.varlist)
    unprime_vars = {stx.prime(var): var for var in aut.vars
                    if not stx.isprimed(var)}
    # fix an order for tupling
    keys = list(k for k in aut.vars if not stx.isprimed(k))
    umap = dict()  # map assignments -> node numbers
    g = nx.DiGraph()
    queue, visited = _init_search(g, aut, umap, keys, qinit)
    g.initial_nodes = set(queue)
    varnames = set(keys)
    symbolic._assert_support_moore(aut.action['sys'], aut)
    # search
    while queue:
        node = queue.pop()
        values = g.node[node]
        log.debug('at node: {d}'.format(d=values))
        assert set(values) == varnames, (values, aut.vars)
        u = aut.action['env']
        u = aut.let(values, u)
        # apply Mealy controller function
        env_iter = aut.pick_iter(
            u, care_vars=primed_vars['env'])
        u = aut.action['sys']
        assert u != aut.false
        sys = aut.let(values, u)
        assert sys != aut.false
        for next_env in env_iter:
            log.debug('next_env: {r}'.format(r=next_env))
            # no effect if `aut.moore`
            u = aut.let(next_env, sys)
            u = aut.let(unprime_vars, u)
            env_values = {unprime_vars[var]: value
                          for var, value in next_env.items()}
            v = aut.let(env_values, visited)
            # prefer already visited nodes
            v &= u
            if v == aut.false:
                log.info('cannot remain in visited nodes')
                v = u
                remain = False
            else:
                remain = True
            assert v != aut.false
            sys_values = aut.pick(
                v, care_vars=aut.varlist['sys'])
            d = dict(env_values)
            d.update(sys_values)
            # assert
            u = aut.let(d, visited)
            assert u == aut.true or u == aut.false
            assert remain == (u == aut.true), remain
            # find or add node
            if remain:
                next_node = _find_node(d, umap, keys)
            else:
                next_node = _add_new_node(d, g, queue, umap, keys)
                visited = _add_to_visited(d, visited, aut)
            g.add_edge(node, next_node)
            log.debug((
                'next env: {e}\n'
                'next sys: {s}\n').format(
                    e=env_values,
                    s=sys_values))
    return g
Esempio n. 21
0
def is_state_predicate(u):
    """Return `True` if `u` depends only on unprimed values."""
    return not any(stx.isprimed(var) for var in u.support)
Esempio n. 22
0
def is_proper_action(u):
    """Return `True` if `u` depends on both primed and unprimed."""
    r = u.support
    return (
        any(stx.isprimed(var) for var in r) and
        any(not stx.isprimed(var) for var in r))
Esempio n. 23
0
def is_proper_action(u):
    """Return `True` if `u` depends on both primed and unprimed."""
    r = u.support
    return (any(stx.isprimed(var) for var in r)
            and any(not stx.isprimed(var) for var in r))
Esempio n. 24
0
def is_state_predicate(u):
    """Return `True` if `u` depends only on unprimed values."""
    return not any(stx.isprimed(var) for var in u.support)
Esempio n. 25
0
def primed_support(u, fol):
    """Return primed identifiers that `u` depends on.

    These identifiers include both variables and constants.
    """
    return {k for k in fol.support(u) if stx.isprimed(k)}
Esempio n. 26
0
def unprimed_support(u, fol):
    """Return unprimed identifiers that `u` depends on."""
    return {k for k in fol.support(u) if not stx.isprimed(k)}
Esempio n. 27
0
def unprimed_support(u, fol):
    """Return unprimed identifiers that `u` depends on."""
    return {k for k in fol.support(u) if not stx.isprimed(k)}
Esempio n. 28
0
def primed_support(u, fol):
    """Return primed identifiers that `u` depends on.

    These identifiers include both variables and constants.
    """
    return {k for k in fol.support(u) if stx.isprimed(k)}
Esempio n. 29
0
def action_to_steps(aut, qinit='\A \A'):
    r"""Return enumerated graph with steps as edges.

    Only `aut.init['env']` considered.
    The predicate `aut.init['sys']` is ignored.

    `qinit` has different meaning that in `omega.games.gr1`.
    Nonetheless, for synthesized `aut.init['env']`,
    the meaning of `qinit` here yields the expected result.

    Enumeration is done based on `qinit`:

    - `'\A \A'`: pick all states that satisfy `aut.init['env']`
    - `'\E \E'`: pick one state that satisfies `aut.init['env']`
    - `'\A \E'`: for all states that satisfy `aut.init['env']`,
      pick a unique state for each env state `x`
    - `'\E \A'`: pick a sys state `u` and enumerate all
      states that satisfy `aut.init['env']` and `y = u`
    """
    assert aut.action['sys'] != aut.false
    primed_vars = _primed_vars_per_quantifier(aut.varlist)
    unprime_vars = {
        stx.prime(var): var
        for var in aut.vars if not stx.isprimed(var)
    }
    # fix an order for tupling
    keys = list(k for k in aut.vars if not stx.isprimed(k))
    umap = dict()  # map assignments -> node numbers
    g = nx.DiGraph()
    queue, visited = _init_search(g, aut, umap, keys, qinit)
    g.initial_nodes = set(queue)
    varnames = set(keys)
    symbolic._assert_support_moore(aut.action['sys'], aut)
    # search
    while queue:
        node = queue.pop()
        values = g.nodes[node]
        log.debug('at node: {d}'.format(d=values))
        assert set(values) == varnames, (values, aut.vars)
        u = aut.action['env']
        u = aut.let(values, u)
        # apply Mealy controller function
        env_iter = aut.pick_iter(u, care_vars=primed_vars['env'])
        u = aut.action['sys']
        assert u != aut.false
        sys = aut.let(values, u)
        assert sys != aut.false
        for next_env in env_iter:
            log.debug('next_env: {r}'.format(r=next_env))
            # no effect if `aut.moore`
            u = aut.let(next_env, sys)
            u = aut.let(unprime_vars, u)
            env_values = {
                unprime_vars[var]: value
                for var, value in next_env.items()
            }
            v = aut.let(env_values, visited)
            # prefer already visited nodes
            v &= u
            if v == aut.false:
                log.info('cannot remain in visited nodes')
                v = u
                remain = False
            else:
                remain = True
            assert v != aut.false
            sys_values = aut.pick(v, care_vars=aut.varlist['sys'])
            d = dict(env_values)
            d.update(sys_values)
            # assert
            u = aut.let(d, visited)
            assert u == aut.true or u == aut.false
            assert remain == (u == aut.true), remain
            # find or add node
            if remain:
                next_node = _find_node(d, umap, keys)
            else:
                next_node = _add_new_node(d, g, queue, umap, keys)
                visited = _add_to_visited(d, visited, aut)
            g.add_edge(node, next_node)
            log.debug(('next env: {e}\n'
                       'next sys: {s}\n').format(e=env_values, s=sys_values))
    return g