Esempio n. 1
0
    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()
Esempio n. 2
0
    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
Esempio n. 3
0
    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
Esempio n. 4
0
    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')
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
# 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()
Esempio n. 8
0
# 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)])
Esempio n. 9
0
# (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: