def __init__(self, input_alphabets, formal_arg_names): self.input_alphabets = input_alphabets self.formal_arg_names = formal_arg_names if len(self.input_alphabets) != len(self.formal_arg_names): raise Exception( 'Number of inputs must match number of formal arguments ({} vs {})' .format(self.input_alphabets, self.formal_arg_names)) self.states = [] self.state_num_map = {} self.state_name_map = {} self.state_num = 0 self.hoa_aut = spot.make_twa_graph() self.var_map = VarMap() self.bdds = {} for formal, base in zip(self.formal_arg_names, self.input_alphabets): self.var_map[formal] = [ BuchiAutomaton.fresh_ap() for _ in range(base_len(base)) ] self.bdds[formal] = [ buddy.bdd_ithvar(self.hoa_aut.register_ap(ap)) for ap in self.var_map[formal] ] self.hoa_aut.set_buchi()
def build(self): """Create an ω-automaton for the rewrite graph""" # A transition-based ω-automaton graph (in C++ we could have defined # this structure on the fly, but not from Python) twa = spot.make_twa_graph(self.bdd_dict) # Register and get the BDD variables for the atomic propositions self._register_aprops(twa) # Depth-first exploration of the graph while creating the TωA pending = [0] self.state_map = {0: twa.new_state()} # self._state_label(self.graph.getStateTerm(0)) while pending: state = pending.pop() state_spot = self.state_map[state] for next_state in self.graph.getNextStates(state): next_state_spot = self.state_map.get(next_state) if next_state_spot is None: next_state_spot = twa.new_state() self.state_map[next_state] = next_state_spot pending.append(next_state) # Check the iteration tags and set the accepting labels of the edges next_state_term = self.instance.get_cterm( self.graph.getStateTerm(next_state)) acc_set = [] for tag, enter in self.instance.extract_tags( self.graph.getStateTerm(next_state)): acc_index = self.iter_map.get(tag) if acc_index is None: acc_index = len(self.iter_map) self.iter_map[tag] = acc_index acc_set.append(2 * acc_index + (0 if enter else 1)) twa.new_edge(state_spot, next_state_spot, self._state_label(next_state_term), acc_set) twa.set_init_state(self.state_map[0]) # Set the acceptance condition acc_condition = ' & '.join([ f'(Fin({2 * n}) | Inf({2 * n + 1}))' for n in range(len(self.iter_map)) ]) if acc_condition != '': twa.set_acceptance(2 * len(self.iter_map), acc_condition) return twa
def toSpot(self, bdict=default_bdd_dict): """ Translate a (generalized) buchi automaton into bdd in spot package :param bdict: the bdd_dict that the output automaton uses :return: an spot generalized buchi automaton """ aut = spot.make_twa_graph(bdict) ap_list = dict() state_map = dict() for ap in self.ap_list: # if ap not in ['0', '1']: ap_list[ap] = buddy.bdd_ithvar(aut.register_ap(ap)) aut.set_generalized_buchi(self.acc_num) aut.prop_state_acc(1) new_index = 0 for index, state in self.state_dict.items(): aut.new_state() state_map[index] = new_index new_index = new_index + 1 aut.set_init_state(state_map[self.getInitState()]) for edge in self.edge_list: acc = self.getStateAcc(edge.src) ap_calc_list = parse(edge.ap, ops, re_splitter) ap_stack = list() for token in ap_calc_list: if token == '!': ap_stack[-1] = -ap_stack[-1] elif token == '&': ap_stack[-2] = ap_stack[-1] & ap_stack[-2] ap_stack.pop() elif token == '|': ap_stack[-2] = ap_stack[-1] | ap_stack[-2] ap_stack.pop() elif token in self.ap_list: ap_stack.append(ap_list[token]) elif token == '0': ap_stack.append(buddy.bddfalse) elif token == '1': ap_stack.append(buddy.bddtrue) else: raise Exception('Unknown AP token %s in edge formula' % token) if len(ap_stack) != 1: raise Exception('Wrong edge AP formula format!') aut.new_edge(state_map[edge.src], state_map[edge.dst], ap_stack[0], acc) return aut, state_map
def shuffle(self, disjunction=False): new_aut = spot.make_twa_graph() # We want to make sure that it visits infinitely often BOTH automata's accepting states if disjunction: new_aut.set_acceptance(2, 'Inf(0) | Inf(1)') else: new_aut.set_acceptance(2, 'Inf(0) & Inf(1)') new_aut.new_states(2 * self.aut_a.num_states() * self.aut_b.num_states()) idx = 0 for i in ['a', 'b']: for qa in range(self.aut_a.num_states()): for qb in range(self.aut_b.num_states()): self.state_encoding[(i, qa, qb)] = idx idx += 1 for ap in self.aut_a.ap(): buddy.bdd_ithvar(new_aut.register_ap(ap.ap_name())) for ap in self.aut_b.ap(): buddy.bdd_ithvar(new_aut.register_ap(ap.ap_name())) a_init = self.aut_a.get_init_state_number() b_init = self.aut_b.get_init_state_number() new_aut.set_init_state(self.state_encoding[('a', a_init, b_init)]) for e in self.aut_a.edges(): for qb in range(self.aut_b.num_states()): src = self.state_encoding[('a', e.src, qb)] dst = self.state_encoding[('b', e.dst, qb)] acc = self.transform_acc(e.acc, 0) # print('Adding edge: {} -> {} with cond {} and acc {}'.format(src, dst, spot.bdd_to_formula(e.cond), acc)) new_aut.new_edge(src, dst, e.cond, acc) for e in self.aut_b.edges(): for qa in range(self.aut_a.num_states()): src = self.state_encoding[('b', qa, e.src)] dst = self.state_encoding[('a', qa, e.dst)] acc = self.transform_acc(e.acc, 1) # print('Adding edge: {} -> {} with cond {} and acc {}'.format(src, dst, spot.bdd_to_formula(e.cond), acc)) new_aut.new_edge(src, dst, e.cond, acc) return new_aut.postprocess('BA')
def custom_product(negG_aut, g_aut): bdict = negG_aut.get_dict() if g_aut.get_dict() != bdict: raise RuntimeError("automata should share their dictionary") result = spot.make_twa_graph(bdict) result.copy_ap_of(negG_aut) result.copy_ap_of(g_aut) sdict = {} todo = [] def dst(ls, rs): pair = (ls, rs) p = sdict.get(pair) if p is None: p = result.new_state() sdict[pair] = p todo.append((ls, rs, p)) return p result.set_init_state(dst(negG_aut.get_init_state_number(), g_aut.get_init_state_number())) result.set_buchi() result.prop_state_acc(True) new_dead_states = [] while todo: lsrc, rsrc, osrc = todo.pop() if negG_aut.state_is_accepting(lsrc): for lt in negG_aut.out(lsrc): for rt in g_aut.out(rsrc): result.new_edge(osrc, osrc, lt.cond, [0]) continue for lt in negG_aut.out(lsrc): for rt in g_aut.out(rsrc): cond = lt.cond & rt.cond if cond != buddy.bddfalse: result.new_edge(osrc, dst(lt.dst, rt.dst), cond) result.merge_states() result.merge_edges() result.purge_dead_states() return result
def buchi_transform(original_aut, builder): # Build a new automata with different edges new_aut = spot.make_twa_graph() # Set the acceptance condition to be same as the input automata acc = original_aut.get_acceptance() new_aut.set_acceptance(acc.used_sets().max_set(), acc) new_aut.new_states(original_aut.num_states()) new_aut.set_init_state(original_aut.get_init_state_number()) builder.pre_build(new_aut) ne = original_aut.num_edges() if settings.get_debug_level() > 2: import sys for i, e in enumerate(original_aut.edges()): cond = builder.build_cond(e.cond) new_aut.new_edge(e.src, e.dst, cond, e.acc) if i % 10000 == 0: sys.stdout.write('\r{} of {} edges ({:.2f}%)'.format( i, ne, 100 * i / ne)) print() else: # TODO: This does the same thing as above, but it just doesn't run the check/print every time. # We could run the same loop and check for debug every time, but this minor overhead # accumulates a fair bit once you get to having millions of edges, so we duplicate it. # It would still be nice to avoid this, though. for e in original_aut.edges(): cond = builder.build_cond(e.cond) new_aut.new_edge(e.src, e.dst, cond, e.acc) builder.post_build(new_aut) return new_aut
# under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # Spot is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import spot # Test case reduced from a report from Juraj Major <*****@*****.**>. a = spot.make_twa_graph(spot._bdd_dict) a.set_acceptance(0, spot.acc_code("t")) assert (a.prop_state_acc() == True) a.set_acceptance(1, spot.acc_code("Fin(0)")) assert (a.prop_state_acc() == spot.trival.maybe()) # Some tests for used_inf_fin_sets(), which return a pair of mark_t. (inf, fin) = a.get_acceptance().used_inf_fin_sets() assert inf == [] assert fin == [0] (inf, fin) = spot.acc_code("(Fin(0)|Inf(1))&Fin(2)&Inf(0)").used_inf_fin_sets() assert inf == [0, 1] assert fin == [0, 2] # is_rabin_like() returns (bool, [(inf, fin), ...]) (b, v) = spot.acc_cond("(Fin(0)&Inf(1))|(Fin(2)&Inf(0))").is_rabin_like()
# under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # Spot is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import spot import buddy aut = spot.make_twa_graph(spot._bdd_dict) p1 = buddy.bdd_ithvar(aut.register_ap("p1")) p2 = buddy.bdd_ithvar(aut.register_ap("p2")) m = aut.set_buchi() aut.new_states(3) aut.set_init_state(0) aut.new_univ_edge(0, [1, 2], p1, m) aut.new_univ_edge(0, [0, 1], p2) aut.new_univ_edge(1, [0, 2, 1], p1 & p2) aut.new_edge(2, 2, p1 | p2) tr = [(s, [[x for x in aut.univ_dests(i)] for i in aut.out(s)])
# (at your option) any later version. # # Spot is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # This file tests various error conditions on the twa API import spot from buddy import bddtrue aut = spot.make_twa_graph(spot.make_bdd_dict()) try: print(aut.to_str()) exit(2) except RuntimeError as e: assert "no state" in str(e) try: aut.set_init_state(2) except ValueError as e: assert "nonexisting" in str(e) try: aut.set_univ_init_state([2, 1]) except ValueError as e: