def IntervalToTick(aut): tickaut = data_structure.Automaton(aut.alphabet, aut.collection) dictionary = {} tickaut.initial = tickaut.add_new_state(aut.initial.marked) dictionary[aut.initial] = tickaut.initial tovisit = [aut.initial] if 'tick' not in aut.collection.events: aut.collection.make_event('tick', False, True, False) tick = aut.collection.events['tick'] infinity = float('inf') edgestoadd = [] while len(tovisit) != 0: intstate = tovisit.pop() tickstate = dictionary[intstate] maxticks = max([edge.l if edge.r == infinity else edge.r + 1 for edge in intstate.get_outgoing()]) tickstates = [tickstate] + [tickaut.add_new_state(tickstate.marked) for i in range(maxticks)] edgestoadd.extend([data_structure.Edge(tickstate[i], tickstate[i+1], tick) for i in range(maxticks)]) edgestoadd.append(data_structure.Edge(tickstate[maxticks+1], tickstate[maxticks+1], tick)) for edge in intstate.get_outgoing(): if edge.succ not in dictionary: newstate = tickaut.add_new_state(edge.succ.marked) dictionary[edge.succ] = newstate tovisit.append(newstate) succstate = dictionary[edge.succ] l,r = edge.l, min(maxticks, edge.r)+1 for i in range(l,r): edgestoadd.append(data_structure.Edge(tickstates[i], succstate, edge.label)) tickaut.add_edges(edgestoadd) return tickaut
def automaton_abstraction(aut): """ Compute new automaton by means of bisimularity computation with reduced number of states. @param aut: Input automaton @type aut: L{Automaton} @return: Reduced automaton @rtype: L{Automaton} """ # Compute partition partition_list = bisimilarity_partition(aut) # Construct new automaton based on bisimularity results new_aut = data_structure.Automaton(aut.alphabet, aut.collection) new_aut.set_kind(aut.aut_kind) state_map = {} # Mapping of old state -> new_state for number, partition in enumerate(partition_list): # Decide on marker property of the partition assert len(partition) > 0 # Get a value from the set without modifying it state = iter(partition).next() new_state = new_aut.add_new_state(marked = state.marked, num = number) for state in partition: state_map[state] = new_state # Set initial state new_aut.initial = state_map[aut.initial] # Add edges # # Since the Automaton silently drops duplicate edges, we will have unique # edges for state in aut.get_states(): for edge in state.get_outgoing(): new_aut.add_edge_data(state_map[state], state_map[edge.succ], edge.label) # Clearing local data state_map.clear() return new_aut
def convert_ads_file(ads_fname, coll): """ Load ADS file, convert it to internal data format, and return the result. @param ads_fname: Filename of the ADS file to load. @type ads_fname: C{str} @param coll: Collection to store the events of the automaton. @type coll: L{Collection} @return: Converted automaton. @rtype: L{Automaton} """ handle = open(ads_fname, 'r') _name, state_size, marker_lines, vocal_states, trans = read_ads_file(handle) assert len(vocal_states) == 0 # Vocal states are not supported atm. # Construct/query events of the automaton. evts = {} observable = True for src, evtnum, dest in trans: if evtnum not in evts: evt = coll.make_event(str(evtnum), evtnum & 1, observable, False) evts[evtnum] = evt aut = data_structure.Automaton(set(evts.itervalues()), coll) if marker_lines == ['*']: marker_states = None # All states are marker state. else: marker_states = set(marker_lines) # Construct all states in the automaton. for num in range(state_size): aut.add_new_state(marker_states is None or num in marker_states, num) aut.set_initial(aut.get_state(0)) for src, evtnum, dest in trans: srcstate = aut.get_state(src) deststate = aut.get_state(dest) aut.add_edge_data(srcstate, deststate, evts[evtnum]) return aut
def prune_tree_automaton(wunfolded, weightmap): """ Reduce the tree automaton L{wunfolded} by pruning away everything except the paths to the leafs with the lowest value. @param wunfolded: Weighted tree automaton. @type wunfolded: L{WeightedAutomaton} @param weightmap: Mapping of weighted states to weight (C{maxplus.INFINITE} for infinite). @type weightmap: C{dict} of L{WeightedState} to C{int}/C{maxplus.INFINITE} @return: Pruned tree automaton. @rtype: L{Automaton} @note: Weight at the edges is not used. """ coll = wunfolded.collection pruned = data_structure.Automaton(wunfolded.alphabet, coll) ini_state = wunfolded.initial minval = weightmap[ini_state] assert minval is not None ini_s = pruned.add_new_state(ini_state.marked, ini_state.number) pruned.set_initial(ini_s) notdone = [ini_state] while len(notdone) > 0: state = notdone.pop() for edge in state.get_outgoing(): assert weightmap[edge.succ] is not None # Temp paranoia check if weightmap[edge.succ] is maxplus.INFINITE: continue # Infinite weight is always bigger than minval if weightmap[edge.succ] <= minval: nst = pruned.add_new_state(edge.succ.marked, edge.succ.number) notdone.append(edge.succ) pruned.add_edge_data(pruned.get_state(state.number), nst, edge.label) else: assert weightmap[edge.succ] > minval return pruned
def heap_unfold_product(aut_list, eventdata, heap_len, distances_to_marker, shortest_path): result_alphabet = set() for aut in aut_list: result_alphabet.update(aut.alphabet) plant = data_structure.Automaton(result_alphabet, aut_list[0].collection) mapping = {} heap_map = {} aut_resource_usage = calc_resource_usage(aut_list, eventdata, heap_len) initial_state_mapping = tuple(aut.initial for aut in aut_list) initial_state = plant.add_new_state(marker_calc(initial_state_mapping)) plant.set_initial(initial_state) mapping[initial_state] = initial_state_mapping heap_map[initial_state] = maxplus.make_rowmat(0, heap_len) shortest_path_max = 0 for comp, path in shortest_path.items(): if path > shortest_path_max: shortest_path_max = path traverse(comp_list, plant, initial_state, mapping, heap_map, eventdata, aut_resource_usage, distances_to_marker, shortest_path_max) return plant
def construct_greedy_progressive_supervisor_epuck(aut, resources, progressive_events, triples, L): sup = data_structure.Automaton(set(aut.alphabet), aut.collection) dict = {} to_process = [] f_index = find_index(triples, aut.initial, len(triples)-1) sup.initial = sup.add_new_state(aut.initial.marked) sup.initial.collisions = aut.initial.collisions dict[(aut.initial, f_index)] = sup.initial to_process.append((aut.initial, f_index)) while (to_process): state, k = to_process.pop(0) sup_source = dict[(state, k)] theta, _, _ = triples[k][state] for edge in state.get_outgoing(): if edge.label not in progressive_events: f_index = find_index(triples, edge.succ, len(triples)-1) if (edge.succ, f_index) not in dict: dict[(edge.succ, f_index)] = sup.add_new_state(edge.succ.marked) to_process.append((edge.succ, f_index)) sup_target = dict[(edge.succ, f_index)] sup.add_edge_data(sup_source, sup_target, edge.label) else: f_index = find_index(triples, edge.succ, k-1) if f_index == -1: continue _, Q, _ = triples[f_index][edge.succ] contour = rev_res_plus(Q, edge) norm = calculate_norm(contour, L) print str(norm) + " " + str(theta) + " " + str(f_index) + " " + str(k) if (norm <= theta): if (edge.succ, f_index) not in dict: dict[(edge.succ, f_index)] = sup.add_new_state(edge.succ.marked) to_process.append((edge.succ, f_index)) dict[(edge.succ, f_index)].collisions = edge.succ.collisions sup_target = dict[(edge.succ, f_index)] sup.add_edge_data(sup_source, sup_target, edge.label) for state in sup.get_states(): for edge in state.get_outgoing(): edge.weight = 1 return sup
def remove_weights(waut): """ Remove the weights of weighted automaton L{waut}. @param waut: Weighted automaton. @type waut: L{collection.WeightedAutomaton} @return: Equivalent unweighted automaton. @rtype: L{collection.Automaton} """ aut = data_structure.Automaton(waut.alphabet, waut.collection) aut.set_kind(waut.aut_kind) for wstat in waut.get_states(): aut.add_new_state(wstat.marked, wstat.number) aut.set_initial(aut.get_state(waut.initial.number)) for wstat in waut.get_states(): src = aut.get_state(wstat.number) for wedge in wstat.get_outgoing(): dest = aut.get_state(wedge.succ.number) aut.add_edge_data(src, dest, wedge.label) return aut
def natural_projection_map(aut, preserved): """ Project an automaton on preserved events. For each cluster of states (connected with each other through non-preserved events), find the next cluster for each preserved event by computing the union of reachable state clusters (from the original cluster, do the preserved event for all states, and merge all states reachable through non-preserved events after the transition). @param aut: Automaton to project. @type aut: L{Automaton} @param preserved: Set of event of the automaton to preserve. @type preserved: C{set} of L{Event} @return: Automaton reduced to L{preserved} events, and a state map. @rtype: L{Automaton}, and a C{dictionary} of a C{set} of L{State} from the original automaton to a L{State} in the returned automaton. """ non_preserved = aut.alphabet.difference(preserved) new_aut = data_structure.Automaton(preserved.copy(), aut.collection) def add_new_state(states, state_map, new_aut, notdone_list): frozen_states = frozenset(states) if frozen_states in state_map: return state_map[frozen_states] marked = False for state in states: if state.marked: marked = True break s = new_aut.add_new_state(marked) state_map[frozen_states] = s notdone_list.append((frozen_states, s)) return s state_map = {} notdone_list = [] states = aut.reachable_states(aut.initial, non_preserved) new_aut.set_initial(add_new_state(states, state_map, new_aut, notdone_list)) while len(notdone_list) > 0: states, new_state = notdone_list.pop() outgoing_events = set(edge.label for state in states for edge in state.get_outgoing()) for evt in preserved.intersection(outgoing_events): dest_states = set() for state in states: for edge in state.get_outgoing(evt): if edge.succ not in dest_states: dest_states.update( aut.reachable_states(edge.succ, non_preserved)) # else: edge.succ already handled if len(dest_states) > 0: s2 = add_new_state(dest_states, state_map, new_aut, notdone_list) new_aut.add_edge_data(new_state, s2, evt) return new_aut, state_map
def make_supervisor_optimized(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_optimized( plants, specs, verbose) #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) return tau_abstraction.subsetconstructionnotweighted( chi_aut, set(), 0) # # 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 edgestoadd = [] 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) edgestoadd.append( data_structure.Edge(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) edgestoadd.append( data_structure.Edge(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) edgestoadd.append(data_structure.Edge(dump_state, dump_state, evt)) aut_A.add_edges(edgestoadd) #A2 = unweighted_determinization(aut_A) A2 = tau_abstraction.subsetconstructionnotweighted(aut_A, set(), 0) b = A2.reduce(False, True) assert b #A3 = projection(A2) A3 = tau_abstraction.subsetconstructionnotweighted( A2, set([evt for evt in A2.alphabet if not evt.observable]), 0) #A4 = inverse_projection(A3) A4 = inverse_projection_optimized(A3) A2.clear() A3.clear() #A5 = product.n_ary_unweighted_product([chi_aut, A4]) A5 = tau_abstraction.synchronousproduct([chi_aut, A4], 0) 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) return tau_abstraction.subsetconstructionnotweighted( chi_aut, set(), 0) A5.clear() #A6 = complement(A4) A6 = complement_optimized(A4) #A7 = unweighted_determinization( #product.n_ary_unweighted_product([chi_aut, A6])) chiA6 = tau_abstraction.synchronousproduct([chi_aut, A6], 0) A7 = tau_abstraction.subsetconstructionnotweighted(chiA6, set(), 0) 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
def controllable_coreachable_product_optimized(plants, specs, verbose=True): """ Compute the controllable and co-reachable sub set of a product. @param plants: Plant automata. @type plants: C{list} of L{BaseAutomaton} @param specs: Specification automata. @type specs: C{list} of L{BaseAutomaton} @return: C{None} if empty automaton reached, or (L{Automaton}, disableds) where disableds is a map of automaton states to set of disabled events """ #prod_aut, bad_states = compute_products(plants, specs, verbose) prod_aut, bad_states = tau_abstraction.synchronousproduct_supervisor( plants, specs, 0) prod_aut.reduce(True, False) # Construct controllable_states uncontrollables = set(evt for evt in prod_aut.alphabet if not evt.controllable) controllable_states = set() for state in prod_aut.get_states(): if state not in bad_states: controllable_states.add(state) while True: # Find coreachable states in L{controllable_states} coreachable_states = set() notdone_list = [] for state in prod_aut.get_states(): if state not in controllable_states: continue if state.marked: coreachable_states.add(state) notdone_list.append(state) while len(notdone_list) > 0: state = notdone_list.pop() for edge in state.get_incoming(): if edge.pred not in controllable_states: continue if edge.pred not in coreachable_states: coreachable_states.add(edge.pred) notdone_list.append(edge.pred) bad_states = supervisor_product.coreachable_bad_states( prod_aut, controllable_states.difference(coreachable_states), uncontrollables) if len(bad_states) == 0: break controllable_states = coreachable_states.difference(bad_states) coreachable_states.clear() bad_states.clear() if prod_aut.initial not in controllable_states: return None # Construct a new automaton from the reachable and controllable subset new_aut = data_structure.Automaton(prod_aut.alphabet, prod_aut.collection) def new_state(old_state, new_aut, notdone_list): if not new_aut.has_state(old_state.number): s = new_aut.add_new_state(old_state.marked, num=old_state.number) notdone_list.append(old_state) return s else: return new_aut.get_state(old_state.number) # Copy states boundary_disableds = {} # Map of chi states to set of disabled events notdone_list = [] s = new_state(prod_aut.initial, new_aut, notdone_list) new_aut.set_initial(s) edgestoadd = [] while len(notdone_list) > 0: state = notdone_list.pop() for edge in state.get_outgoing(): if edge.succ not in controllable_states: # Found an edge that leads to outside the controllable # subset, make a note of it # Find the same state as 'state' in the new automaton equiv_state = new_aut.get_state(state.number) if equiv_state not in boundary_disableds: boundary_disableds[equiv_state] = set([edge.label]) else: boundary_disableds[equiv_state].add(edge.label) continue # Ignore the state in the copying process new_state(edge.succ, new_aut, notdone_list) # Copy edges for state in prod_aut.get_states(): if not new_aut.has_state(state.number): continue for edge in state.get_outgoing(): if not new_aut.has_state(edge.succ.number): continue edgestoadd.append( data_structure.Edge(new_aut.get_state(state.number), new_aut.get_state(edge.succ.number), edge.label)) #new_aut.add_edge_data(new_aut.get_state(state.number), #new_aut.get_state(edge.succ.number), edge.label) new_aut.add_edges(edgestoadd) prod_aut.clear() return new_aut, boundary_disableds
def model_conversion(aut, preserved_events): """ Compute automaton with only observable events. @note: If marker events are to be preserved, they should be added to the L{preserved_events} by the user. @param aut: Original automaton @type aut: L{Automaton} @param preserved_events: Observable events @type preserved_events: C{set} of C{Event} @return: Reduced automaton @rtype: L{Automaton} """ non_preserved_events = aut.alphabet.difference(preserved_events) new_aut = data_structure.Automaton(preserved_events, aut.collection) def get_new_state(old_state): """ From a state of the old automaton (old_state), return the associated state of the new automaton (or create one) """ if not new_aut.has_state(old_state.number): new_state = new_aut.add_new_state(marked = old_state.marked, num = old_state.number) return new_state return new_aut.get_state(old_state.number) for state in aut.get_states(): for edge in state.get_outgoing(): if edge.label in preserved_events or edge.label.marker: reachables = aut.reachable_states(edge.succ, non_preserved_events) coreachables = aut.coreachable_states(state, non_preserved_events) for start_state in coreachables: # Find or create same start state in new automaton new_start = get_new_state(start_state) for dest_state in reachables: # Find or create same dest state in new automaton new_dest = get_new_state(dest_state) new_aut.add_edge_data(new_start, new_dest, edge.label) reachables.clear() coreachables.clear() # Initial state must have a path with an observable event to make the # line below hold new_aut.set_initial(new_aut.get_state(aut.initial.number)) valid_aut = new_aut.reduce(reachability = True) assert valid_aut == True non_preserved_events.clear() return new_aut
def setup(self, props): self.aut = data_structure.Automaton(props.alphabet, props.coll)
def dothis(local_alphabet): print local_alphabet.pop() coll = collection.Collection() comp_list = weighted_frontend.load_weighted_automata(coll, "plant1.cfg", False, True) local_alphabet = comp_list[0].alphabet print local_alphabet dothis(local_alphabet) print local_alphabet temp_coll = collection.Collection() temp_automaton = weighted_structure.WeightedAutomaton(local_alphabet, temp_coll) # temp_automaton.add_new_state(False, comp_list[0].initial.number) for state in comp_list[0].get_states(): ns = temp_automaton.add_new_state(state.marked, state.number) for state in comp_list[0].get_states(): for edge in state.get_outgoing(): if edge.label in local_alphabet: print "this happends" new_edge = edge.copy(temp_automaton.get_state(edge.pred.number), temp_automaton.get_state(edge.succ.number)) temp_automaton.add_edge(new_edge) temp_automaton.initial = temp_automaton.get_state(comp_list[0].initial.number) temp_automaton.reduce(True, True) temp_req = data_structure.Automaton(set([next(iter(local_alphabet))]), temp_coll) print temp_automaton.initial.get_outgoing().pop()
def progressive_synthesis(automaton, resources, progressive_events): #print progressive_events tim = -time() automaton = finite_makespan_restricted(automaton, progressive_events) supervisor = data_structure.Automaton(set(automaton.alphabet), automaton.collection) zero_contour = frozendict() for r in resources: zero_contour[r] = 0 init = supervisor.add_new_state(automaton.initial.marked) init.x = automaton.initial init.x_f = zero_contour dictionary = {} dictionary[(init.x, init.x_f)] = init supervisor.initial = init to_process = [init] Q = {} num_uncont = {} covered_uncont = {} Q_process = set() while to_process: state = to_process.pop() x, x_f = state.x, state.x_f uncont = 0 for edge in state.x.get_outgoing(): if edge.label in progressive_events and not edge.label.controllable: uncont = uncont + 1 y, y_f = edge.succ, ground(res_plus(x_f, edge)) if (y, y_f) not in dictionary: new_state = supervisor.add_new_state(y.marked) dictionary[(y, y_f)] = new_state new_state.x = y new_state.x_f = y_f to_process.append(new_state) succ_state = dictionary[(y, y_f)] new_edge = data_structure.Edge(state, succ_state, edge.label) new_edge.weight = edge.weight supervisor.add_edge(new_edge) #supervisor.add_edge_data(state, succ_state, edge.label) if not state.marked or uncont != 0: Q[state] = None else: Q[state] = ceil(x_f) Q_process.add(state) num_uncont[state] = uncont covered_uncont[state] = 0 print "states: " + str(supervisor.get_num_states()) print supervisor while Q_process: print len(Q_process) Q_processnew = set() for state in Q_process: if num_uncont[state] > 0: m = None for edge in state.get_outgoing(): if edge.label in progressive_events and not edge.label.controllable: temp = floor(res_plus(state.x_f, edge)) + Q[edge.succ] if (m == None): m = temp else: m = max(m, temp) if (Q[state] == m): continue Q[state] = m for edge in state.get_incoming(): if edge.label in progressive_events: if edge.label.controllable and num_uncont[edge.pred] == 0: temp = floor(res_plus(edge.pred.x_f, edge)) + Q[state] if Q[edge.pred] == None: Q[edge.pred] = temp Q_processnew.add(edge.pred) for edge2 in edge.pred.get_incoming(): if edge2.label in progressive_events and not edge2.label.controllable: covered_uncont[edge2.pred] = covered_uncont[edge2.pred] + 1 elif (temp < Q[edge.pred]): Q[edge.pred] = temp if edge.pred not in Q_processnew: Q_processnew.add(edge.pred) elif not edge.label.controllable and num_uncont[edge.pred] == covered_uncont[edge.pred]: temp = floor(res_plus(edge.pred.x_f, edge)) + Q[state] if (Q[edge.pred] == None): for edge2 in edge.pred.get_incoming(): if edge2.label in progressive_events and not edge2.label.controllable: covered_uncont[edge2.pred] = covered_uncont[edge2.pred] + 1 if (Q[edge.pred] == None or temp < Q[edge.pred]): Q_processnew.add(edge.pred) if (len(Q_processnew) == 0): break else: Q_process = Q_processnew edgestoremove = [] for state in supervisor.get_states(): for edge in state.get_outgoing(): if edge.label in progressive_events: temp = floor(res_plus(edge.pred.x_f, edge)) + Q[edge.succ] if Q[state] < temp: edgestoremove.append(edge) for edge in edgestoremove: supervisor.remove_edge(edge) supervisor.reduce(True, True) print supervisor tim = tim + time() print tim return supervisor, Q[automaton.initial]