def __init__(self, event, duration, resources): """ Constructor. @param event: Event. @type event: L{Event} @param duration: Duration of the use. @type duration: C{int} or C{float} @param resources: Available resources (alphabets). @type resources: C{list} of C{set} of L{Event} """ self.event = event self.duration = duration self.used = [(event in res) for res in resources] mat = self._compute_mat(resources, event, duration) q_tilde = [ self._q_tilde_val(event in res, duration) for res in resources ] q_check = [ self._q_check_val(event in res, duration) for res in resources ] q_check_mat = maxplus.ColumnMatrix(q_check) q_tilde_mat = maxplus.RowMatrix(q_tilde) multiply = maxplus.otimes_mat_mat(q_check_mat, q_tilde_mat) qq = maxplus.oplus_mat_mat(maxplus.make_unit_matrix(len(resources)), multiply) self.matHat = maxplus.otimes_mat_mat(mat, qq)
def reduce_automaton_row_vecors(waut, wvalues, evtdata, num_res, rvecs): """ Reduce the weighted automaton. @param waut: (Weighted) automaton (the weight is not used). @type waut: L{Automaton} @param wvalues: Column matrix data, associated with each state in L{waut}. @type wvalues: L{maxplus.DataCollection} @param evtdata: Event information. @type evtdata: L{EventData} @param num_res: Number of resources. @type num_res: C{int} @param start: Start vector (row-matrix), if specified. @type start: C{None}, or L{maxplus.DataCollection} @return: Reduced automaton. @rtype: L{Automaton} """ waut = waut.copy() # Make a copy wvalues = dict((st.number, val) for st, val in wvalues.iteritems()) # Do a breadth-first expansion over the automaton. #: Mapping of states to their row matrix value. seen_states = set([waut.initial]) not_done = [waut.initial] while len(not_done) > 0: # Since we do a breadth-first expansion, make a new 'not_done' # from scratch on each iteration. new_not = [] for state in not_done: #rval = maxplus.make_rowmat(0, num_res) rval = rvecs[state] sval = maxplus.otimes_mat_mat(rval, wvalues[state.number]) toremove = [] for edge in state.get_outgoing(): result = maxplus.otimes_mat_mat(rval, evtdata[edge.label].matHat) cm = maxplus.otimes_mat_mat(result, wvalues[edge.succ.number]) if cm.get_scalar() <= sval.get_scalar(): # Keep the edge. if edge.succ not in seen_states: # It is a new state. seen_states.add(edge.succ) new_not.append(edge.succ) else: # Drop the edge. #waut.remove_edge(edge) toremove.append(edge) for edge in toremove: waut.remove_edge(edge) # Next iteration. not_done = new_not waut.reduce(True, True) return waut
def add_abstracted_tau_paths(aut, eventdata, cliques, start_state, end_state, evt_path): new_tau_evt_name = "tau" for evt in evt_path: if evt.name.find("tau") == 0: new_tau_evt_name = new_tau_evt_name + "-(" + evt.name + ")" else: new_tau_evt_name = new_tau_evt_name + "-" + evt.name new_tau_evt = aut.collection.make_event(new_tau_evt_name, True, True, False) if not new_tau_evt in aut.alphabet: aut.alphabet.add(new_tau_evt) aut.add_edge_data(start_state, end_state, new_tau_evt, 1) # fake init of ExtendedEventData tau_evt_data = taskresource.ExtendedEventData( new_tau_evt, 0, set([frozenset(aut.alphabet)])) # setting of actual resources and Matrix tau_evt_data.used = [] for i in range(len(eventdata[evt_path[0]].used)): tau_evt_data.used.append(False) for j in range(len(evt_path)): if eventdata[evt_path[j]].used[i] == True: tau_evt_data.used[i] = True break tau_evt_data.matHat = eventdata[evt_path[0]].matHat for i in range(1, len(evt_path)): tau_evt_data.matHat = maxplus.otimes_mat_mat( tau_evt_data.matHat, eventdata[evt_path[i]].matHat) for i in range(len(tau_evt_data.matHat.data)): for j in range(len(tau_evt_data.matHat.data[i])): tau_evt_data.duration = maxplus.maximum( tau_evt_data.duration, tau_evt_data.matHat.data[i][j]) eventdata[new_tau_evt] = tau_evt_data
def reduce_automaton_greedy_correctly(waut, wvalues, evtdata, num_res, L): """ Reduce the weighted automaton. @param waut: (Weighted) automaton (the weight is not used). @type waut: L{Automaton} @param wvalues: Column matrix data, associated with each state in L{waut}. @type wvalues: L{maxplus.DataCollection} @param evtdata: Event information. @type evtdata: L{EventData} @param num_res: Number of resources. @type num_res: C{int} @param start: Start vector (row-matrix), if specified. @type start: C{None}, or L{maxplus.DataCollection} @return: Reduced automaton. @rtype: L{Automaton} """ waut = waut.copy() # Make a copy wvalues = dict((st.number, val) for st, val in wvalues.iteritems()) # Do a breadth-first expansion over the automaton. #: Mapping of states to their row matrix value. seen_states = set([waut.initial]) not_done = [waut.initial] while len(not_done) > 0: # Since we do a breadth-first expansion, make a new 'not_done' # from scratch on each iteration. new_not_done = [] for state in not_done: for edge in list(state.get_outgoing()): mq = maxplus.otimes_mat_mat(evtdata[edge.label].matHat, wvalues[edge.succ.number]) th = wvalues[edge.pred.number] if compute_weight.compute_norm(mq, L) <= compute_weight.compute_norm(th, L): # Keep the edge. if edge.succ not in seen_states: # It is a new state. seen_states.add(edge.succ) new_not_done.append(edge.succ) else: # Drop the edge. waut.remove_edge(edge) # Next iteration. not_done = new_not_done waut.reduce(True, True) return waut
def make_greedy_time_optimal_supervisor_row_vectors(comp_names, req_names, evt_pairs, sup_name, row_vectors, operator): """ Compute a greedy time optimal supervisor. @param comp_names: Available components (weighted automata). @type comp_names: C{list} of L{str} @param req_names: Available requirements (unweighted automata). @type req_names: C{list} of L{str} @param evt_pairs: Additional event pairs (eg "{(a, b), (c, e)}", "type1", or "type2") @type evt_pairs: C{str} @param sup_name: Name of the resulting supervisor. @type sup_name: C{str} """ common.print_line("Started greedy time optimal supervisor " "computation (version %s)" % automata.version) coll = collection.Collection() comp_list = load_weighted_automata(coll, comp_names, 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 result = compute_weight.compute_greedy_time_optimal_supervisor( comp_list, req_list, eventdata, heap_len, row_vectors, operator) if result is None: common.print_line('Could not compute the weighted supervisor') return wsup, wmap = result one = maxplus.make_rowmat(0, heap_len) one = maxplus.otimes_mat_mat(one, wmap[wsup.initial]) biggest = one.get_scalar() common.print_line("Sub-optimal makespan is %s" % biggest) wsup = weighted_supervisor.reduce_automaton_row_vecors( wsup, wmap, eventdata, heap_len, row_vectors) frontend.dump_stats("Computed weighted supervisor", wsup) save_weighted_automaton(wsup, "Supervisor is saved in %s\n", sup_name)
def enhance_compute_state_row_vector(aut, marker_valfn, nonmarker_valfn, eventdata, operate_class): """ Compute row vector of each state Attach a weight to each state, and iteratively update these weights until a stable situation is found. - Initial setup: - Marker states have weight 'marker_valfn(state)'. - Other states have weight 'nonmarker_valfn(state)' - Update rules: Update until all weights are stable. @param aut: Weighted automaton. @type aut: L{WeightedAutomaton} @return: Dictionary of states to their row vector. @rtype: C{dict} of L{WeightedState} to (C{int} or C{None} if infinite) @todo: THIS CODE LOOKS LIKE A DUPLICATE """ # 1. Compute state information for each state. computation = {} for state in aut.get_states(): if state.marked: computation[state] = (MARKER_STATE, ) # continue # Non-marked states edges = [] #: Edges collected so far controllable = True #: Collect controllable edges # Collect successor states from 'state' by event. evt_dests = {} #: event to list (weight, dest-state). controllable = True #: State has only edges with controllable events. for edge in state.get_outgoing(): weight_dests = evt_dests.get(edge.label) if weight_dests is None: weight_dests = [] evt_dests[edge.label] = weight_dests controllable = (controllable and edge.label.controllable) weight_dests.append((edge.weight, edge.succ)) if controllable: # Keep all edges (all have controllable event label). edges = list(evt_dests.iteritems()) # assert len(edges) > 0 # Otherwise cannot compute min or max. computation[state] = (CONTROLLABLE, edges) else: # Only keep edges with uncontrollable event labels. edges = [(evt, dests) for evt, dests in evt_dests.iteritems() if not evt.controllable] #assert len(edges) > 0 # Otherwise cannot compute min or max. computation[state] = (UNCONTROLLABLE, edges) # 2. Initialize weights. row_vectors = {} #: Map of states to a set of row vectors. need_to_update = set() for state in computation.iteritems(): if state[0].number == MARKER_STATE: row_vectors[state[0]] = marker_valfn(state[0]) else: row_vectors[state[0]] = nonmarker_valfn(state[0]) need_to_update.update(compute_weight.pred_states(state[0])) count = 0 # 3. Iteratively update the row vector with new ones until stable. while True: count = count + 1 # Compute new row_vectors update_f = 0 for state, comp in computation.iteritems(): if state not in need_to_update: continue if comp[0] == MARKER_STATE: continue for evt, statedestlist in comp[1]: dest = (statedestlist[0])[1] tmp_vector = maxplus.otimes_mat_mat(row_vectors[state], eventdata[evt].matHat) if operate_class == 1: scalar1 = scalar_compute(tmp_vector) scalar2 = scalar_compute(row_vectors[dest]) if scalar_compare(scalar1, scalar2) == -1: row_vectors[dest] = tmp_vector update_f = 1 elif operate_class == 2: flag = -1 row_vectors[dest], flag = minimal_compute( tmp_vector, row_vectors[dest]) if flag == 0: update_f = 1 if update_f == 0: break return row_vectors
def compute_state_row_vector(aut, marker_valfn, nonmarker_valfn, eventdata, operate_class): """ Compute row vector of each state Attach a weight to each state, and iteratively update these weights until a stable situation is found. - Initial setup: - Marker states have weight 'marker_valfn(state)'. - Other states have weight 'nonmarker_valfn(state)' - Update rules: Update until all weights are stable. @param aut: Weighted automaton. @type aut: L{WeightedAutomaton} @return: Dictionary of states to their row vector. @rtype: C{dict} of L{WeightedState} to (C{int} or C{None} if infinite) @todo: THIS CODE LOOKS LIKE A DUPLICATE """ # 1. Compute state information for each state. computation = compute_weight.make_state_info_mapping(aut) # 2. Initialize weights. row_vectors = {} #: Map of states to a set of row vectors. need_to_update = set() for state, comp in computation.iteritems(): if state.number == MARKER_STATE: row_vectors[state] = marker_valfn(state) else: row_vectors[state] = nonmarker_valfn(state) need_to_update.update(compute_weight.pred_states(state)) count = 0 # 3. Iteratively update the row vector with new ones until stable. while True: count = count + 1 # Compute new row_vectors new_need_to_update = set() for state, comp in computation.iteritems(): if state not in need_to_update: continue if comp[0] == MARKER_STATE: continue for evt, statedestlist in comp[1]: dest = (statedestlist[0])[1] tmp_vector = maxplus.otimes_mat_mat(row_vectors[state], eventdata[evt].matHat) if vector_equal_compare(tmp_vector, row_vectors[dest]) != 0: new_need_to_update.update( compute_weight.pred_states(state)) if operate_class == 1: scalar1 = scalar_compute(tmp_vector) scalar2 = scalar_compute(row_vectors[dest]) if scalar_compare(scalar1, scalar2) == -1: row_vectors[dest] = tmp_vector elif operate_class == 2: row_vectors[dest], f = minimal_compute( tmp_vector, row_vectors[dest]) if len(new_need_to_update) == 0: break need_to_update = new_need_to_update for state, comp in computation.iteritems(): M = row_vectors[state] return row_vectors
def traverse(aut_list, plant, start_state, mapping, heap_map, eventdata, aut_resource_usage, distances_to_marker, shortest_path_max): global path_found if path_found: return if plant.get_num_states() % 1000 == 0: common.print_line("%d states traversed." % plant.get_num_states()) edges = [] disabled = set() for aut, state in zip(aut_list, mapping[start_state]): aut_edges = [] aut_events = set() for edge in state.get_outgoing(): aut_edges.append(edge) aut_events.add(edge.label) edges.append(aut_edges) disabled.update(aut.alphabet.difference(aut_events)) for evt in plant.alphabet.difference(disabled): if path_found: return target_mapping = calc_target(aut_list, mapping[start_state], evt) # state collision part, make it nicer state_name_list = [] for aut, state in zip(aut_list, target_mapping): for name in aut.state_names[state.number].split("_"): state_name_list.append(name) if len(state_name_list) > len(set(state_name_list)): continue target_heap = maxplus.otimes_mat_mat(heap_map[start_state], eventdata[evt].matHat) do_this_event = True if target_mapping in mapping.values(): do_this_event = False for state, map in mapping.items(): if map == target_mapping: for heap_old, heap_new in zip(heap_map[state].data[0], target_heap.data[0]): if heap_new < heap_old: do_this_event = True break if do_this_event == True: break if do_this_event == False: continue do_this_event = False for aut, start, target in zip(aut_list, mapping[start_state], target_mapping): if distances_to_marker[aut][start] > distances_to_marker[aut][target]: do_this_event = True break if do_this_event == False: continue for aut, start, target in zip(aut_list, mapping[start_state], target_mapping): if target_heap.data[0][aut_resource_usage[aut]] + distances_to_marker[aut][target] > shortest_path_max: do_this_event = False break if do_this_event == False: continue if do_this_event: # add target state to plant target_state = plant.add_new_state(marker_calc(target_mapping)) # add transition to plant new_edge = data_structure.Edge(start_state, target_state, evt) plant.add_edge(new_edge) # add mapping mapping[target_state] = target_mapping heap_map[target_state] = target_heap if marker_calc(target_mapping): path_found = True common.print_line("Path length:") print max(target_heap.data[0]) break else: traverse(aut_list, plant, target_state, mapping, heap_map, eventdata, aut_resource_usage, distances_to_marker, shortest_path_max)