Beispiel #1
0
def fts2SC(ts, env_name='ctrl', act='act'):
    """ 
    Get a mealy machine with reach +  move state on all transitions 
        Parameters
        ----------
    ts :  FTS 
    env_name='move' :  label for on transitions environment action
    reach='reach' : ouput of each transition

    """
    h = transys.MealyMachine()

    mlist = list()
    for node in ts.nodes():
        mlist += [node]

    inputs = transys.machines.create_machine_ports(dict({env_name: mlist}))
    h.add_inputs(inputs)
    outputs = transys.machines.create_machine_ports(dict({act: mlist}))
    h.add_outputs(outputs)

    h.add_nodes_from(ts.nodes())
    for (st1, st2) in ts.transitions():
        q = {env_name: st2, act: st2}
        h.transitions.add(st1, st2, **dict(q))
    h.add_node('Minit')
    h.states.initial |= {'Minit'}
    for init in ts.states.initial:
        q = {env_name: init, act: init}
        h.transitions.add('Minit', init, **dict(q))
    return h
Beispiel #2
0
def fts2mealy(ts, env_name='move', reach_name='reach'):
    """ 
    Get a mealy machine with reach +  move state on all transitions 
        Parameters
        ----------
    ts :  FTS 
    env_name='move' :  label for on transitions environment action
    reach='reach' : ouput of each transition

    """
    h = transys.MealyMachine()

    mlist = list()
    for node in ts.nodes():
        mlist += [node]

    inputs = transys.machines.create_machine_ports(dict({env_name: mlist}))
    h.add_inputs(inputs)
    outputs = transys.machines.create_machine_ports(
        dict({reach_name: 'boolean'}))
    h.add_outputs(outputs)

    h.add_nodes_from(ts.nodes())
    for (st1, st2) in ts.transitions():
        q = {reach_name: 1, env_name: st2}
        h.transitions.add(st1, st2, **dict(q))

    for init in ts.states.initial:
        h.states.initial |= {init}

    return h
Beispiel #3
0
def remove_aux_inputs(ctrl, inputs):

    #1. check whether you are allowed to remove the aux inputs. <= not done
    #2. remove aux. inputs.

    ctrl_new = transys.MealyMachine()
    ctrl_new.add_outputs(ctrl.outputs)

    # this needs to be changed to be a limited set
    inputs_dict = dict()
    for i in inputs:
        inputs_dict[i] = ctrl.inputs[i]
    ctrl_new.add_inputs(inputs_dict)

    # add nodes from original mealy
    ctrl_new.add_nodes_from(ctrl.nodes())
    block_pairs = it_product(ctrl, ctrl)
    for (b, c) in block_pairs:
        labels = {
            frozenset([(key, label[key]) for key in ctrl_new.inputs.keys()] +
                      [(output, label[output])
                       for output in ctrl_new.outputs.keys()])
            for (x, y, label) in ctrl.transitions.find(b, c)
        }
        for q in labels:
            ctrl_new.transitions.add(b, c, **dict(q))

    ctrl_new.states.initial.add_from(ctrl.states.initial)

    return ctrl_new
Beispiel #4
0
def thermostat_with_hysteresis():
    """Example 3.5, p.50 [LS11]
    """
    class temperature_type():
        def is_valid_value(x):
            if not isinstance(x, [float, int]):
                raise TypeError('Input temperature must be float.')

        def __contains__(self, guard):
            # when properly implemented, do appropriate syntactic check
            if isinstance(guard, float):
                return True

            return False

    m = trs.MealyMachine()

    m.add_inputs({'temperature': set()})
Beispiel #5
0
def pedestrians():
    """Example 2.14, p.63 [LS11]
    """
    m = trs.MealyMachine()

    m.add_inputs({'sigR': mc.pure, 'sigG': mc.pure, 'sigY': mc.pure})

    m.add_outputs({'pedestrian': mc.pure})

    m.states.add_from(['none', 'waiting', 'crossing'])
    m.states.initial.add('crossing')

    for sigR in mc.pure:
        for sigG in mc.pure:
            for sigY in mc.pure:
                m.transitions.add('none',
                                  'none',
                                  sigR=sigR,
                                  sigG=sigG,
                                  sigY=sigY,
                                  pedestrian='absent')

                m.transitions.add('none',
                                  'waiting',
                                  sigR=sigR,
                                  sigG=sigG,
                                  sigY=sigY,
                                  pedestrian='present')

    m.transitions.add('waiting',
                      'crossing',
                      sigR='present',
                      sigG='absent',
                      sigY='absent',
                      pedestrian='absent')
    m.transitions.add('crossing',
                      'none',
                      sigR='absent',
                      sigG='present',
                      sigY='absent',
                      pedestrian='absent')
    m.save()
    return m
