예제 #1
0
def language_inclusion(aut1, aut2):
    """
    Verify that language of L{aut1} is a sub-set of the language of L{aut2}.

    @param aut1: Automaton with smallest language.
    @type  aut1: L{Automaton}

    @param aut2: Automaton with biggest language.
    @type  aut2: L{Automaton}

    @return: Indication whether the condition holds (L{aut1} has a language
             subset of L{aut2}).
    @rtype:  C{bool}
    """
    aut1 = supervisor.unweighted_determinization(aut1)

    aut2 = supervisor.unweighted_determinization(aut2)
    aut2 = supervisor.complement(aut2)

    prod = product.n_ary_unweighted_product([aut1, aut2])
    for state in prod.get_states():
        if state.marked:
            return False

    return True
예제 #2
0
def compute_weighted_supervisor(comp, req):
    """
    Compute weighted supervisor.

    @param comp: Available component (weighted automaton).
    @type  comp: C{WeightedAutomaton}

    @param req: Available requirement (unweighted automaton).
    @type  req: C{UnweightedAutomaton}

    @return: Resulting supervisor (unweighted automaton).
    @type:   C{UnweightedAutomaton}

    @note: It starts the same way as L{compute_optimal_weighted_supervisor}.
    """
    # Compute supremal supervisor without considering weight.
    wsup = compute_weight.compute_weighted_supremal(comp, req)
    if wsup is None:
        return None

    obs_alphabet = set(evt for evt in comp.alphabet if evt.observable)
    waut2 = weighted_projection.weighted_projection(wsup, obs_alphabet)
    waut2 = weighted_determinization(waut2)
    weight_map = compute_weight.compute_state_weights(waut2,
                                                    marker_valfn = lambda s: 0)

    props = algorithm.ManagerProperties(waut2.collection)
    props.aut_type = algorithm.UNWEIGHTED_AUT
    props.alphabet = waut2.alphabet
    props.marker_func = algorithm.MARKED_ANY
    props.explore_mgr = algorithm.ORIGINAL_STATE
    props.edge_calc = algorithm.COPY_LABEL

    mgr = algorithm.Manager(props)

    mgr.set_initial((waut2.initial,))
    while True:
        state = mgr.get_next()
        if state is None:
            break

        state = state[0]
        for edge in state.get_outgoing():
            dest_weight = maxplus.otimes(weight_map[edge.succ], edge.weight)
            if maxplus.equal(weight_map[state], dest_weight) or \
                    maxplus.biggerthan(weight_map[state], dest_weight):
                mgr.add_edge((edge.pred,), (edge.succ,), [edge])

    unw_comp = conversion.remove_weights(comp)
    result = product.n_ary_unweighted_product([unw_comp, mgr.get_automaton()])

    return result
예제 #3
0
def make_minimal_weighted_supervisor(plant, req, new_fname):
    """
    Compute deterministic weighted supervisor for non-deterministic plant and
    deterministic requirements.

    @param plant: Filename of the non-deterministic weighted (but not
                  minimally) automaton.
    @type  plant: C{str}

    @param req: Filename of the requirements as deterministic non-weighted
                automaton.
    @type  req: C{str}

    @param new_fname: Filename of the created deterministic controller.
    @type  new_fname: C{str}
    """
    common.print_line("Started minimal weighted supervisor computations "
                      "(version %s)" % automata.version)
    coll = collection.Collection()

    plant_waut = load_weighted_automaton(coll, plant, False, True)
    req_aut = frontend.load_automaton(coll, req, False, True)
    wsup = compute_weight.compute_weighted_supremal(plant_waut, req_aut)
    if wsup is None:
        new_aut = None
    else:
        observables = set(
            [evt for evt in plant.events.itervalues() if evt.observable])
        check_marking_aware(wsup, observables)
        wsup2 = weighted_projection.weighted_projection(wsup, observables)
        new_aut = compute_weight.minimal_weight_deterministic_controllable(
            wsup2)
    if new_aut is None:
        common.print_line("No minimal weight controller found!")

    else:
        unw_plant = conversion.remove_weights(plant_waut)
        prod = product.n_ary_unweighted_product([unw_plant, new_aut[0]])
        result = supervisor.unweighted_determinization(prod)

        common.print_line("Minimum weight is %s" % new_aut[1])
        frontend.save_automaton(result,
                                "Saving minimal weight controller in %s",
                                new_fname)
예제 #4
0
def abstract_obervables(plant, sup):
    """
    Reduce the supervisor to contain only observable transitions between
    states and self loops for non-observable events.

    @param plant: Plant automaton.
    @type  plant: L{Automaton}

    @param sup: Supervisor with observable and non-observable transitions.
    @type  sup: L{Automaton}

    @return: Reduced supervisor.
    @rtype:  L{Automaton}
    """
    prod = product.n_ary_unweighted_product([sup, plant])
    det_prod = unweighted_determinization(prod)
    prod.clear()

    observables = set([
        evt for evt in det_prod.alphabet if evt.observable or evt.name == 'tau'
    ])
    obs_sup, obsup_map = natural_projection_map(det_prod, observables)

    non_observables = det_prod.alphabet.difference(observables)

    obs_sup.add_event_set(non_observables)

    for det_stateset, obssup_state in obsup_map.iteritems():
        events = set(edge.label for state in det_stateset
                     for edge in state.get_outgoing())

        # Get non-observable events from the set of det-states
        events = events.intersection(non_observables)

        for evt in events:
            obs_sup.add_edge_data(obssup_state, obssup_state, evt)

    obsup_map.clear()
    det_prod.clear()  # Used by obsup_map

    return obs_sup
예제 #5
0
def row_vector_compute(plant, req_names, evt_pairs, row_vector_names,
                       operator_class):
    coll = collection.Collection()
    comp_list = weighted_frontend.load_weighted_automata(
        coll, plant, False, True)
    req_list = frontend.load_automata(coll, req_names, False, True)
    evt_pairs = taskresource.process_event_pairs(coll, req_list, evt_pairs)
    result = taskresource.compute_custom_eventdata(comp_list, evt_pairs)
    if result is None:
        common.print_line('Could not compute the event data from the '
                          'components and event pairs\n'
                          'Perhaps they are inconsistent?')
        return

    eventdata, heap_len = result

    plant = weighted_product.n_ary_weighted_product(
        comp_list, algorithm.EQUAL_WEIGHT_EDGES)
    requirement = product.n_ary_unweighted_product(req_list)

    for comp in comp_list:
        comp.clear()
    del comp_list

    wsup = compute_weight.compute_weighted_supremal(plant, requirement)
    if wsup is None:
        return None
    requirement.clear()
    del requirement

    row_zero_mat = maxplus.make_rowmat(0, heap_len)
    row_epsilon_mat = maxplus.make_rowmat(maxplus.INFINITE, heap_len)

    marker_valfn = lambda state: row_zero_mat
    nonmarker_valfn = lambda state: row_epsilon_mat

    row_vecs = compute_state_row_vector(wsup, marker_valfn, nonmarker_valfn,
                                        eventdata, operator_class)

    return row_vecs
예제 #6
0
def make_product(aut_fnames, result_fname, preserve_names = False):
    """
    Multiply the automata in the L{aut_fnames} list, and write the result to
    L{result_fname}.

    @param aut_fnames: Comma-seperated list of automata filenames.
    @type  aut_fnames: C{str}

    @param result_fname: Filename for writing the resulting automaton.
    @type  result_fname: C{str}

    @param preserve_names: Try to preserve state names in the product.
    @type  preserve_names: C{bool}
    """
    common.print_line("Started product computations (version %s)"
                        % automata.version)
    coll = collection.Collection()

    aut_list = load_automata(coll, aut_fnames, False, False)
    result = product.n_ary_unweighted_product(aut_list, True, True,
                                              preserve_names)

    dump_stats("Computed product", result)
    save_automaton(result, "Product is saved in %s\n", result_fname)
예제 #7
0
def make_supervisor(plants, specs, verbose=True):
    """
    Construct a supervisor for the L{plants} that behaves safely within the
    L{specs} requirements.

    @param plants: Plant automata.
    @type  plants: C{list} of L{BaseAutomaton}

    @param specs: Requirements specification automata.
    @type  specs: C{list} of L{BaseAutomaton}

    @return: Supervisor automaton if it exists, C{None} otherwise.
    @rtype: L{Automaton} or C{None}
    """
    assert len(plants) > 0
    assert len(specs) > 0

    # The iteration below replaces the specs by its own automaton.
    # To prevent leaking automata, these own automata should be deleted
    # before exit.
    delete_specs = False

    deterministic_and_all_observable = True
    # Check that all events are observable
    for plant in plants:
        for evt in plant.alphabet:
            if not evt.observable:
                deterministic_and_all_observable = False
                break

    if deterministic_and_all_observable:
        # Check that plant is deterministic
        for plant in plants:
            for state in plant.get_states():
                evts = set()  #: Set of events encountered at a state.
                for edge in state.get_outgoing():
                    if edge.label in evts:
                        deterministic_and_all_observable = False
                        break
                    evts.add(edge.label)

    while True:  # make_supervisor() is an iterative function

        result = controllable_coreachable_product(plants, specs, verbose)
        if result is None:
            if delete_specs:
                for spec in specs:
                    spec.clear()
            return None

        if deterministic_and_all_observable:  # We are finished!
            if delete_specs:
                for spec in specs:
                    spec.clear()
            return result[0]

        chi_aut, boundary_disableds = result

        if len(boundary_disableds) == 0:
            if delete_specs:
                for spec in specs:
                    spec.clear()
            return unweighted_determinization(chi_aut)

        #
        # Construct automaton A
        #
        aut_A = data_structure.Automaton(chi_aut.alphabet.copy(),
                                         chi_aut.collection)

        for state in chi_aut.coreachable_states_set(
                set(boundary_disableds.keys()), None):
            aut_A.add_new_state(marked=False, num=state.number)

        assert aut_A.has_state(chi_aut.initial.number)
        aut_A.set_initial(aut_A.get_state(chi_aut.initial.number))

        # Copy edges
        for state in chi_aut.get_states():
            if not aut_A.has_state(state.number):
                continue

            for edge in state.get_outgoing():
                if not aut_A.has_state(edge.succ.number):
                    continue

                aut_A.add_edge_data(aut_A.get_state(state.number),
                                    aut_A.get_state(edge.succ.number),
                                    edge.label)
        # Add dump state
        dump_state = aut_A.add_new_state(True)
        for state, disableds in boundary_disableds.iteritems():
            for disabled in disableds:
                aut_A.add_edge_data(aut_A.get_state(state.number), dump_state,
                                    disabled)

        # Self-loops for all events in dump-state
        for evt in aut_A.alphabet:
            aut_A.add_edge_data(dump_state, dump_state, evt)

        A2 = unweighted_determinization(aut_A)
        b = A2.reduce(False, True)
        assert b

        A3 = projection(A2)
        A4 = inverse_projection(A3)

        A2.clear()
        A3.clear()

        A5 = product.n_ary_unweighted_product([chi_aut, A4])

        marked = False
        for state in A5.get_states():
            if state.marked:
                marked = True
                break
        if not marked:
            A4.clear()
            A5.clear()
            if delete_specs:
                for spec in specs:
                    spec.clear()

            return unweighted_determinization(chi_aut)

        A5.clear()

        A6 = complement(A4)
        A7 = unweighted_determinization(
            product.n_ary_unweighted_product([chi_aut, A6]))
        b = A7.reduce(False, True)
        if not b:
            if delete_specs:
                for spec in specs:
                    spec.clear()
            return None

        A4.clear()
        A6.clear()

        # Iteration:
        # plants = plants
        specs = [A7]
        delete_specs = True
예제 #8
0
def sequential_abstraction(automata_list, target_events):
    """
    Perform a sequence of abstraction and product computation steps

    @param automata_list: List of automata
    @type  automata_list: C{list} of L{Automaton}

    @param target_events: List of events to preserve after abstraction
    @type  target_events: C{set} of L{Event}

    @return: An automaton
    @rtype: L{Automaton}
    """
    assert len(automata_list) > 0

    coll = automata_list[0].collection
    common.print_line("Started")

    # Paranoia check, all automata should use the same collection
    for aut in automata_list:
        assert aut.collection is coll

    # Setup for first automaton
    k = 1
    t_k = compute_t(1, automata_list, target_events)
    aut_k = automata_list[k - 1]
    msg = "#states after adding %d automata: %d" % (k, aut_k.get_num_states())
    common.print_line(msg)

    result = abstraction(aut_k, t_k)

    msg = "#states and #transitions after abstraction: %d, %d" \
                            % (result.get_num_states(), result.get_num_edges())
    common.print_line(msg)
    k = k + 1

    # For each automaton 2..len(automata_list) (including upper-bound)
    while k <= len(automata_list):
        prev_result = result

        aut_k = automata_list[k - 1]

        prod = product.n_ary_unweighted_product([prev_result, aut_k])

        msg = "#states of %d automata: %d; #states and #transitions " \
              "of product: %d %d" % (k, aut_k.get_num_states(),
                                    prod.get_num_states(), prod.get_num_edges())
        common.print_line(msg)

        t_k = compute_t(k, automata_list, target_events)
        result = abstraction(prod, t_k)

        msg = "#states and #transitions after abstraction: %d, %d" \
                            % (result.get_num_states(), result.get_num_edges())
        common.print_line(msg)

        # Remove intermediate results from collection
        prev_result.clear()
        prod.clear()

        k = k + 1

    return result