From 0bf0a99d6d9dc83e4f2ce4807be490b09b6ec742 Mon Sep 17 00:00:00 2001 From: Laurent XU Date: Wed, 1 Jun 2016 14:34:19 +0200 Subject: [PATCH] parity: add spot::colorize_parity() These functions colorize automata with parity acceptance. They output parity automata. * spot/twaalgos/parity.cc, spot/twaalgos/parity.hh: Here * tests/core/parity.cc: Add tests for spot::colorize_parity() * tests/python/parity.ipynb: Add documentation about spot::colorize_parity() --- spot/twaalgos/parity.cc | 56 ++++ spot/twaalgos/parity.hh | 22 ++ tests/core/parity.cc | 42 +++ tests/python/parity.ipynb | 649 +++++++++++++++++++++++++++++++++++++- 4 files changed, 767 insertions(+), 2 deletions(-) diff --git a/spot/twaalgos/parity.cc b/spot/twaalgos/parity.cc index 43f48a9a3..eb835fac6 100644 --- a/spot/twaalgos/parity.cc +++ b/spot/twaalgos/parity.cc @@ -146,4 +146,60 @@ namespace spot change_style, output_max, current_max); return aut; } + + twa_graph_ptr + colorize_parity(const const_twa_graph_ptr& aut, bool keep_style) + { + return colorize_parity_here(make_twa_graph(aut, twa::prop_set::all()), + keep_style); + } + + twa_graph_ptr + colorize_parity_here(twa_graph_ptr aut, bool keep_style) + { + bool current_max; + bool current_odd; + if (!aut->acc().is_parity(current_max, current_odd, true)) + throw new std::invalid_argument("colorize_parity: input " + "must have a parity acceptance."); + + bool has_empty = false; + for (const auto& e: aut->edges()) + if (!e.acc) + { + has_empty = true; + break; + } + auto num_sets = aut->num_sets(); + int incr = 0; + if (has_empty) + { + // If the automaton has a transition that belong to any set, we need to + // introduce a new acceptance set. + // We may want to add a second acceptance set to keep the style of + // the parity acceptance + incr = 1 + (keep_style && current_max); + num_sets += incr; + bool new_style = current_odd == (keep_style || !current_max); + auto new_acc = acc_cond::acc_code::parity(current_max, + new_style, num_sets); + aut->set_acceptance(num_sets, new_acc); + } + if (current_max) + { + --incr; + for (auto& e: aut->edges()) + { + auto maxset = e.acc.max_set(); + e.acc = acc_cond::mark_t{maxset ? maxset + incr : incr}; + } + } + else + { + auto unused_mark = num_sets - incr; + for (auto& e: aut->edges()) + e.acc = e.acc ? e.acc.lowest() : acc_cond::mark_t{unused_mark}; + } + return aut; + } } diff --git a/spot/twaalgos/parity.hh b/spot/twaalgos/parity.hh index 385805d2d..df04af9fe 100644 --- a/spot/twaalgos/parity.hh +++ b/spot/twaalgos/parity.hh @@ -87,5 +87,27 @@ namespace spot SPOT_API twa_graph_ptr change_parity_here(twa_graph_ptr aut, parity_kind kind, parity_style style); /// @} + + /// \brief Colorize an automaton with parity acceptance + /// + /// An automaton is said colored iff all the transitions belong to exactly one + /// acceptance set. The algorithm achieves thiat by removing superfluous + /// acceptance marks. It may introduce a new set to mark the transitions with + /// no acceptance sets and a second set may be introduced to keep the style. + /// The input must be an automaton with a parity acceptance, otherwise an + /// invalid_argument exception is thrown. + /// + /// \param aut the input automaton + /// + /// \param keep_style whether the style of the parity acc is kept. + /// + /// \return the colorized automaton + /// @{ + SPOT_API twa_graph_ptr + colorize_parity(const const_twa_graph_ptr& aut, bool keep_style = false); + + SPOT_API twa_graph_ptr + colorize_parity_here(twa_graph_ptr aut, bool keep_style = false); + /// @} /// @} } diff --git a/tests/core/parity.cc b/tests/core/parity.cc index 49193e3a1..0c7e2904b 100644 --- a/tests/core/parity.cc +++ b/tests/core/parity.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -269,6 +270,32 @@ static bool is_almost_colored(spot::const_twa_graph_ptr aut) return true; } +static bool is_colored_printerr(spot::const_twa_graph_ptr aut) +{ + bool result = is_colored(aut); + if (!result) + { + std::cerr << "======Not colored======" << std::endl; + spot::print_hoa(std::cerr, aut); + std::cerr << std::endl; + } + return result; +} + +static spot::parity_kind to_parity_kind(bool is_max) +{ + if (is_max) + return spot::parity_kind_max; + return spot::parity_kind_min; +} + +static spot::parity_style to_parity_style(bool is_odd) +{ + if (is_odd) + return spot::parity_style_odd; + return spot::parity_style_even; +} + int main() { auto current_bdd = spot::make_bdd_dict(); @@ -323,6 +350,21 @@ int main() assert(is_almost_colored(output) && "change_parity: too many acc on a transition"); } + // Check colorize_parity + for (auto keep_style: { true, false }) + { + auto output = spot::colorize_parity(aut, keep_style); + assert(is_colored_printerr(output) + && "colorize_parity: not colored."); + assert(are_equiv(aut, output) + && "colorize_parity: not equivalent."); + auto target_kind = to_parity_kind(is_max); + auto target_style = keep_style ? to_parity_style(is_odd) + : spot::parity_style_any; + assert(is_right_parity(output, target_kind, target_style, + is_max, is_odd, acc_num_sets) + && "change_parity: wrong acceptance."); + } } } return 0; diff --git a/tests/python/parity.ipynb b/tests/python/parity.ipynb index a04270c08..1fe189586 100644 --- a/tests/python/parity.ipynb +++ b/tests/python/parity.ipynb @@ -123,8 +123,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "##To toggle **style**\n", - "###A new acceptance set is introduced and all the existing sets' indexes are increased by 1.\n", + "## To toggle **style**\n", + "### A new acceptance set is introduced and all the existing sets' indexes are increased by 1.\n", "#### Parity max odd 5 -> Parity max even\n", "If the acceptance is a parity **max**, all the transitions that do not belong to any acceptance set will belong to the new set." ] @@ -1303,6 +1303,651 @@ } ], "prompt_number": 10 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Colorize parity\n", + "An automaton with a parity acceptance is not necessarily a parity automaton. It must be colored to be qualified like this.\n", + "## Parity max\n", + "Transitions with multiple acceptance sets are purified by keeping only the set with the greatest index.\n", + "
\n", + "If there is a transition that do not belong to any acceptance set, a new acceptance set is introduced at the least significant place.\n", + "
\n", + "The least significant place of a parity max acceptance is where the indexes are the lowest, so all the existing acceptance sets' indexes will be shifted.\n", + "#### Colorize parity max odd 4" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "aut_max_odd4 = tuple(spot.automata(\"randaut -A 'parity max odd 4' -Q4 2|\"))[0]\n", + "display(aut_max_odd4.show(\".a\"))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "G\n", + "\n", + "Inf(\n", + "\u2778\n", + ") | (Fin(\n", + "\u2777\n", + ") & (Inf(\n", + "\u2776\n", + ") | Fin(\n", + "\u24ff\n", + ")))\n", + "[parity max odd 4]\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "2\n", + "\n", + "2\n", + "\n", + "\n", + "0->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\n", + "\n", + "3\n", + "\n", + "3\n", + "\n", + "\n", + "0->3\n", + "\n", + "\n", + "!p0 & !p1\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "2->1\n", + "\n", + "\n", + "!p0 & p1\n", + "\n", + "\n", + "3->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\n", + "\n", + "3->3\n", + "\n", + "\n", + "p0 & !p1\n", + "\u24ff\n", + "\n", + "\n", + "1->0\n", + "\n", + "\n", + "!p0 & p1\n", + "\u24ff\n", + "\u2777\n", + "\n", + "\n", + "1->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\n", + "\n", + "" + ], + "text": [ + "" + ] + } + ], + "prompt_number": 11 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The new acceptance sets are:\n", + "+ \u2205 -> 0\n", + "+ 0 -> 1\n", + "+ 1 -> 2\n", + "+ 2 -> 3\n", + "+ 3 -> 4\n", + "\n", + "#### The result of colorizing the given parity max odd 4 is" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "aut_max_odd4_colored = spot.colorize_parity(aut_max_odd4, False)\n", + "display(aut_max_odd4_colored.show(\".a\"))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "G\n", + "\n", + "Inf(\n", + "\u2779\n", + ") | (Fin(\n", + "\u2778\n", + ") & (Inf(\n", + "\u2777\n", + ") | (Fin(\n", + "\u2776\n", + ") & Inf(\n", + "\u24ff\n", + "))))\n", + "[parity max even 5]\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "2\n", + "\n", + "2\n", + "\n", + "\n", + "0->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u24ff\n", + "\n", + "\n", + "3\n", + "\n", + "3\n", + "\n", + "\n", + "0->3\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u24ff\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "2->1\n", + "\n", + "\n", + "!p0 & p1\n", + "\u24ff\n", + "\n", + "\n", + "3->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u24ff\n", + "\n", + "\n", + "3->3\n", + "\n", + "\n", + "p0 & !p1\n", + "\u2776\n", + "\n", + "\n", + "1->0\n", + "\n", + "\n", + "!p0 & p1\n", + "\u2778\n", + "\n", + "\n", + "1->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u24ff\n", + "\n", + "\n", + "" + ], + "text": [ + "" + ] + } + ], + "prompt_number": 12 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can notice that the **style** has been toggled.\n", + "
\n", + "To prevent colorize_parity from this we can add one extra acceptance set in the acceptance condition.\n", + "\n", + "The new acceptance sets are now:\n", + "+ \u2205 -> 1\n", + "+ 0 -> 2\n", + "+ 1 -> 3\n", + "+ 2 -> 4\n", + "+ 3 -> 5\n", + "#### The result of colorizing the given parity max odd 4 without changing the style is" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "aut_max_odd4_colored_bis = spot.colorize_parity(aut_max_odd4, True)\n", + "display(aut_max_odd4_colored_bis.show(\".a\"))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "G\n", + "\n", + "Inf(\n", + "\u277a\n", + ") | (Fin(\n", + "\u2779\n", + ") & (Inf(\n", + "\u2778\n", + ") | (Fin(\n", + "\u2777\n", + ") & (Inf(\n", + "\u2776\n", + ") | Fin(\n", + "\u24ff\n", + ")))))\n", + "[parity max odd 6]\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "2\n", + "\n", + "2\n", + "\n", + "\n", + "0->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u2776\n", + "\n", + "\n", + "3\n", + "\n", + "3\n", + "\n", + "\n", + "0->3\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u2776\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "2->1\n", + "\n", + "\n", + "!p0 & p1\n", + "\u2776\n", + "\n", + "\n", + "3->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u2776\n", + "\n", + "\n", + "3->3\n", + "\n", + "\n", + "p0 & !p1\n", + "\u2777\n", + "\n", + "\n", + "1->0\n", + "\n", + "\n", + "!p0 & p1\n", + "\u2779\n", + "\n", + "\n", + "1->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u2776\n", + "\n", + "\n", + "" + ], + "text": [ + "" + ] + } + ], + "prompt_number": 13 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Parity min\n", + "Transitions with multiple acceptance sets are purified by keeping only the set with the lowest index.\n", + "
\n", + "If there is a transition that do not belong to any acceptance set, a new acceptance set is introduced at the least significant place.\n", + "
\n", + "The least significant place of a parity min acceptance is where the indexes are the greatest.\n", + "#### Colorize parity min odd 4" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "aut_min_odd4 = tuple(spot.automata(\"randaut -A 'parity min odd 4' -Q4 2|\"))[0]\n", + "display(aut_min_odd4.show(\".a\"))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "G\n", + "\n", + "Fin(\n", + "\u24ff\n", + ") & (Inf(\n", + "\u2776\n", + ") | (Fin(\n", + "\u2777\n", + ") & Inf(\n", + "\u2778\n", + ")))\n", + "[parity min odd 4]\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "2\n", + "\n", + "2\n", + "\n", + "\n", + "0->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\n", + "\n", + "3\n", + "\n", + "3\n", + "\n", + "\n", + "0->3\n", + "\n", + "\n", + "!p0 & !p1\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "2->1\n", + "\n", + "\n", + "!p0 & p1\n", + "\n", + "\n", + "3->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\n", + "\n", + "3->3\n", + "\n", + "\n", + "p0 & !p1\n", + "\u24ff\n", + "\n", + "\n", + "1->0\n", + "\n", + "\n", + "!p0 & p1\n", + "\u24ff\n", + "\u2777\n", + "\n", + "\n", + "1->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\n", + "\n", + "" + ], + "text": [ + "" + ] + } + ], + "prompt_number": 14 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The new acceptance sets are:\n", + "+ \u2205 -> 4\n", + "+ 0 -> 0\n", + "+ 1 -> 1\n", + "+ 2 -> 2\n", + "+ 3 -> 3\n", + "\n", + "#### The result of colorizing the given parity max odd 4 is" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "aut_min_odd4_colored_bis = spot.colorize_parity(aut_min_odd4, True)\n", + "display(aut_min_odd4_colored_bis.show(\".a\"))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "G\n", + "\n", + "Fin(\n", + "\u24ff\n", + ") & (Inf(\n", + "\u2776\n", + ") | (Fin(\n", + "\u2777\n", + ") & (Inf(\n", + "\u2778\n", + ") | Fin(\n", + "\u2779\n", + "))))\n", + "[parity min odd 5]\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "2\n", + "\n", + "2\n", + "\n", + "\n", + "0->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u2779\n", + "\n", + "\n", + "3\n", + "\n", + "3\n", + "\n", + "\n", + "0->3\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u2779\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "2->1\n", + "\n", + "\n", + "!p0 & p1\n", + "\u2779\n", + "\n", + "\n", + "3->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u2779\n", + "\n", + "\n", + "3->3\n", + "\n", + "\n", + "p0 & !p1\n", + "\u24ff\n", + "\n", + "\n", + "1->0\n", + "\n", + "\n", + "!p0 & p1\n", + "\u24ff\n", + "\n", + "\n", + "1->2\n", + "\n", + "\n", + "!p0 & !p1\n", + "\u2779\n", + "\n", + "\n", + "" + ], + "text": [ + "" + ] + } + ], + "prompt_number": 15 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Remark: colorizing a parity min won't change the **style** of the acceptance." + ] } ], "metadata": {}