zlktree: remimplement zielonka_tree without BDDs

* spot/twaalgos/zlktree.cc (zielonka_tree): Find the models using a
recursive procedure on the acceptance condition, without conversion to
BDD.
* tests/python/_zlktree.ipynb: Adjust to a different order of nodes.
This commit is contained in:
Alexandre Duret-Lutz 2021-08-31 15:17:56 +02:00
parent 200ee0d204
commit 86c22d98bc
2 changed files with 88 additions and 119 deletions

View file

@ -22,41 +22,13 @@
#include <deque> #include <deque>
#include <spot/twaalgos/zlktree.hh> #include <spot/twaalgos/zlktree.hh>
#include <spot/twaalgos/genem.hh> #include <spot/twaalgos/genem.hh>
#include "spot/priv/bddalloc.hh"
namespace spot namespace spot
{ {
zielonka_tree::zielonka_tree(const acc_cond& cond) namespace
{ {
const acc_cond::acc_code& code = cond.get_acceptance(); // Or goal is the find the list of maximal models for a formula
auto used = code.used_sets(); // named cond and defined later for each node.
unsigned c = used.count();
unsigned max = used.max_set();
bdd_allocator ba;
int base = ba.allocate_variables(c);
assert(base == 0);
std::vector<bdd> col_to_bdd(max ? max : 1, bddfalse);
std::vector<unsigned> bdd_to_col(c);
bdd all_neg = bddtrue;
for (unsigned i = 0; i < max; ++i)
if (used.has(i))
{
bdd_to_col[base] = i;
all_neg &= bdd_nithvar(base);
col_to_bdd[i] = bdd_ithvar(base++);
}
bdd poscond = code.to_bdd(col_to_bdd.data());
bdd negcond = !poscond;
nodes_.emplace_back();
nodes_[0].parent = 0;
nodes_[0].colors = used;
nodes_[0].level = 0;
// Or goal is the find the list of maximal models for a formula named
// cond and defined later for each node.
// //
// For instance if cond is satisfied by {1}, {3}, {1,2}, {1,2,3}, // For instance if cond is satisfied by {1}, {3}, {1,2}, {1,2,3},
// {0,3}, and {0,1,3}, then the maximal models are {1,2,3} and // {0,3}, and {0,1,3}, then the maximal models are {1,2,3} and
@ -76,8 +48,61 @@ namespace spot
unsigned size; unsigned size;
acc_cond::mark_t model; acc_cond::mark_t model;
}; };
std::vector<size_model> models;
void max_models(acc_cond cond,
acc_cond::mark_t colors,
std::vector<size_model>& out)
{
if (!colors)
return;
if (cond.accepting(colors))
{
unsigned sz = colors.count();
auto iter = out.begin();
while (iter != out.end())
{
if (iter->size < sz)
// We have checked all larger models.
break;
if (colors.subset(iter->model))
// curmodel is covered by iter->model.
return;
++iter;
}
// insert the model
iter = out.insert(iter, {sz, colors});
++iter;
// erase all models it contains
out.erase(std::remove_if(iter, out.end(),
[&](auto& mod) {
return mod.model.subset(colors);
}), out.end());
}
else if (acc_cond::mark_t fu = cond.fin_unit())
{
max_models(cond.remove(fu, true), colors - fu, out);
}
else if (int fo = cond.fin_one(); fo >= 0)
{
acc_cond::mark_t fo_m = {(unsigned) fo};
max_models(cond.remove(fo_m, true), colors - fo_m, out);
max_models(cond.remove(fo_m, false), colors, out);
}
}
}
zielonka_tree::zielonka_tree(const acc_cond& cond)
{
const acc_cond::acc_code& code = cond.get_acceptance();
auto used = code.used_sets();
acc_cond negcond(cond.num_sets(), cond.get_acceptance().complement());
nodes_.emplace_back();
nodes_[0].parent = 0;
nodes_[0].colors = used;
nodes_[0].level = 0;
std::vector<size_model> models;
// This loop is a BFS over the increasing set of nodes. // This loop is a BFS over the increasing set of nodes.
for (unsigned node = 0; node < nodes_.size(); ++node) for (unsigned node = 0; node < nodes_.size(); ++node)
{ {
@ -86,67 +111,12 @@ namespace spot
if (node == 0) if (node == 0)
is_even_ = is_accepting; is_even_ = is_accepting;
// colors that do not appear in this node should acc_cond c = (is_accepting ? negcond : cond).restrict_to(colors);
// be set to false in the acceptance.
bdd to_remove = bddtrue;
for (unsigned c: (colors ^ used).sets())
to_remove &= !col_to_bdd[c];
bdd cond = bdd_restrict(is_accepting ? negcond : poscond, to_remove);
// These is where we will store the ordered list of models, as
// explained in the declation of that vector.
models.clear(); models.clear();
max_models(c, colors, models);
while (cond != bddfalse) unsigned num_children = models.size();
{ if (num_children == 0) // This is a leaf of the tree.
// Find one model of cond. If it has some don't cares
// variable, we interpret them as true, so in effect, we can
// start from a model where all colors are sets, and only
// unset those that are negative in the output of
// bdd_satone.
bdd one = bdd_satone(cond);
cond -= one;
acc_cond::mark_t curmodel = colors;
while (one != bddtrue)
{
unsigned v = bdd_to_col[bdd_var(one)];
if (bdd_high(one) == bddfalse)
{
curmodel.clear(v);
one = bdd_low(one);
}
else
{
one = bdd_high(one);
}
}
//
unsigned sz = curmodel.count();
if (sz == 0)
// ignore the empty set
continue;
auto iter = models.begin();
while (iter != models.end())
{
if (iter->size < sz)
// We have checked all larger models.
break;
if (curmodel.subset(iter->model))
// curmodel is covered by iter->model.
goto donotinsert;
++iter;
}
// insert the model
iter = models.insert(iter, {sz, curmodel});
++iter;
// erase all models it contains
models.erase(std::remove_if(iter, models.end(),
[&](auto& mod) {
return mod.model.subset(curmodel);
}), models.end());
donotinsert:;
}
if (models.empty()) // This is a leaf of the tree.
{ {
if (num_branches_++ == 0) if (num_branches_++ == 0)
one_branch_ = node; one_branch_ = node;
@ -154,7 +124,6 @@ namespace spot
} }
unsigned first = nodes_.size(); unsigned first = nodes_.size();
nodes_[node].first_child = first; nodes_[node].first_child = first;
unsigned num_children = models.size();
nodes_.reserve(first + num_children); nodes_.reserve(first + num_children);
for (auto& m: models) for (auto& m: models)
nodes_.push_back({node, static_cast<unsigned>(nodes_.size() + 1), nodes_.push_back({node, static_cast<unsigned>(nodes_.size() + 1),

View file

@ -126,7 +126,7 @@
"<g id=\"node9\" class=\"node\">\n", "<g id=\"node9\" class=\"node\">\n",
"<title>8</title>\n", "<title>8</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"124.36\" cy=\"-26.87\" rx=\"35.21\" ry=\"26.74\"/>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"124.36\" cy=\"-26.87\" rx=\"35.21\" ry=\"26.74\"/>\n",
"<text text-anchor=\"middle\" x=\"124.36\" y=\"-30.67\" font-family=\"Times,serif\" font-size=\"14.00\">{3}</text>\n", "<text text-anchor=\"middle\" x=\"124.36\" y=\"-30.67\" font-family=\"Times,serif\" font-size=\"14.00\">{1}</text>\n",
"<text text-anchor=\"middle\" x=\"124.36\" y=\"-15.67\" font-family=\"Times,serif\" font-size=\"14.00\">&lt;8&gt;</text>\n", "<text text-anchor=\"middle\" x=\"124.36\" y=\"-15.67\" font-family=\"Times,serif\" font-size=\"14.00\">&lt;8&gt;</text>\n",
"</g>\n", "</g>\n",
"<!-- 4&#45;&gt;8 -->\n", "<!-- 4&#45;&gt;8 -->\n",
@ -139,7 +139,7 @@
"<g id=\"node10\" class=\"node\">\n", "<g id=\"node10\" class=\"node\">\n",
"<title>9</title>\n", "<title>9</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"213.36\" cy=\"-26.87\" rx=\"35.21\" ry=\"26.74\"/>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"213.36\" cy=\"-26.87\" rx=\"35.21\" ry=\"26.74\"/>\n",
"<text text-anchor=\"middle\" x=\"213.36\" y=\"-30.67\" font-family=\"Times,serif\" font-size=\"14.00\">{1}</text>\n", "<text text-anchor=\"middle\" x=\"213.36\" y=\"-30.67\" font-family=\"Times,serif\" font-size=\"14.00\">{3}</text>\n",
"<text text-anchor=\"middle\" x=\"213.36\" y=\"-15.67\" font-family=\"Times,serif\" font-size=\"14.00\">&lt;9&gt;</text>\n", "<text text-anchor=\"middle\" x=\"213.36\" y=\"-15.67\" font-family=\"Times,serif\" font-size=\"14.00\">&lt;9&gt;</text>\n",
"</g>\n", "</g>\n",
"<!-- 4&#45;&gt;9 -->\n", "<!-- 4&#45;&gt;9 -->\n",
@ -152,7 +152,7 @@
"<g id=\"node11\" class=\"node\">\n", "<g id=\"node11\" class=\"node\">\n",
"<title>10</title>\n", "<title>10</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"308.36\" cy=\"-26.87\" rx=\"41.94\" ry=\"26.74\"/>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"308.36\" cy=\"-26.87\" rx=\"41.94\" ry=\"26.74\"/>\n",
"<text text-anchor=\"middle\" x=\"308.36\" y=\"-30.67\" font-family=\"Times,serif\" font-size=\"14.00\">{3}</text>\n", "<text text-anchor=\"middle\" x=\"308.36\" y=\"-30.67\" font-family=\"Times,serif\" font-size=\"14.00\">{1}</text>\n",
"<text text-anchor=\"middle\" x=\"308.36\" y=\"-15.67\" font-family=\"Times,serif\" font-size=\"14.00\">&lt;10&gt;</text>\n", "<text text-anchor=\"middle\" x=\"308.36\" y=\"-15.67\" font-family=\"Times,serif\" font-size=\"14.00\">&lt;10&gt;</text>\n",
"</g>\n", "</g>\n",
"<!-- 5&#45;&gt;10 -->\n", "<!-- 5&#45;&gt;10 -->\n",
@ -165,7 +165,7 @@
"<g id=\"node12\" class=\"node\">\n", "<g id=\"node12\" class=\"node\">\n",
"<title>11</title>\n", "<title>11</title>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"409.36\" cy=\"-26.87\" rx=\"41.94\" ry=\"26.74\"/>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"409.36\" cy=\"-26.87\" rx=\"41.94\" ry=\"26.74\"/>\n",
"<text text-anchor=\"middle\" x=\"409.36\" y=\"-30.67\" font-family=\"Times,serif\" font-size=\"14.00\">{1}</text>\n", "<text text-anchor=\"middle\" x=\"409.36\" y=\"-30.67\" font-family=\"Times,serif\" font-size=\"14.00\">{3}</text>\n",
"<text text-anchor=\"middle\" x=\"409.36\" y=\"-15.67\" font-family=\"Times,serif\" font-size=\"14.00\">&lt;11&gt;</text>\n", "<text text-anchor=\"middle\" x=\"409.36\" y=\"-15.67\" font-family=\"Times,serif\" font-size=\"14.00\">&lt;11&gt;</text>\n",
"</g>\n", "</g>\n",
"<!-- 5&#45;&gt;11 -->\n", "<!-- 5&#45;&gt;11 -->\n",
@ -191,7 +191,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7f14dc46b540> >" "<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7fd0ba77a4b0> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -286,7 +286,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"(9, 2)" "(8, 3)"
] ]
}, },
"execution_count": 6, "execution_count": 6,
@ -307,7 +307,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"(9, 3)" "(8, 2)"
] ]
}, },
"execution_count": 7, "execution_count": 7,
@ -328,7 +328,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"(8, 3)" "(9, 2)"
] ]
}, },
"execution_count": 8, "execution_count": 8,
@ -755,7 +755,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7f14dd55e780> >" "<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7fd0ba77a450> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -1111,7 +1111,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7f14dc427f90> >" "<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7fd0ba755810> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -1247,7 +1247,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7f14dc427630> >" "<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7fd0ba77a630> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -1358,7 +1358,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7f14dc42d090> >" "<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7fd0ba755510> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -1421,7 +1421,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7f14dc42d720> >" "<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7fd0ba755780> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -1484,7 +1484,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7f14dc427630> >" "<spot.zielonka_tree; proxy of <Swig Object of type 'spot::zielonka_tree *' at 0x7fd0ba755e40> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -2587,7 +2587,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.acd; proxy of <Swig Object of type 'spot::acd *' at 0x7f14dc427600> >" "<spot.acd; proxy of <Swig Object of type 'spot::acd *' at 0x7fd0ba74db70> >"
] ]
}, },
"execution_count": 24, "execution_count": 24,
@ -3974,7 +3974,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc2662a0> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0ba759870> >"
] ]
}, },
"execution_count": 38, "execution_count": 38,
@ -4058,7 +4058,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.acd; proxy of <Swig Object of type 'spot::acd *' at 0x7f14dc29b240> >" "<spot.acd; proxy of <Swig Object of type 'spot::acd *' at 0x7fd0ba764510> >"
] ]
}, },
"execution_count": 40, "execution_count": 40,
@ -4181,7 +4181,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc266720> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0ba764240> >"
] ]
}, },
"execution_count": 41, "execution_count": 41,
@ -4329,7 +4329,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc29b750> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0ba764750> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -4483,7 +4483,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc29b3f0> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0ba7646c0> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -4629,7 +4629,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc29b2a0> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0ba759bd0> >"
] ]
}, },
"metadata": {}, "metadata": {},
@ -4881,7 +4881,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.acd; proxy of <Swig Object of type 'spot::acd *' at 0x7f14dc27a120> >" "<spot.acd; proxy of <Swig Object of type 'spot::acd *' at 0x7fd0ba747030> >"
] ]
}, },
"execution_count": 48, "execution_count": 48,
@ -5015,7 +5015,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc27abd0> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0ba747c90> >"
] ]
}, },
"execution_count": 50, "execution_count": 50,
@ -5406,7 +5406,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc295360> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0b9cfb570> >"
] ]
}, },
"execution_count": 51, "execution_count": 51,
@ -5790,7 +5790,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc295420> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0b9cfb840> >"
] ]
}, },
"execution_count": 52, "execution_count": 52,
@ -5874,7 +5874,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc295960> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0b9cfbc90> >"
] ]
}, },
"execution_count": 53, "execution_count": 53,
@ -5996,7 +5996,7 @@
"</svg>\n" "</svg>\n"
], ],
"text/plain": [ "text/plain": [
"<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f14dc295ba0> >" "<spot.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fd0b9cfb5a0> >"
] ]
}, },
"execution_count": 56, "execution_count": 56,