diff --git a/NEWS b/NEWS index 1a93911d9..5e7364963 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,7 @@ New in spot 2.7.0.dev (not yet release) - Work around GCC bug #89303, that causes memory leaks and std::weak_bad_ptr exceptions when Spot is compiled with the version of g++ 8.2 currently - distributed with Debian (starting with 8.2.0-15). + distributed by Debian unstable (starting with g++ 8.2.0-15). Python: @@ -17,6 +17,20 @@ New in spot 2.7.0.dev (not yet release) - unregister_all_my_variables(for_me) - unregister_variable(var, for_me) + - Better support for explicit Kripke structures + - the kripke_graph type now has bindings + - spot.automaton() and spot.automata() now support a want_kripke=True + to return a kripke_graph + See the bottom of https://spot.lrde.epita.fr/ipynb/ltsmin-dve.html + for some examples. + + Library: + + - Printing Kripke structures via print_hoa() will save state names. + + - kripke_graph_ptr objects now honnor any "state-names" property + when formating states. + Bugs fixed: - The print_dot_psl() function would incorrectly number all but the @@ -38,7 +52,7 @@ New in spot 2.7.0.dev (not yet release) suspendable automaton could incorrectly build transition-based automata when multipliying two state-based automata. This caused ltl2tgba to emit error messages such as: "automaton has - transition-based acceptance despite prop_state_acc()==true" + transition-based acceptance despite prop_state_acc()==true". New in spot 2.7 (2018-12-11) diff --git a/THANKS b/THANKS index 68d3443f0..49d5e17bf 100644 --- a/THANKS +++ b/THANKS @@ -17,6 +17,7 @@ Felix Klaedtke Florian Perlié-Long František Blahoudek Gerard J. Holzmann +Hashim Ali Heikki Tauriainen Henrich Lauko Jan Strejček diff --git a/python/spot/__init__.py b/python/spot/__init__.py index 266ee5a48..dc7b9efbc 100644 --- a/python/spot/__init__.py +++ b/python/spot/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2014-2018 Laboratoire de +# Copyright (C) 2014-2019 Laboratoire de # Recherche et Développement de l'Epita (LRDE). # # This file is part of Spot, a model checking library. @@ -367,7 +367,8 @@ class atomic_prop_set: def automata(*sources, timeout=None, ignore_abort=True, - trust_hoa=True, no_sid=False, debug=False): + trust_hoa=True, no_sid=False, debug=False, + want_kripke=False): """Read automata from a list of sources. Parameters @@ -386,6 +387,10 @@ def automata(*sources, timeout=None, ignore_abort=True, trust_hoa : bool, optional If True (the default), supported HOA properies that cannot be easily verified are trusted. + want_kripke : bool, optional + If True, the input is expected to discribe Kripke + structures, in the HOA format, and the returned type + will be of type kripke_graph_ptr. no_sid : bool, optional When an automaton is obtained from a subprocess, this subprocess is started from a shell with its own session @@ -445,6 +450,8 @@ def automata(*sources, timeout=None, ignore_abort=True, o.ignore_abort = ignore_abort o.trust_hoa = trust_hoa o.raise_errors = True + o.want_kripke = want_kripke + for filename in sources: try: p = None @@ -496,8 +503,9 @@ def automata(*sources, timeout=None, ignore_abort=True, mgr = proc if proc else _supress() with mgr: while a: - # This returns None when we reach the end of the file. - a = p.parse(_bdd_dict).aut + # the automaton is None when we reach the end of the file. + res = p.parse(_bdd_dict) + a = res.ks if want_kripke else res.aut if a: yield a finally: diff --git a/python/spot/impl.i b/python/spot/impl.i index 66e8c7127..38bdeb916 100644 --- a/python/spot/impl.i +++ b/python/spot/impl.i @@ -47,7 +47,6 @@ %shared_ptr(spot::fair_kripke) %shared_ptr(spot::kripke) %shared_ptr(spot::kripke_graph) -%shared_ptr(spot::kripke) %shared_ptr(spot::ta) %shared_ptr(spot::ta_explicit) %shared_ptr(spot::ta_product) @@ -172,8 +171,9 @@ #include -#include #include +#include +#include #include #include @@ -678,10 +678,11 @@ def state_is_accepting(self, src) -> "bool": %include -%include - %include %include +%include + +%include %include %include diff --git a/spot/kripke/kripkegraph.hh b/spot/kripke/kripkegraph.hh index bfd83426b..a8bde37a0 100644 --- a/spot/kripke/kripkegraph.hh +++ b/spot/kripke/kripkegraph.hh @@ -1,5 +1,5 @@ // -*- coding: utf-8 -*- -// Copyright (C) 2011-2018 Laboratoire de Recherche et Développement de +// Copyright (C) 2011-2019 Laboratoire de Recherche et Développement de // l'Epita (LRDE) // // This file is part of Spot, a model checking library. @@ -239,9 +239,11 @@ namespace spot std::string format_state(unsigned n) const { - std::stringstream ss; - ss << n; - return ss.str(); + auto named = get_named_prop>("state-names"); + if (named && n < named->size()) + return (*named)[n]; + + return std::to_string(n); } virtual std::string format_state(const state* st) const override diff --git a/spot/twaalgos/hoa.cc b/spot/twaalgos/hoa.cc index 0a97c0f75..32a0eb019 100644 --- a/spot/twaalgos/hoa.cc +++ b/spot/twaalgos/hoa.cc @@ -1,5 +1,5 @@ // -*- coding: utf-8 -*- -// Copyright (C) 2014-2018 Laboratoire de Recherche et +// Copyright (C) 2014-2019 Laboratoire de Recherche et // Developpement de l'Epita (LRDE). // // This file is part of Spot, a model checking library. @@ -304,6 +304,9 @@ namespace spot case 'k': state_labels = true; break; + case 'K': + state_labels = false; + break; case 'l': newline = false; break; @@ -732,14 +735,12 @@ namespace spot const const_twa_ptr& aut, const char* opt) { - - auto a = std::dynamic_pointer_cast(aut); - if (!a) - a = make_twa_graph(aut, twa::prop_set::all()); - + bool preserve_names = false; // for Kripke structures, automatically append "k" to the options. + // (Unless "K" was given.) char* tmpopt = nullptr; - if (std::dynamic_pointer_cast(aut)) + if (std::dynamic_pointer_cast(aut) && + (!opt || (strchr(opt, 'K') == nullptr))) { unsigned n = opt ? strlen(opt) : 0; tmpopt = new char[n + 2]; @@ -747,7 +748,13 @@ namespace spot strcpy(tmpopt, opt); tmpopt[n] = 'k'; tmpopt[n + 1] = 0; + preserve_names = true; } + + auto a = std::dynamic_pointer_cast(aut); + if (!a) + a = make_twa_graph(aut, twa::prop_set::all(), preserve_names); + print_hoa(os, a, tmpopt ? tmpopt : opt); delete[] tmpopt; return os; diff --git a/tests/python/ltsmin-dve.ipynb b/tests/python/ltsmin-dve.ipynb index f2b34d426..36ac77f6d 100644 --- a/tests/python/ltsmin-dve.ipynb +++ b/tests/python/ltsmin-dve.ipynb @@ -436,7 +436,7 @@ "\n" ], "text/plain": [ - " *' at 0x7f0f044132a0> >" + " *' at 0x7fb8f84f9870> >" ] }, "execution_count": 9, @@ -1265,7 +1265,7 @@ "\n" ], "text/plain": [ - " *' at 0x7f0f04381d50> >" + " *' at 0x7fb8f84691e0> >" ] }, "execution_count": 12, @@ -1453,7 +1453,7 @@ "\n" ], "text/plain": [ - " *' at 0x7f0f04381b10> >" + " *' at 0x7fb8f8469360> >" ] }, "execution_count": 13, @@ -1548,7 +1548,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -1582,7 +1582,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -1663,10 +1663,10 @@ "\n" ], "text/plain": [ - " *' at 0x7f0f04392d80> >" + " *' at 0x7fb8f85624e0> >" ] }, - "execution_count": 20, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -1676,11 +1676,338 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "# Saving Kripke structures to some file\n", + "\n", + "For experiments, it is sometime useful to save a Kripke structure in the HOA format. The HOA printer will automatically use `state-labels` for Kripke structures." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HOA: v1\n", + "States: 22\n", + "Start: 0\n", + "AP: 3 \"a<1\" \"b>2\" \"dead\"\n", + "acc-name: all\n", + "Acceptance: 0 t\n", + "properties: state-labels explicit-labels state-acc\n", + "--BODY--\n", + "State: [0&!1&!2] 0 \"a=0, b=0, Q=0\"\n", + "1 2\n", + "State: [!0&!1&!2] 1 \"a=1, b=0, Q=0\"\n", + "3 4\n", + "State: [0&!1&!2] 2 \"a=0, b=1, Q=0\"\n", + "4 5\n", + "State: [!0&!1&!2] 3 \"a=2, b=0, Q=0\"\n", + "6 7\n", + "State: [!0&!1&!2] 4 \"a=1, b=1, Q=0\"\n", + "7 8\n", + "State: [0&!1&!2] 5 \"a=0, b=2, Q=0\"\n", + "8 9 10\n", + "State: [!0&!1&2] 6 \"a=3, b=0, Q=0\"\n", + "6\n", + "State: [!0&!1&!2] 7 \"a=2, b=1, Q=0\"\n", + "11 12\n", + "State: [!0&!1&!2] 8 \"a=1, b=2, Q=0\"\n", + "12 13 14\n", + "State: [0&1&!2] 9 \"a=0, b=3, Q=0\"\n", + "15\n", + "State: [0&!1&!2] 10 \"a=0, b=2, Q=1\"\n", + "14 15\n", + "State: [!0&!1&2] 11 \"a=3, b=1, Q=0\"\n", + "11\n", + "State: [!0&!1&!2] 12 \"a=2, b=2, Q=0\"\n", + "16 17 18\n", + "State: [!0&1&!2] 13 \"a=1, b=3, Q=0\"\n", + "19\n", + "State: [!0&!1&!2] 14 \"a=1, b=2, Q=1\"\n", + "18 19\n", + "State: [0&1&2] 15 \"a=0, b=3, Q=1\"\n", + "15\n", + "State: [!0&!1&!2] 16 \"a=3, b=2, Q=0\"\n", + "20\n", + "State: [!0&1&!2] 17 \"a=2, b=3, Q=0\"\n", + "21\n", + "State: [!0&!1&!2] 18 \"a=2, b=2, Q=1\"\n", + "20 21 12\n", + "State: [!0&1&2] 19 \"a=1, b=3, Q=1\"\n", + "19\n", + "State: [!0&!1&!2] 20 \"a=3, b=2, Q=1\"\n", + "16\n", + "State: [!0&1&!2] 21 \"a=2, b=3, Q=1\"\n", + "17\n", + "--END--\n" + ] + } + ], + "source": [ + "string = k.to_str('hoa')\n", + "print(string)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can load this as a Kripke structure by passing the `want_kripke` option to `spot.automaton()`. The type `kripke_graph` stores the Kripke structure explicitely (like a `twa_graph` stores an automaton explicitely), so you may want to avoid it for very large modelsand use it only for development." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "t\n", + "[all]\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "a=0, b=0, Q=0\n", + ""a<1" & !"b>2" & !dead\n", + "\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "1\n", + "\n", + "a=1, b=0, Q=0\n", + "!"a<1" & !"b>2" & !dead\n", + "\n", + "\n", + "\n", + "0->1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "2\n", + "\n", + "a=0, b=1, Q=0\n", + ""a<1" & !"b>2" & !dead\n", + "\n", + "\n", + "\n", + "0->2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "3\n", + "\n", + "a=2, b=0, Q=0\n", + "!"a<1" & !"b>2" & !dead\n", + "\n", + "\n", + "\n", + "1->3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "4\n", + "\n", + "a=1, b=1, Q=0\n", + "!"a<1" & !"b>2" & !dead\n", + "\n", + "\n", + "\n", + "1->4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "2->4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "5\n", + "\n", + "a=0, b=2, Q=0\n", + ""a<1" & !"b>2" & !dead\n", + "\n", + "\n", + "\n", + "2->5\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "6\n", + "\n", + "a=3, b=0, Q=0\n", + "!"a<1" & !"b>2" & dead\n", + "\n", + "\n", + "\n", + "3->6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "7\n", + "\n", + "a=2, b=1, Q=0\n", + "...\n", + "\n", + "\n", + "\n", + "3->7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "4->7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "8\n", + "\n", + "a=1, b=2, Q=0\n", + "...\n", + "\n", + "\n", + "\n", + "4->8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "5->8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "u5\n", + "\n", + "...\n", + "\n", + "\n", + "\n", + "5->u5\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "9\n", + "\n", + "a=0, b=3, Q=0\n", + "...\n", + "\n", + "\n", + "\n", + "5->9\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "6->6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "u7\n", + "\n", + "...\n", + "\n", + "\n", + "\n", + "7->u7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "u8\n", + "\n", + "...\n", + "\n", + "\n", + "\n", + "8->u8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "u9\n", + "\n", + "...\n", + "\n", + "\n", + "\n", + "9->u9\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + " *' at 0x7fb8f84690f0> >" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "k2 = spot.automaton(string, want_kripke=True)\n", + "print(type(k2))\n", + "k2" + ] } ], "metadata": { @@ -1699,7 +2026,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.7" + "version": "3.7.2+" } }, "nbformat": 4,