diff --git a/spot/twaalgos/dot.cc b/spot/twaalgos/dot.cc index 103ab89d1..9d8c16d91 100644 --- a/spot/twaalgos/dot.cc +++ b/spot/twaalgos/dot.cc @@ -1196,11 +1196,6 @@ namespace spot { if (!circuit) return; - auto is_input = [nb_in = circuit->num_inputs()](unsigned val) - { - return (val & ~1) <= (2 * nb_in); - }; - const auto& in_names = circuit->input_names(); const auto& out_names = circuit->output_names(); @@ -1212,133 +1207,99 @@ namespace spot auto num_gates = circuit->num_gates(); auto gates = circuit->gates(); - // If a circuit doesn't use an input, we need a special placement - bool uses_in = false; - auto add_edge = [](std::ostream &stream, const unsigned src, const unsigned dst) { auto src_gate = src & ~1; - stream << src_gate; - stream << " -> " << dst; + stream << " " << src_gate << " -> " << dst; if (src & 1) stream << " [arrowhead=dot]"; stream << '\n'; }; if (vertical) - os_ << "digraph \"\" {\nrankdir = BT;\n"; + os_ << "digraph \"\" {\n rankdir = BT\n"; else - os_ << "digraph \"\" {\nrankdir = LR;\n"; + os_ << "digraph \"\" {\n rankdir = LR\n"; - os_ << "# latches left\n"; + os_ << " {\n rank = same\n" + " node [shape=box,style=filled,fillcolor=\"#ffe6cc\"]\n"; for (unsigned i = 0; i < num_latches; ++i) - { - auto first = circuit->latch_var(i); - auto first_m_mod = first & ~1; - os_ << "node[shape=box, label=\"L" << i << "_out\"] " - << first_m_mod << ";\n"; - } - - //Predefine all nodes - - os_ << "# input nodes\n"; - for (unsigned i = 0; i < num_inputs; ++i) - os_ << "node [shape=triangle, label=\"" - << in_names[i] << "\"] " - << circuit->input_var(i) << ";\n"; - - os_ << "# latch nodes\n"; - for (unsigned i = 0; i < num_latches; ++i) - os_ << "node[shape=box, label=\"L" << i << "\"] L" << i << ";\n"; - - os_ << "# gate nodes\n"; - for (unsigned i = 0; i < num_gates; ++i) - if ((gates[i].first != 0) && (gates[i].second != 0)) { - uses_in |= is_input(gates[i].first) | is_input(gates[i].second); - auto gate_var = circuit->gate_var(i); - os_ << "node [shape=circle, label=\"" << gate_var - << "\"] " << gate_var << ";\n"; + auto first_m_mod = circuit->latch_var(i) & ~1; + os_ << " " << first_m_mod << " [label=\"L" << i << "_out\"]\n"; } - - os_ << "# and ins\n"; - for (unsigned i = 0; i < num_gates; ++i) - if ((gates[i].first != 0) && (gates[i].second != 0)) + os_ << " }\n"; + if (num_gates) { - auto gate_var = circuit->gate_var(i); - add_edge(os_, gates[i].first, gate_var); - add_edge(os_, gates[i].second, gate_var); + os_ << " node [shape=circle,style=solid]\n"; + for (unsigned i = 0; i < num_gates; ++i) + if ((gates[i].first != 0) && (gates[i].second != 0)) + os_ << " " << circuit->gate_var(i) << '\n'; } - - bool has_alone_gate = false; - - os_ << "# Latches\n"; - for (unsigned i = 0; i < num_latches; ++i) - { - auto second = latches[i]; - os_ << "node[shape=box, label=\"L" << i << "_in\"] L" << i << ";\n"; - if (second <= 1 && !has_alone_gate) + bool has_false = false; + if (num_latches) { - os_ << "node[shape=box, label=\"Const\"] 0" << std::endl; - has_alone_gate = true; + os_ << " {\n rank=same\n" + " node [shape=box,style=filled," + "fillcolor=\"#ffe6cc\",label=\"\\N_in\"]\n"; + for (unsigned i = 0; i < num_latches; ++i) + { + os_ << " L" << i << '\n'; + if (latches[i] <= 1) + has_false = true; + } + os_ << " }\n"; } - os_ << (second & ~1) << " -> L" << i; - if (i & 1) - os_ << "[arrowhead=dot]"; - os_ << '\n'; - } - - // Outs can be defined after everything else - os_ << "# Outs\n"; const char* out_pos = vertical ? ":s" : ":w"; + const char* rotate = vertical ? "" : ",orientation=-90"; + if (num_outputs) + { + os_ << " {\n rank = sink\n " + "node [shape=invtriangle,style=filled,fillcolor=\"#ffe5f1\"" + << rotate << "]\n"; + for (unsigned i = 0; i < num_outputs; ++i) + { + os_ << " o" << i << " [label=\"" << out_names[i] << "\"]\n"; + if (outputs[i] <= 1) + has_false = true; + } + os_ << " }\n"; + } + if (num_inputs | has_false) + { + os_ << " {\n rank=source\n" + " node [shape=triangle,style=filled,fillcolor=\"#e9f4fb\"" + << rotate << "]\n"; + for (unsigned i = 0; i < num_inputs; ++i) + os_ << " " << circuit->input_var(i) + << " [label=\"" << in_names[i] << "\"]\n"; + if (has_false) + os_ << + " 0 [shape=box,fillcolor=\"#ffe6cc\",label=\"False\"]\n"; + os_ << " }\n"; + } for (unsigned i = 0; i < num_outputs; ++i) - { - os_ << "node [shape=triangle, orientation=180, label=\"" - << out_names[i] << "\"] o" << i - << out_names[i] << ";\n"; - auto z = outputs[i]; - uses_in |= is_input(z); - if (z <= 1 && !has_alone_gate) { - os_ << "node[shape=box, label=\"Const\"] 0" << std::endl; - has_alone_gate = true; + auto z = outputs[i]; + os_ << " " << (z & ~1) << " -> o" << i << out_pos; + if (z & 1) + os_ << " [arrowhead=dot]"; + os_ << '\n'; } - os_ << (z & ~1) << "->" << 'o' << i << out_names[i] << out_pos; - if (outputs[i] & 1) - os_ << " [arrowhead=dot]"; - os_ << '\n'; - } - - if (has_alone_gate || num_inputs > 0) - { - os_ << (uses_in ? "{rank = source; " : "{rank = same; "); - for (unsigned i = 0; i < num_inputs; ++i) - os_ << circuit->input_var(i) << "; "; - if (has_alone_gate) - os_ << "0; "; - os_ << "}\n"; - } - if (num_outputs > 0) - { - os_ << "{rank = sink; "; - for (unsigned i = 0; i < num_outputs; ++i) - os_ << 'o' << i << out_names[i] << "; "; - os_ << "}\n"; - } - if (num_latches > 0) - { - os_ << "{rank = same; "; - for (unsigned i = 0; i < num_latches; ++i) - os_ << 'L' << i << "; "; - os_ << "}\n{rank = same; "; - for (unsigned i = 0; i < num_latches; ++i) + for (unsigned i = 0; i < num_latches; ++i) { - auto first = circuit->latch_var(i); - auto first_m_mod = first & ~1; - os_ << first_m_mod << "; "; + os_ << " " << (latches[i] & ~1) << " -> L" << i; + if (latches[i] & 1) + os_ << " [arrowhead=dot]"; + os_ << '\n'; } - os_ << "}\n"; - } + for (unsigned i = 0; i < num_gates; ++i) + if ((gates[i].first != 0) && (gates[i].second != 0)) + { + auto gate_var = circuit->gate_var(i); + add_edge(os_, gates[i].first, gate_var); + add_edge(os_, gates[i].second, gate_var); + } os_ << "}\n"; } }; diff --git a/tests/python/synthesis.ipynb b/tests/python/synthesis.ipynb index 3ee2d3eb5..5e29b62e4 100644 --- a/tests/python/synthesis.ipynb +++ b/tests/python/synthesis.ipynb @@ -696,7 +696,7 @@ "\n" ], "text/plain": [ - " *' at 0x7f4e7018b5a0> >" + " *' at 0x7f6c003de2a0> >" ] }, "metadata": {}, @@ -2713,7 +2713,7 @@ "\n" ], "text/plain": [ - " *' at 0x7f4e700b8150> >" + " *' at 0x7f6c005968d0> >" ] }, "execution_count": 5, @@ -3039,7 +3039,7 @@ "\n" ], "text/plain": [ - " *' at 0x7f4e700b87b0> >" + " *' at 0x7f6c003de630> >" ] }, "execution_count": 6, @@ -3060,7 +3060,7 @@ "\n", "A strategy can be converted to a circuit in the [AIGER format](http://fmv.jku.at/aiger/FORMAT.aiger) using `strategy_to_aig()`. This takes a second argument specifying what type of encoding to use (exactly like `ltlsynt`'s `--aiger=...` option). \n", "\n", - "In this case, the circuit is quite simple: `o0` should be the negation of previous value of `i1`. This is done by storing the value of `i1` in a latch. And the value if `i0` can be ignored." + "In this case, the circuit is quite simple: `o0` should be the negation of previous value of `i1`. This is done by storing the value of `i1` in a latch. And the value of `i0` can be ignored." ] }, { @@ -3085,74 +3085,144 @@ "\n", "\n", "6\n", - "\n", + "\n", "L0_out\n", "\n", - "\n", - "\n", - "o0o0\n", - "\n", + "\n", + "\n", + "o0\n", + "\n", "o0\n", "\n", - "\n", - "\n", - "6->o0o0:s\n", + "\n", + "\n", + "6->o0:s\n", "\n", "\n", "\n", - "\n", + "\n", "\n", + "L0\n", + "\n", + "L0_in\n", + "\n", + "\n", + "\n", "2\n", - "\n", + "\n", "i1\n", "\n", - "\n", - "\n", - "L0\n", - "\n", - "L0\n", - "\n", "\n", - "\n", + "\n", "2->L0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "4\n", - "\n", + "\n", "i0\n", "\n", "\n", "\n" ], "text/plain": [ - " >" + " >" ] }, "metadata": {}, "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "aag 3 2 1 1 0\n", - "2\n", - "4\n", - "6 3\n", - "7\n", - "i0 i1\n", - "i1 i0\n", - "o0 o0\n" - ] } ], "source": [ "aig = spot.strategy_to_aig(strat, \"isop\")\n", - "display(aig)\n", - "print(aig.to_str())" + "display(aig)" + ] + }, + { + "cell_type": "markdown", + "id": "a7100505", + "metadata": {}, + "source": [ + "While we are at it, let us mention that you can render those circuits horizontally as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "8272357d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "6\n", + "\n", + "L0_out\n", + "\n", + "\n", + "\n", + "o0\n", + "\n", + "o0\n", + "\n", + "\n", + "\n", + "6->o0:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "L0\n", + "\n", + "L0_in\n", + "\n", + "\n", + "\n", + "2\n", + "\n", + "i1\n", + "\n", + "\n", + "\n", + "2->L0\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "4\n", + "\n", + "i0\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "aig.show('h')" ] }, { @@ -3176,7 +3246,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "efc7c557", "metadata": {}, "outputs": [ @@ -3346,7 +3416,7 @@ "\n" ], "text/plain": [ - " *' at 0x7f4e700b8cc0> >" + " *' at 0x7f6c003dec90> >" ] }, "metadata": {}, @@ -3368,62 +3438,62 @@ "\n", "\n", "4\n", - "\n", + "\n", "L0_out\n", "\n", "\n", - "\n", + "\n", "6\n", "\n", "6\n", "\n", "\n", - "\n", + "\n", "4->6\n", "\n", "\n", "\n", - "\n", - "\n", - "2\n", - "\n", - "i0\n", - "\n", - "\n", - "\n", - "2->6\n", - "\n", - "\n", - "\n", "\n", "\n", "L0\n", - "\n", - "L0\n", + "\n", + "L0_in\n", "\n", "\n", - "\n", + "\n", "6->L0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "o0o0\n", - "\n", + "\n", + "\n", + "o0\n", + "\n", "o0\n", "\n", - "\n", - "\n", - "6->o0o0:s\n", + "\n", + "\n", + "6->o0:s\n", "\n", "\n", "\n", + "\n", + "\n", + "2\n", + "\n", + "i0\n", + "\n", + "\n", + "\n", + "2->6\n", + "\n", + "\n", + "\n", "\n", "\n" ], "text/plain": [ - " >" + " >" ] }, "metadata": {}, @@ -3450,7 +3520,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "f9f8d0e3", "metadata": {}, "outputs": [ @@ -3463,93 +3533,93 @@ "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", "6\n", - "\n", + "\n", "L0_out\n", "\n", "\n", - "\n", + "\n", "8\n", - "\n", - "8\n", + "\n", + "8\n", "\n", "\n", - "\n", + "\n", "6->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "2\n", - "\n", - "i0\n", - "\n", - "\n", - "\n", - "2->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4\n", - "\n", - "i1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "L0\n", - "\n", - "L0\n", + "\n", + "L0_in\n", "\n", "\n", "\n", "8->L0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", + "\n", + "o0\n", + "\n", + "o0\n", + "\n", + "\n", + "\n", + "8->o0:s\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "o1\n", + "\n", + "o1\n", + "\n", + "\n", "\n", - "o0o0\n", - "\n", - "o0\n", + "2\n", + "\n", + "i0\n", "\n", - "\n", + "\n", "\n", - "8->o0o0:s\n", - "\n", - "\n", + "2->8\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "o1o1\n", - "\n", - "o1\n", + "4\n", + "\n", + "i1\n", "\n", "\n", "\n", "0\n", - "\n", - "Const\n", + "\n", + "False\n", "\n", - "\n", - "\n", - "0->o1o1:s\n", - "\n", - "\n", + "\n", + "\n", + "0->o1:s\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - " >" + " >" ] }, "metadata": {}, @@ -3576,7 +3646,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "57d7875d", "metadata": {}, "outputs": [], @@ -3597,7 +3667,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "4796e7d7", "metadata": {}, "outputs": [ @@ -3614,101 +3684,101 @@ " viewBox=\"0.00 0.00 202.39 289.50\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", "\n", "\n", - "\n", - "\n", - "2\n", - "\n", - "i0\n", - "\n", "\n", - "\n", + "\n", "6\n", "\n", "6\n", "\n", - "\n", - "\n", - "2->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "8\n", - "\n", - "8\n", - "\n", - "\n", - "\n", - "2->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4\n", - "\n", - "i1\n", - "\n", - "\n", - "\n", - "4->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->8\n", - "\n", - "\n", - "\n", "\n", - "\n", + "\n", "10\n", "\n", "10\n", "\n", "\n", - "\n", + "\n", "6->10\n", "\n", "\n", "\n", - "\n", - "\n", - "o1o1\n", - "\n", + "\n", + "\n", + "o1\n", + "\n", "o1\n", "\n", - "\n", - "\n", - "6->o1o1:s\n", + "\n", + "\n", + "6->o1:s\n", "\n", "\n", "\n", + "\n", + "\n", + "8\n", + "\n", + "8\n", + "\n", "\n", - "\n", + "\n", "8->10\n", "\n", "\n", "\n", - "\n", - "\n", - "o0o0\n", - "\n", + "\n", + "\n", + "o0\n", + "\n", "o0\n", "\n", - "\n", - "\n", - "10->o0o0:s\n", + "\n", + "\n", + "10->o0:s\n", "\n", "\n", "\n", + "\n", + "\n", + "2\n", + "\n", + "i0\n", + "\n", + "\n", + "\n", + "2->6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "2->8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "4\n", + "\n", + "i1\n", + "\n", + "\n", + "\n", + "4->6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "4->8\n", + "\n", + "\n", + "\n", "\n", "\n" ], "text/plain": [ - " >" + " >" ] }, "metadata": {}, @@ -3722,7 +3792,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "id": "000f3948", "metadata": {}, "outputs": [ @@ -3751,7 +3821,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "id": "60e8b21a", "metadata": {}, "outputs": [ @@ -3777,7 +3847,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "id": "f5d49a9e", "metadata": {}, "outputs": [ @@ -3820,10 +3890,10 @@ "\n" ], "text/plain": [ - " *' at 0x7f4e700b8cf0> >" + " *' at 0x7f6c003c2300> >" ] }, - "execution_count": 14, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" }