diff --git a/src/graph/Makefile.am b/src/graph/Makefile.am index 858cc6980..04e01c39c 100644 --- a/src/graph/Makefile.am +++ b/src/graph/Makefile.am @@ -24,4 +24,6 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS) graphdir = $(pkgincludedir)/graph graph_HEADERS = \ - graph.hh + graph.hh \ + ngraph.hh + diff --git a/src/graph/ngraph.hh b/src/graph/ngraph.hh new file mode 100644 index 000000000..0eb3c505f --- /dev/null +++ b/src/graph/ngraph.hh @@ -0,0 +1,125 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2014 Laboratoire de Recherche et Développement de +// l'Epita. +// +// 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 . + +#ifndef SPOT_GRAPH_NGRAPH_HH +# define SPOT_GRAPH_NGRAPH_HH + +#include +#include +#include "graph.hh" + +namespace spot +{ + template , + typename Name_Equal = std::equal_to> + class named_graph + { + protected: + Graph& g_; + public: + + typedef typename Graph::state state; + typedef typename Graph::transition transition; + typedef State_Name name; + + typedef std::unordered_map name_to_state_t; + name_to_state_t name_to_state; + typedef std::vector state_to_name_t; + state_to_name_t state_to_name; + + named_graph(Graph& g) + : g_(g) + { + } + + Graph& graph() + { + return g_; + } + + Graph& graph() const + { + return g_; + } + + template + state new_state(name n, Args&&... args) + { + auto p = name_to_state.insert(std::make_pair(n, 0U)); + if (p.second) + { + unsigned s = g_.new_state(std::forward(args)...); + p.first->second = s; + if (state_to_name.size() < s + 1) + state_to_name.resize(s + 1); + state_to_name[s] = n; + return s; + } + return p.first->second; + } + + state get_state(name n) const + { + return name_to_state.at(n); + } + + name get_name(state s) const + { + return state_to_name.at(s); + } + + template + transition + new_transition(name src, name dst, Args&&... args) + { + return g_.new_transition(get_state(src), get_state(dst), + std::forward(args)...); + } + + template + transition + new_transition(name src, + const std::vector& dst, Args&&... args) + { + std::vector d; + d.reserve(dst.size()); + for (auto n: dst) + d.push_back(get_state(n)); + return g_.new_transition(get_state(src), d, std::forward(args)...); + } + + template + transition + new_transition(name src, + const std::initializer_list& dst, Args&&... args) + { + std::vector d; + d.reserve(dst.size()); + for (auto n: dst) + d.push_back(get_state(n)); + return g_.new_transition(get_state(src), d, std::forward(args)...); + } + }; + +} + +#endif // SPOT_GRAPH_NGRAPH_HH diff --git a/src/graphtest/Makefile.am b/src/graphtest/Makefile.am index f1c5ba60d..2863c728e 100644 --- a/src/graphtest/Makefile.am +++ b/src/graphtest/Makefile.am @@ -22,11 +22,12 @@ AM_CPPFLAGS = -I$(srcdir)/.. -I.. $(BUDDY_CPPFLAGS) AM_CXXFLAGS = $(WARNING_CXXFLAGS) LDADD = ../libspot.la -noinst_PROGRAMS = graph +noinst_PROGRAMS = graph ngraph graph_SOURCES = graph.cc +ngraph_SOURCES = ngraph.cc -TESTS = graph.test +TESTS = graph.test ngraph.test EXTRA_DIST = $(TESTS) diff --git a/src/graphtest/ngraph.cc b/src/graphtest/ngraph.cc new file mode 100644 index 000000000..70e324887 --- /dev/null +++ b/src/graphtest/ngraph.cc @@ -0,0 +1,362 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2014 Laboratoire de Recherche et Développement de +// l'Epita. +// +// 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 . + + +#include +#include "graph/ngraph.hh" + +template +void +dot_state(std::ostream& out, const spot::digraph& g, unsigned n) +{ + out << " [label=\"" << g.state_data(n) << "\"]\n"; +} + +template +void +dot_state(std::ostream& out, const spot::digraph&, unsigned) +{ + out << '\n'; +} + +template +void +dot_state(std::ostream& out, const spot::digraph& g, unsigned n, + std::string name) +{ + out << " [label=\"" << name << "\\n" << g.state_data(n) << "\"]\n"; +} + +template +void +dot_state(std::ostream& out, const spot::digraph&, unsigned, + std::string name) +{ + out << " [label=\"" << name << "\"]\n"; +} + + +template +void +dot_trans(std::ostream& out, const spot::digraph&, TR& tr) +{ + out << " [label=\"" << tr.data() << "\"]\n"; +} + +template +void +dot_trans(std::ostream& out, const spot::digraph&, TR&) +{ + out << '\n'; +} + + +template +void +dot(std::ostream& out, const spot::digraph& g) +{ + out << "digraph {\n"; + unsigned c = g.nb_states(); + for (unsigned s = 0; s < c; ++s) + { + out << ' ' << s; + dot_state(out, g, s); + for (auto& t: g.out(s)) + { + out << ' ' << s << " -> " << t.dst; + dot_trans(out, g, t); + } + } + out << "}\n"; +} + +template +void +dot(std::ostream& out, const spot::named_graph& g) +{ + out << "digraph {\n"; + auto& gg = g.graph(); + unsigned c = gg.nb_states(); + for (unsigned s = 0; s < c; ++s) + { + out << ' ' << s; + dot_state(out, gg, s, g.get_name(s)); + for (auto& t: gg.out(s)) + { + out << ' ' << s << " -> " << t.dst; + dot_trans(out, gg, t); + } + } + out << "}\n"; +} + + +bool g1(const spot::digraph& g, + unsigned s, int e) +{ + int f = 0; + for (auto& t: g.out(s)) + { + (void) t; + ++f; + } + return f == e; +} + +bool f1() +{ + spot::digraph g(3); + spot::named_graph, std::string> gg(g); + + auto s1 = gg.new_state("s1"); + auto s2 = gg.new_state("s2"); + auto s3 = gg.new_state("s3"); + gg.new_transition("s1", "s2"); + gg.new_transition("s1", "s3"); + gg.new_transition("s2", "s3"); + gg.new_transition("s3", "s1"); + gg.new_transition("s3", "s2"); + gg.new_transition("s3", "s3"); + + dot(std::cout, gg); + + int f = 0; + for (auto& t: g.out(s1)) + { + (void) t; + ++f; + } + return f == 2 + && g1(g, s3, 3) + && g1(g, s2, 1) + && g1(g, s1, 2); +} + + +bool f2() +{ + spot::digraph g(3); + spot::named_graph, std::string> gg(g); + + auto s1 = gg.new_state("s1", 1); + gg.new_state("s2", 2); + gg.new_state("s3", 3); + gg.new_transition("s1", "s2"); + gg.new_transition("s1", "s3"); + gg.new_transition("s2", "s3"); + gg.new_transition("s3", "s2"); + + dot(std::cout, gg); + + int f = 0; + for (auto& t: g.out(s1)) + { + f += g.state_data(t.dst); + } + return f == 5; +} + +bool f3() +{ + spot::digraph g(3); + spot::named_graph, std::string> gg(g); + + auto s1 = gg.new_state("s1"); + gg.new_state("s2"); + gg.new_state("s3"); + gg.new_transition("s1", "s2", 1); + gg.new_transition("s1", "s3", 2); + gg.new_transition("s2", "s3", 3); + gg.new_transition("s3", "s2", 4); + + dot(std::cout, gg); + + int f = 0; + for (auto& t: g.out(s1)) + { + f += t.label; + } + return f == 3 && g.states().size() == 3; +} + +bool f4() +{ + spot::digraph g(3); + spot::named_graph, std::string> gg(g); + + auto s1 = gg.new_state("s1", 2); + gg.new_state("s2", 3); + gg.new_state("s3", 4); + gg.new_transition("s1", "s2", 1); + gg.new_transition("s1", "s3", 2); + gg.new_transition("s2", "s3", 3); + gg.new_transition("s3", "s2", 4); + + dot(std::cout, gg); + + int f = 0; + for (auto& t: g.out(s1)) + { + f += t.label * g.state_data(t.dst); + } + return f == 11; +} + +bool f5() +{ + typedef spot::digraph> graph_t; + graph_t g(3); + spot::named_graph gg(g); + + auto s1 = gg.new_state("s1"); + gg.new_state("s2"); + gg.new_state("s3"); + gg.new_transition("s1", "s2", std::make_pair(1, 1.2f)); + gg.new_transition("s1", "s3", std::make_pair(2, 1.3f)); + gg.new_transition("s2", "s3", std::make_pair(3, 1.4f)); + gg.new_transition("s3", "s2", std::make_pair(4, 1.5f)); + + int f = 0; + float h = 0; + for (auto& t: g.out(s1)) + { + f += std::get<0>(t); + h += std::get<1>(t); + } + return f == 3 && (h > 2.49 && h < 2.51); +} + +bool f6() +{ + typedef spot::digraph> graph_t; + graph_t g(3); + spot::named_graph gg(g); + + auto s1 = gg.new_state("s1"); + gg.new_state("s2"); + gg.new_state("s3"); + gg.new_transition("s1", "s2", 1, 1.2f); + gg.new_transition("s1", "s3", 2, 1.3f); + gg.new_transition("s2", "s3", 3, 1.4f); + gg.new_transition("s3", "s2", 4, 1.5f); + + int f = 0; + float h = 0; + for (auto& t: g.out(s1)) + { + f += t.first; + h += t.second; + } + return f == 3 && (h > 2.49 && h < 2.51); +} + +bool f7() +{ + typedef spot::digraph graph_t; + graph_t g(3); + spot::named_graph gg(g); + + auto s1 = gg.new_state("s1", 2); + gg.new_state("s2", 3); + gg.new_state("s3", 4); + gg.new_transition("s1", {"s2", "s3"}, 1); + gg.new_transition("s1", {"s3"}, 2); + gg.new_transition("s2", {"s3"}, 3); + gg.new_transition("s3", {"s2"}, 4); + + int f = 0; + for (auto& t: g.out(s1)) + { + for (auto& tt: t.dst) + { + f += t.label * g.state_data(tt); + } + } + return f == 15; +} + + +struct int_pair +{ + int one; + int two; + + friend std::ostream& operator<<(std::ostream& os, int_pair p) + { + os << '(' << p.one << ',' << p.two << ')'; + return os; + } + +#if __GNUC__ <= 4 && __GNUC_MINOR__ <= 6 + int_pair(int one, int two) + : one(one), two(two) + { + } + + int_pair() + { + } +#endif +}; + +bool f8() +{ + typedef spot::digraph graph_t; + graph_t g(3); + spot::named_graph gg(g); + auto s1 = gg.new_state("s1", 2, 4); + gg.new_state("s2", 3, 6); + gg.new_state("s3", 4, 8); + gg.new_transition("s1", "s2", 1, 3); + gg.new_transition("s1", "s3", 2, 5); + gg.new_transition("s2", "s3", 3, 7); + gg.new_transition("s3", "s2", 4, 9); + + dot(std::cout, gg); + + int f = 0; + for (auto& t: g.out(s1)) + { + f += t.one * g.state_data(t.dst).one; + f += t.two * g.state_data(t.dst).two; + } + return f == 69; +} + + +int main() +{ + bool a1 = f1(); + bool a2 = f2(); + bool a3 = f3(); + bool a4 = f4(); + bool a5 = f5(); + bool a6 = f6(); + bool a7 = f7(); + bool a8 = f8(); + std::cout << a1 << ' ' + << a2 << ' ' + << a3 << ' ' + << a4 << ' ' + << a5 << ' ' + << a6 << ' ' + << a7 << ' ' + << a8 << '\n'; + return !(a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8); +} diff --git a/src/graphtest/ngraph.test b/src/graphtest/ngraph.test new file mode 100755 index 000000000..1ce2c6206 --- /dev/null +++ b/src/graphtest/ngraph.test @@ -0,0 +1,87 @@ +#!/bin/sh +# -*- coding: utf-8 -*- +# Copyright (C) 2014 Laboratoire de Recherche et Développement de +# l'Epita (LRDE). +# +# 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 . + +# While running some benchmark, Tomáš Babiak found that Spot took too +# much time (i.e. >1h) to translate those six formulae. It turns out +# that the WDBA minimization was performed after the degeneralization +# algorithm, while this is not necessary (WDBA will produce a BA, so +# we may as well skip degeneralization). Translating these formulae +# in the test-suite ensure that they don't take too much time (the +# buildfarm will timeout if it does). + +. ./defs + +set -e + +run 0 ../ngraph > stdout + +cat >expected < 1 + 0 -> 2 + 1 [label="s2"] + 1 -> 2 + 2 [label="s3"] + 2 -> 0 + 2 -> 1 + 2 -> 2 +} +digraph { + 0 [label="s1\n1"] + 0 -> 1 + 0 -> 2 + 1 [label="s2\n2"] + 1 -> 2 + 2 [label="s3\n3"] + 2 -> 1 +} +digraph { + 0 [label="s1"] + 0 -> 1 [label="1"] + 0 -> 2 [label="2"] + 1 [label="s2"] + 1 -> 2 [label="3"] + 2 [label="s3"] + 2 -> 1 [label="4"] +} +digraph { + 0 [label="s1\n2"] + 0 -> 1 [label="1"] + 0 -> 2 [label="2"] + 1 [label="s2\n3"] + 1 -> 2 [label="3"] + 2 [label="s3\n4"] + 2 -> 1 [label="4"] +} +digraph { + 0 [label="s1\n(2,4)"] + 0 -> 1 [label="(1,3)"] + 0 -> 2 [label="(2,5)"] + 1 [label="s2\n(3,6)"] + 1 -> 2 [label="(3,7)"] + 2 [label="s3\n(4,8)"] + 2 -> 1 [label="(4,9)"] +} +1 1 1 1 1 1 1 1 +EOF + +diff stdout expected +