Beispiel #6
0
def traffic_light():
    m = trs.MealyMachine()
    pure_signal = {'present', 'absent'}

    m.add_inputs({'tick': pure_signal})
    m.add_outputs({'go': pure_signal, 'stop': pure_signal})

    m.states.add_from(['red', 'green', 'yellow'])
    m.states.initial.add('red')

    p = 'present'
    a = 'absent'

    m.transitions.add('red', 'green', tick=p, go=p, stop=a)
    m.transitions.add('green', 'yellow', tick=p, go=a, stop=p)
    m.transitions.add('yellow', 'red', tick=p, go=a, stop=p)

    m.save()
    return m
Beispiel #7
0
def test_determinize_machine_init():
    mach = transys.MealyMachine()
    mach.add_inputs({'a': {0, 1}})
    mach.add_outputs({'b': {0, 1}, 'c': {0, 1}})
    u = 'Sinit'
    mach.add_nodes_from([u, 1, 2])

    # initial reactions:

    # to input: a=0
    mach.add_edge(u, 1, a=0, b=0, c=1)
    mach.add_edge(u, 2, a=0, b=0, c=1)
    mach.add_edge(u, 1, a=0, b=1, c=0)
    mach.add_edge(u, 2, a=0, b=1, c=1)

    # to input: a=1
    mach.add_edge(u, 1, a=1, b=0, c=1)
    mach.add_edge(u, 2, a=1, b=0, c=1)
    mach.add_edge(u, 1, a=1, b=1, c=0)
    mach.add_edge(u, 2, a=1, b=1, c=1)

    # determinize all outputs arbitrarily
    detmach = synth.determinize_machine_init(mach)
    assert detmach is not mach

    for a in {0, 1}:
        edges = [(i, j) for (i, j, d) in detmach.edges_iter(u, data=True)
                 if d['a'] == a]
        assert len(edges) == 1

    # determinize output b arbitrarily,
    # but output c is constrained to the initial value 0
    detmach = synth.determinize_machine_init(mach, {'c': 0})

    for a in {0, 1}:
        edges = [(i, j, d) for (i, j, d) in detmach.edges_iter(u, data=True)
                 if d['a'] == a]
        assert len(edges) == 1

        ((i, j, d), ) = edges
        assert j == 1
        assert d['b'] == 1
Beispiel #8
0
def garage_counter(ploting=True):
    """Example 3.4, p.49 [LS11], for M=2

    no state variables in this Finite-State Machine
    """
    m = trs.MealyMachine()

    m.add_inputs({'up': {'present', 'absent'}, 'down': {'present', 'absent'}})

    m.add_outputs({'count': range(3)})

    m.states.add_from(range(3))
    m.states.initial.add(0)

    m.transitions.add(0, 1, up='present', down='absent', count=1)
    m.transitions.add(1, 0, up='absent', down='present', count=0)

    m.transitions.add(1, 2, up='present', down='absent', count=2)
    m.transitions.add(2, 1, up='absent', down='present', count=1)

    if ploting:
        m.plot()

    return m
Beispiel #9
0
def mealy_machine_example():
    import numpy as np

    class check_diaphragm():
        """camera f-number."""
        def is_valid_value(x):
            if x <= 0.7 or x > 256:
                raise TypeError('This f-# is outside allowable range.')

        def __contains__(self, guard):
            # when properly implemented, do appropriate syntactic check
            if isinstance(guard, float):
                return True

            return False

        def __call__(self, guard_set, input_port_value):
            """This method "knows" that we are using x to denote the input
            within guards."""
            self.is_valid_value(input_port_value)

            guard_var_def = {'x': input_port_value}
            guard_value = eval(guard_set, guard_var_def)

            if not isinstance(guard_value, bool):
                raise TypeError('Guard value is non-boolean.\n'
                                'A guard is a predicate, '
                                'so it can take only boolean values.')

    class check_camera():
        """is it looking upwards ?"""
        def is_valid_value(self, x):
            if x.shape != (3,):
                raise Exception('Not a 3d vector!')

        def __contains__(self, guard):
            # when properly implemented, do appropriate syntactic check
            if isinstance(guard, np.ndarray) and guard.shape == (3,):
                return True

            return False

        def __call__(self, guard_set, input_port_value):
            self.is_valid_value(input_port_value)

            v1 = guard_set # guard_halfspace_normal_vector
            v2 = input_port_value # camera_direction_vector

            if np.inner(v1, v2) > 0.8:
                return True

            return False

    # note: guards are conjunctions,
    # any disjunction is represented by 2 edges

    # input defs
    inputs = [
        ('speed', {'zero', 'low', 'high', 'crazy'} ),
        ('seats', trs.PowerSet(range(5) ) ),
        ('aperture', check_diaphragm() ),
        ('camera', check_camera() )
    ]

    # outputs def
    outputs = [('photo', {'capture', 'wait'} ) ]

    # state variables def
    state_vars = [('light', {'on', 'off'} ) ]

    # define the machine itself
    m = trs.MealyMachine()

    m.add_state_vars(state_vars)
    m.add_inputs(inputs)
    m.add_outputs(outputs)

    m.states.add('s0')
    m.states.add_from(['s1', 's2'])
    m.states.initial.add('s0')

    m.transitions.add(
        's0', 's1',
        speed='low',
        seats=(0, 1),
        aperture=0.3,
        camera=np.array([0,0,1]),
        photo='capture'
    )

    guard = {'camera':np.array([1,1,1]),
             'speed':'high',
             'aperture':0.3,
             'seats':(2, 3),
             'photo':'wait'}
    m.transitions.add('s1', 's2', **guard)

    m.plot(rankdir='TB')

    return m
Beispiel #10
0
def quotient_mealy(mealy, node_relation=None, relabel=False, outputs={'loc'}):
    """Returns the quotient graph of ``G`` under the specified equivalence
    relation on nodes.

    Parameters
    ----------
    mealy : NetworkX graph
       The graph for which to return the quotient graph with the specified node
       relation.

    node_relation : Boolean function with two arguments
       This function must represent an equivalence relation on the nodes of
       ``G``. It must take two arguments *u* and *v* and return ``True``
       exactly when *u* and *v* are in the same equivalence class. The
       equivalence classes form the nodes in the returned graph.


        unlike the original networkx.quotient_graph selfloops are maintained  

    relabel : Boolean
        if true relabel nodes in the graph 

    outputs :  Tells which outputs are critical and should be kept. Given as a set of strings.

    """
    if node_relation is None:
        node_relation = lambda u, v: mealy.states.post(u) == mealy.states.post(
            v)

    q_mealy = transys.MealyMachine()
    q_mealy.add_inputs(mealy.inputs)
    q_mealy.add_outputs(mealy.outputs)
    # Compute the blocks of the partition on the nodes of G induced by the
    # equivalence relation R.
    if relabel:
        mapping = dict(
            (n, i)
            for (i, n) in enumerate(equivalence_classes(mealy, node_relation)))
        for (n, i) in mapping.items():
            if {'Sinit'} <= set(n):
                mapping[n] = 'Sinit'
        q_mealy.add_nodes_from({n for (i, n) in mapping.items()})
    else:
        q_mealy.add_nodes_from(equivalence_classes(mealy, node_relation))

    if relabel:
        block_pairs = it_product(mapping.keys(), mapping.keys())
        for (b, c) in block_pairs:
            labels = {
                frozenset([(key, label[key]) for key in mealy.inputs.keys()] +
                          [(output, label[output]) for output in outputs])
                for (x, y, label) in mealy.transitions.find(b, c)
            }
            for q in labels:
                q_mealy.transitions.add(mapping[b], mapping[c], **dict(q))
    else:
        block_pairs = it_product(q_mealy, q_mealy)
        for (b, c) in block_pairs:
            labels = {
                frozenset([(key, label[key]) for key in mealy.inputs.keys()] +
                          [(output, label[output]) for output in outputs])
                for (x, y, label) in mealy.transitions.find(b, c)
            }
            for q in labels:
                q_mealy.transitions.add(b, c, **dict(q))

    if relabel:
        for node_eq in mapping.keys():
            if any(init in node_eq for init in mealy.states.initial):
                q_mealy.states.initial.add(mapping[node_eq])
    else:  # only initializing  after relabel
        for node_eq in q_mealy.nodes():
            if any(init in node_eq for init in mealy.states.initial):
                q_mealy.states.initial.add(node_eq)

    return q_mealy
Beispiel #11
0
def strategy2mealy(A, spec):
    """Convert strategy to Mealy transducer.

    Note that the strategy is a deterministic game graph,
    but the input C{A} is given as the contraction of
    this game graph.

    @param A: strategy
    @type A: C{networkx.DiGraph}

    @type spec: L{GRSpec}

    @rtype: L{MealyMachine}
    """
    assert len(A) > 0
    logger.info('converting strategy (compact) to Mealy machine')
    env_vars = spec.env_vars
    sys_vars = spec.sys_vars
    mach = transys.MealyMachine()
    inputs = transys.machines.create_machine_ports(env_vars)
    mach.add_inputs(inputs)
    outputs = transys.machines.create_machine_ports(sys_vars)
    mach.add_outputs(outputs)
    str_vars = {k: v for k, v in env_vars.items() if isinstance(v, list)}
    str_vars.update({k: v for k, v in sys_vars.items() if isinstance(v, list)})
    mach.states.add_from(A)
    # transitions labeled with I/O
    for u in A:
        for v in A.successors_iter(u):
            d = A.node[v]['state']
            d = _int2str(d, str_vars)
            mach.transitions.add(u, v, **d)

            logger.info('node: {v}, state: {d}'.format(v=v, d=d))
    # special initial state, for first reaction
    initial_state = 'Sinit'
    mach.states.add(initial_state)
    mach.states.initial.add(initial_state)
    # fix an ordering for keys
    # because tuple(dict.items()) is not safe:
    # https://docs.python.org/2/library/stdtypes.html#dict.items
    try:
        u = next(iter(A))
        keys = A.node[u]['state'].keys()
    except Exception:
        logger.warning('strategy has no states.')
    # to store tuples of dict values for fast search
    # isinit = spec.compile_init(no_str=True)
    # Previous line is the original. Use this module's isinit_test() to create
    # transitions to only specified initial conditions.
    isinit = isinit_test(spec, True)
    # Mealy reaction to initial env input
    init_valuations = set()
    tmp = dict()

    for u, d in A.nodes_iter(data=True):
        var_values = d['state']
        vals = tuple(var_values[k] for k in keys)
        # already an initial valuation ?
        if vals in init_valuations:
            continue
        # add edge: Sinit -> u ?
        tmp.update(var_values)
        if eval(isinit, tmp):
            label = _int2str(var_values, str_vars)
            mach.transitions.add(initial_state, u, **label)
            # remember variable values to avoid
            # spurious non-determinism wrt the machine's memory
            #
            # in other words,
            # "state" omits the strategy's memory
            # hidden (existentially quantified)
            # so multiple nodes can be labeled with the same state
            #
            # non-uniqueness here would be equivalent to
            # multiple choices for initializing the hidden memory.
            init_valuations.add(vals)
            logger.debug('found initial state: {u}'.format(u=u))
        logger.debug('machine vertex: {u}, has var values: {v}'.format(
            u=u, v=var_values))
    n = len(A)
    m = len(mach)
    assert m == n + 1, (n, m)
    if not mach.successors('Sinit'):
        raise Exception('The machine obtained from the strategy '
                        'does not have any initial states !\n'
                        'The strategy is:\n'
                        'vertices:' + pprint.pformat(A.nodes(data=True)) +
                        2 * '\n' + 'edges:\n' + str(A.edges()) + 2 * '\n' +
                        'and the machine:\n' + str(mach) + 2 * '\n' +
                        'and the specification is:\n' + str(spec.pretty()) +
                        2 * '\n')
    return mach