are_isomorphic.cc 4.43 KB
Newer Older
1
// -*- coding: utf-8 -*-
2
// Copyright (C) 2014, 2015 Laboratoire de Recherche et
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// Développement de l'Epita (LRDE).
// Copyright (C) 2004, 2005  Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// 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/>.

#include "tgba/tgbagraph.hh"
#include "tgbaalgos/are_isomorphic.hh"
25
#include "tgbaalgos/canonicalize.hh"
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
#include "tgbaalgos/isdet.hh"
#include <vector>
#include <queue>

namespace
{
  typedef spot::tgba_digraph::graph_t::trans_storage_t tr_t;
  bool
  tr_t_less_than(const tr_t& t1, const tr_t& t2)
  {
    return t1.cond.id() < t2.cond.id();
  }

  bool
  operator!=(const tr_t& t1, const tr_t& t2)
  {
    return t1.cond.id() != t2.cond.id();
  }

  bool
  are_isomorphic_det(const spot::const_tgba_digraph_ptr aut1,
                     const spot::const_tgba_digraph_ptr aut2)
  {
    typedef std::pair<unsigned, unsigned> state_pair_t;
    std::queue<state_pair_t> workqueue;
    workqueue.emplace(aut1->get_init_state_number(),
                      aut2->get_init_state_number());
    std::vector<unsigned> map(aut1->num_states(), -1U);
    map[aut1->get_init_state_number()] = aut2->get_init_state_number();
    std::vector<tr_t> trans1;
    std::vector<tr_t> trans2;
    state_pair_t current_state;
    while (!workqueue.empty())
      {
        current_state = workqueue.front();
        workqueue.pop();

        for (auto& t : aut1->out(current_state.first))
          trans1.emplace_back(t);
        for (auto& t : aut2->out(current_state.second))
          trans2.emplace_back(t);

        if (trans1.size() != trans2.size())
          return false;

        std::sort(trans1.begin(), trans1.end(), tr_t_less_than);
        std::sort(trans2.begin(), trans2.end(), tr_t_less_than);

        for (auto t1 = trans1.begin(), t2 = trans2.begin();
             t1 != trans1.end() && t2 != trans2.end();
             ++t1, ++t2)
          {
            if (*t1 != *t2)
              {
                return false;
              }
            if (map[t1->dst] == -1U)
              {
                map[t1->dst] = t2->dst;
                workqueue.emplace(t1->dst, t2->dst);
              }
            else if (map[t1->dst] != t2->dst)
              {
                return false;
              }
          }

        trans1.clear();
        trans2.clear();
      }
    return true;
  }

  bool
  trivially_different(const spot::const_tgba_digraph_ptr aut1,
                      const spot::const_tgba_digraph_ptr aut2)
  {
    return aut1->num_states() != aut2->num_states() ||
      aut1->num_transitions() != aut2->num_transitions() ||
105 106 107
      // FIXME: At some point, it would be nice to support reordering
      // of acceptance sets (issue #58).
      aut1->acc().get_acceptance() != aut2->acc().get_acceptance();
108 109
  }
}
110 111 112

namespace spot
{
113 114
  isomorphism_checker::isomorphism_checker(const const_tgba_digraph_ptr ref)
  {
115
    ref_ = make_tgba_digraph(ref, twa::prop_set::all());
116 117 118 119 120 121 122 123 124
    ref_deterministic_ = ref_->is_deterministic();
    if (!ref_deterministic_)
      {
        nondet_states_ = spot::count_nondet_states(ref_);
        ref_deterministic_ = (nondet_states_ == 0);
      }
    canonicalize(ref_);
  }

125
  bool
126
  isomorphism_checker::is_isomorphic(const const_tgba_digraph_ptr aut)
127
  {
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    if (trivially_different(ref_, aut))
      return false;

    if (ref_deterministic_)
      {
        if (aut->is_deterministic() || spot::is_deterministic(aut))
          {
            return are_isomorphic_det(ref_, aut);
          }
      }
    else
      {
        if (aut->is_deterministic() ||
            nondet_states_ != spot::count_nondet_states(aut))
          {
            return false;
          }
      }

147
    auto tmp = make_tgba_digraph(aut, twa::prop_set::all());
148 149
    spot::canonicalize(tmp);
    return *tmp == *ref_;
150 151
  }
}