def optimal_run(t, formula, opt_prop): try: logger.info('T has %d states', len(t.g)) # Convert formula to Buchi automaton b = Buchi() b.from_formula(formula) logger.info('B has %d states', len(b.g)) # Compute the product automaton p = ts_times_buchi(t, b) logger.info('P has %d states', len(p.g)) logger.info('Set F has %d states', len(p.final)) # Find the set S of states w/ opt_prop s = p.nodes_w_prop(opt_prop) logger.info('Set S has %d states', len(s)) # Compute the suffix_cycle* and suffix_cycle_cost* suffix_cycle_cost, suffix_cycle_on_p = min_bottleneck_cycle( p.g, s, p.final) # Compute the prefix: a shortest path from p.init to suffix_cycle prefix_length = float('inf') prefix_on_p = [''] i_star = 0 for init_state in p.init.keys(): for i in range(0, len(suffix_cycle_on_p)): length, prefix = source_to_target_dijkstra( p.g, init_state, suffix_cycle_on_p[i], degen_paths=True) if (length < prefix_length): prefix_length = length prefix_on_p = prefix i_star = i if (prefix_length == float('inf')): raise Exception(__name__, 'Could not compute the prefix.') # Wrap suffix_cycle_on_p as required if i_star != 0: # Cut and paste suffix_cycle_on_p = suffix_cycle_on_p[i_star:] + suffix_cycle_on_p[ 1:i_star + 1] # Compute projection of prefix and suffix-cycle to T and return suffix_cycle = [x[0] for x in suffix_cycle_on_p] prefix = [x[0] for x in prefix_on_p] return (prefix_length, prefix, suffix_cycle_cost, suffix_cycle) except Exception as ex: if (len(ex.args) == 2): print("{}: {}".format(*ex.args)) else: print("{}: Unknown exception {}: {}".format( __name__, type(ex), ex)) exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_tb(exc_traceback) exit(1)
def test_ts_times_buchi(): ts = Ts.load('./simple_network.yaml') print('Loaded transition system of size', ts.size()) ts.visualize(edgelabel='weight', draw='matplotlib') plt.show() for u, d in ts.g.nodes_iter(data=True): print u, d print for u, v, d in ts.g.edges_iter(data=True): print u, v, d spec = 'G (F a && F g && !e)' buchi = Buchi() buchi.from_formula(spec) print('Created Buchi automaton of size', buchi.size()) buchi.visualize(draw='matplotlib') plt.show() print for u, d in buchi.g.nodes_iter(data=True): print u, d print for u, v, d in buchi.g.edges_iter(data=True): print u, v, d pa = ts_times_buchi(ts, buchi) print('Created product automaton of size', pa.size()) pa.visualize(draw='matplotlib') plt.show() print for u, d in pa.g.nodes_iter(data=True): print u, d print for u, v, d in pa.g.edges_iter(data=True): print u, v, d cost, prefix, suffix = policy_buchi_pa(pa) print('cost:', cost) print('prefix:', prefix) print('suffix:', suffix)
def compute_sync_seqs(ts_tuple, rhos, tts, b, prefix, suffix): """ Compute synchronization sequences for each, i.e. wait sets, for each agent so that correctness in the field is guaranteed. Parameters ---------- ts_tuple: Tuple of transition system objects ts_tuple[i] is the transition that models agent i. tts: A transition system object tts is the team transition system that models the asynchronous behavior of the team of agents who are individually modeled as the transition systems in ts_tuple. b: A buchi object This is the buchi automaton that corresponds to the negation of the mission specification. prefix: A list of tuples This is the prefix of the run on the team transition system tts. suffix: A list of tuples This is the suffix of the run on the team transition system tts. Results ------- wait_sets: A 2-D list of sets wait_sets[i][j] gives the list of agents that agent i must wait at position j of the run before satisfying any propositions at that state and proceeding with the next position in its run. """ # Indeces of the agents agents = list(range(0, len(ts_tuple))) # Run is prefix + suffix after removing duplicate states run = prefix[0:-1] + suffix[0:-1] suffix_start = len(prefix) - 1 logger.debug('suffix start:%d, run:%s', suffix_start, run) # Everyone goes in lock-step by default wait_sets = [[set(agents) - {ii} for jj in run] for ii in agents] for pos in range(0, len(run)): logger.info("Considering position %d" % pos) if pos == 0: logger.info("Skipping initial position") continue if pos == suffix_start: logger.info("Skipping suffix start") continue # Heuristic, check no sync before considering # agents individually for this_agent in agents: wait_sets[this_agent][pos] = set() field_ts = construct_field_event_ts(agents, rhos, ts_tuple, tts, run, wait_sets, suffix_start) p = ts_times_buchi(field_ts, b) if empty_language(p): logger.info('Heuristic succeeded!') continue # Revert wait sets for this position to their default values logger.info('Heuristic did not help...') for this_agent in agents: wait_sets[this_agent][pos] = set(agents) - {this_agent} for this_agent in agents: for that_agent in set(agents) - {this_agent}: logger.info("Removing %s from %s's wait set", that_agent, this_agent) wait_sets[this_agent][pos].remove(that_agent) # Generate the field TS field_ts = construct_field_event_ts(agents, rhos, ts_tuple, tts, run, wait_sets, suffix_start) # Take the product p = ts_times_buchi(field_ts, b) # Check if the language of inverted formula is empty if empty_language(p): logger.info('Empty Language') else: logger.info('Non-empty language') # Revert change made to wait set of this_agent wait_sets[this_agent][pos].add(that_agent) return wait_sets