avoid mark_t::count() when possible

count() may be implemented using a loop, so using it touch
check count() == 1 or count() > 1 is not advisable.

* spot/twa/acc.hh (mark_t::is_singleton, mark_t::has_many): Introduce
these two methods to replace count()==1 and count()>1
* spot/twa/acc.cc, spot/twaalgos/cleanacc.cc,
spot/twaalgos/determinize.cc, spot/twaalgos/dtwasat.cc,
spot/twaalgos/iscolored.cc, spot/twaalgos/remfin.cc,
spot/twaalgos/toparity.cc: Adjust usage.
This commit is contained in:
Alexandre Duret-Lutz 2020-04-18 23:23:44 +02:00
parent c0e1b3e52a
commit cc12d514be
8 changed files with 219 additions and 197 deletions

View file

@ -152,7 +152,7 @@ namespace spot
{ {
if (!top) if (!top)
// Avoid extra parentheses if there is only one set // Avoid extra parentheses if there is only one set
top = code[pos - 1].mark.count() == 1; top = code[pos - 1].mark.is_singleton();
unsigned level = 0; unsigned level = 0;
const char* and_ = ""; const char* and_ = "";
const char* and_next_ = []() { const char* and_next_ = []() {
@ -207,7 +207,7 @@ namespace spot
{ {
if (!top) if (!top)
// Avoid extra parentheses if there is only one set // Avoid extra parentheses if there is only one set
top = code[pos - 1].mark.count() == 1; top = code[pos - 1].mark.is_singleton();
unsigned level = 0; unsigned level = 0;
const char* or_ = ""; const char* or_ = "";
if (!top) if (!top)
@ -491,7 +491,7 @@ namespace spot
} }
if (o1 != acc_cond::acc_op::Fin if (o1 != acc_cond::acc_op::Fin
|| o2 != acc_cond::acc_op::Inf || o2 != acc_cond::acc_op::Inf
|| m1.count() != 1 || !m1.is_singleton()
|| m2 != (m1 << 1)) || m2 != (m1 << 1))
return false; return false;
seen_fin |= m1; seen_fin |= m1;
@ -519,7 +519,7 @@ namespace spot
assert(code.size() == 2); assert(code.size() == 2);
auto m = code[0].mark; auto m = code[0].mark;
if (mainop == singleop && m.count() != 1) if (mainop == singleop && !m.is_singleton())
return false; return false;
acc_cond::mark_t fin = {}; acc_cond::mark_t fin = {};
@ -557,7 +557,7 @@ namespace spot
acc_cond::mark_t fin = {}; acc_cond::mark_t fin = {};
acc_cond::mark_t inf = {}; acc_cond::mark_t inf = {};
if (op == singleop && m.count() != 1) if (op == singleop && !m.is_singleton())
{ {
pairs.clear(); pairs.clear();
return false; return false;
@ -595,8 +595,8 @@ namespace spot
} }
if (o1 != acc_cond::acc_op::Fin if (o1 != acc_cond::acc_op::Fin
|| o2 != acc_cond::acc_op::Inf || o2 != acc_cond::acc_op::Inf
|| m1.count() != 1 || !m1.is_singleton()
|| m2.count() != 1) || !m2.is_singleton())
{ {
pairs.clear(); pairs.clear();
return false; return false;
@ -723,7 +723,7 @@ namespace spot
if (o1 != acc_cond::acc_op::Fin if (o1 != acc_cond::acc_op::Fin
|| o2 != acc_cond::acc_op::Inf || o2 != acc_cond::acc_op::Inf
|| m1.count() != 1) || !m1.is_singleton())
return false; return false;
unsigned i = m2.count(); unsigned i = m2.count();
@ -826,7 +826,7 @@ namespace spot
if (o1 != acc_cond::acc_op::Inf if (o1 != acc_cond::acc_op::Inf
|| o2 != acc_cond::acc_op::Fin || o2 != acc_cond::acc_op::Fin
|| m1.count() != 1) || !m1.is_singleton())
return false; return false;
unsigned i = m2.count(); unsigned i = m2.count();
@ -1069,7 +1069,6 @@ namespace spot
std::vector<acc_cond::acc_code> elements, std::vector<acc_cond::acc_code> elements,
acc_cond::acc_op op) acc_cond::acc_op op)
{ {
acc_cond::mark_t empty_m = {};
if (elements.size() > 2) if (elements.size() > 2)
{ {
new_cond = original; new_cond = original;
@ -1077,19 +1076,19 @@ namespace spot
} }
if (elements.size() == 2) if (elements.size() == 2)
{ {
unsigned pos = elements[1].back().sub.op == op && unsigned pos = (elements[1].back().sub.op == op
elements[1][0].mark.count() == 1; && elements[1][0].mark.is_singleton());
if (!(elements[0].back().sub.op == op || pos)) if (!(elements[0].back().sub.op == op || pos))
{ {
new_cond = original; new_cond = original;
return false; return false;
} }
if ((elements[1 - pos].used_sets() & elements[pos][0].mark) != empty_m) if ((elements[1 - pos].used_sets() & elements[pos][0].mark))
{ {
new_cond = original; new_cond = original;
return false; return false;
} }
if (elements[pos][0].mark.count() != 1) if (!elements[pos][0].mark.is_singleton())
{ {
return false; return false;
} }
@ -1365,7 +1364,7 @@ namespace spot
for (; i < disj.size() - 1; ++i) for (; i < disj.size() - 1; ++i)
{ {
if (disj[i].back().sub.op != acc_cond::acc_op::Inf if (disj[i].back().sub.op != acc_cond::acc_op::Inf
|| disj[i][0].mark.count() != 1) || !disj[i][0].mark.is_singleton())
return false; return false;
for (auto color : disj[i][0].mark.sets()) for (auto color : disj[i][0].mark.sets())
{ {
@ -1377,7 +1376,7 @@ namespace spot
} }
if (disj[i].back().sub.op == acc_cond::acc_op::Inf) if (disj[i].back().sub.op == acc_cond::acc_op::Inf)
{ {
if (!even || disj[i][0].mark.count() != 1) if (!even || !disj[i][0].mark.is_singleton())
return false; return false;
for (auto color : disj[i][0].mark.sets()) for (auto color : disj[i][0].mark.sets())
{ {
@ -1392,7 +1391,8 @@ namespace spot
} }
} }
else else
{ std::sort(conj.begin(), conj.end(), {
std::sort(conj.begin(), conj.end(),
[](acc_code c1, acc_code c2) [](acc_code c1, acc_code c2)
{ {
return (c1 != c2) return (c1 != c2)
@ -1402,7 +1402,7 @@ namespace spot
for (; i < conj.size() - 1; i++) for (; i < conj.size() - 1; i++)
{ {
if (conj[i].back().sub.op != acc_cond::acc_op::Fin if (conj[i].back().sub.op != acc_cond::acc_op::Fin
|| conj[i][0].mark.count() != 1) || !conj[i][0].mark.is_singleton())
return false; return false;
for (auto color : conj[i][0].mark.sets()) for (auto color : conj[i][0].mark.sets())
{ {
@ -1415,7 +1415,7 @@ namespace spot
{ {
if (even) if (even)
return 0; return 0;
if (conj[i][0].mark.count() != 1) if (!conj[i][0].mark.is_singleton())
return false; return false;
for (auto color : conj[i][0].mark.sets()) for (auto color : conj[i][0].mark.sets())
{ {
@ -1688,7 +1688,7 @@ namespace spot
break; break;
case acc_cond::acc_op::Fin: case acc_cond::acc_op::Fin:
case acc_cond::acc_op::FinNeg: case acc_cond::acc_op::FinNeg:
if (pos[-1].mark.count() > 1 && pos > and_scope) if (pos[-1].mark.has_many() && pos > and_scope)
return false; return false;
SPOT_FALLTHROUGH; SPOT_FALLTHROUGH;
case acc_cond::acc_op::Inf: case acc_cond::acc_op::Inf:
@ -1721,7 +1721,7 @@ namespace spot
break; break;
case acc_cond::acc_op::Inf: case acc_cond::acc_op::Inf:
case acc_cond::acc_op::InfNeg: case acc_cond::acc_op::InfNeg:
if (pos[-1].mark.count() > 1 && pos > or_scope) if (pos[-1].mark.has_many() && pos > or_scope)
return false; return false;
SPOT_FALLTHROUGH; SPOT_FALLTHROUGH;
case acc_cond::acc_op::Fin: case acc_cond::acc_op::Fin:
@ -2569,12 +2569,14 @@ namespace spot
acc_cond::mark_t& res) acc_cond::mark_t& res)
{ {
res = {}; res = {};
acc_cond::mark_t possibles = ~code.used_once_sets();
bool found_one = false; bool found_one = false;
conj = false; conj = false;
fin = false; fin = false;
if (code.empty() || code.is_f()) if (code.empty() || code.is_f())
return false; return false;
acc_cond::mark_t candidates = ~code.used_once_sets();
if (!candidates)
return false;
const acc_cond::acc_word* pos = &code.back(); const acc_cond::acc_word* pos = &code.back();
conj = (pos->sub.op == acc_cond::acc_op::And); conj = (pos->sub.op == acc_cond::acc_op::And);
do do
@ -2598,9 +2600,8 @@ namespace spot
case acc_cond::acc_op::FinNeg: case acc_cond::acc_op::FinNeg:
if (!fin) if (!fin)
{ {
auto m = pos[-1].mark & possibles; auto m = pos[-1].mark & candidates;
if ((!conj && pos[-1].mark.count() == 1) if (m && (conj || pos[-1].mark.is_singleton()))
|| (conj && m.count() > 0))
{ {
found_one = true; found_one = true;
res |= m; res |= m;
@ -2611,9 +2612,8 @@ namespace spot
case acc_cond::acc_op::Fin: case acc_cond::acc_op::Fin:
if (!found_one || fin) if (!found_one || fin)
{ {
auto m = pos[-1].mark & possibles; auto m = pos[-1].mark & candidates;
if ((conj && pos[-1].mark.count() == 1) if (m && (!conj || pos[-1].mark.is_singleton()))
|| (!conj && m.count() > 0))
{ {
found_one = true; found_one = true;
fin = true; fin = true;
@ -2625,7 +2625,7 @@ namespace spot
} }
} }
while (pos >= &code.front()); while (pos >= &code.front());
return res != acc_cond::mark_t {}; return !!res;
} }
} }
@ -2733,7 +2733,7 @@ namespace spot
break; break;
case acc_cond::acc_op::Fin: case acc_cond::acc_op::Fin:
auto m = pos[-1].mark; auto m = pos[-1].mark;
if (m.count() == 1) if (m.is_singleton())
res |= m; res |= m;
pos -= 2; pos -= 2;
break; break;

View file

@ -389,6 +389,28 @@ namespace spot
return id & -id; return id & -id;
} }
/// \brief Whether the mark contains only one bit set.
bool is_singleton() const
{
#if __GNUC__
/* With GCC and Clang, count() is implemented using popcount. */
return count() == 1;
#else
return id && !(id & (id - 1));
#endif
}
/// \brief Whether the mark contains at least two bits set.
bool has_many() const
{
#if __GNUC__
/* With GCC and Clang, count() is implemented using popcount. */
return count() > 1;
#else
return !!(id & (id - 1));
#endif
}
/// \brief Remove n bits that where set. /// \brief Remove n bits that where set.
/// ///
/// If there are less than n bits set, the output is empty. /// If there are less than n bits set, the output is empty.

View file

@ -177,7 +177,7 @@ namespace spot
auto tmp = remove_compl_rec(pos, complement); auto tmp = remove_compl_rec(pos, complement);
if (!tmp.empty() && (tmp.back().sub.op == opfin if (!tmp.empty() && (tmp.back().sub.op == opfin
&& tmp.front().mark.count() == 1)) && tmp.front().mark.is_singleton()))
seen_fin |= tmp.front().mark; seen_fin |= tmp.front().mark;
if (opand == acc_cond::acc_op::And) if (opand == acc_cond::acc_op::And)
@ -390,7 +390,7 @@ namespace spot
case acc_cond::acc_op::FinNeg: case acc_cond::acc_op::FinNeg:
{ {
auto m = pos[-1].mark; auto m = pos[-1].mark;
if (op == wanted && m == m.lowest()) if (op == wanted && m.is_singleton())
{ {
res |= m; res |= m;
} }
@ -427,7 +427,7 @@ namespace spot
if (op == wanted) if (op == wanted)
{ {
auto m = pos[-1].mark; auto m = pos[-1].mark;
if (!seen && m == m.lowest()) if (!seen && m.is_singleton())
{ {
seen = true; seen = true;
res |= m; res |= m;
@ -513,7 +513,7 @@ namespace spot
case acc_cond::acc_op::Fin: case acc_cond::acc_op::Fin:
{ {
auto m = pos[-1].mark; auto m = pos[-1].mark;
if (op == wanted && m == m.lowest()) if (op == wanted && m.is_singleton())
singletons.emplace_back(m, pos); singletons.emplace_back(m, pos);
pos -= 2; pos -= 2;
} }
@ -550,8 +550,8 @@ namespace spot
if (!can_receive) if (!can_receive)
return; return;
for (auto p: singletons) for (auto p: singletons)
if (p.first != can_receive && if (p.first != can_receive
p.first.lowest() == p.first) && p.first.is_singleton())
{ {
// Mark fused singletons as false, // Mark fused singletons as false,
// so that a future call to // so that a future call to
@ -596,7 +596,7 @@ namespace spot
for (auto pair: to_fuse) for (auto pair: to_fuse)
if (pair.first & once) // can we remove pair.first? if (pair.first & once) // can we remove pair.first?
{ {
assert(pair.first.count() == 1); assert(pair.first.is_singleton());
for (auto& e: aut->edges()) for (auto& e: aut->edges())
if (e.acc & pair.first) if (e.acc & pair.first)
e.acc = (e.acc - pair.first) | pair.second; e.acc = (e.acc - pair.first) | pair.second;

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2019 Laboratoire de Recherche et // Copyright (C) 2015-2020 Laboratoire de Recherche et
// Développement de l'Epita. // Développement de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -195,7 +195,7 @@ namespace spot
int newb = brace; int newb = brace;
if (acc) if (acc)
{ {
assert(acc.has(0) && acc.count() == 1 && "Only TBA are accepted"); assert(acc.has(0) && acc.is_singleton() && "Only TBA are accepted");
// Accepting edges generate new braces: step A1 // Accepting edges generate new braces: step A1
newb = braces_.size(); newb = braces_.size();
braces_.emplace_back(brace); braces_.emplace_back(brace);

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013-2019 Laboratoire de Recherche // Copyright (C) 2013-2020 Laboratoire de Recherche
// et Développement de l'Epita. // et Développement de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -153,7 +153,7 @@ namespace spot
break; break;
case acc_cond::acc_op::Fin: case acc_cond::acc_op::Fin:
fin |= pos[-1].mark; fin |= pos[-1].mark;
assert(pos[-1].mark.count() == 1); assert(pos[-1].mark.is_singleton());
pos -= 2; pos -= 2;
break; break;
case acc_cond::acc_op::Inf: case acc_cond::acc_op::Inf:

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2017-2018 Laboratoire de Recherche et Développement // Copyright (C) 2017-2018, 2020 Laboratoire de Recherche et
// de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -26,7 +26,7 @@ namespace spot
is_colored(const const_twa_graph_ptr& aut) is_colored(const const_twa_graph_ptr& aut)
{ {
for (auto t: aut->edges()) for (auto t: aut->edges())
if (t.acc.count() != 1) if (!t.acc.is_singleton())
return false; return false;
return true; return true;
} }

View file

@ -356,7 +356,7 @@ namespace spot
break; break;
case acc_cond::acc_op::Fin: case acc_cond::acc_op::Fin:
fin |= pos[-1].mark; fin |= pos[-1].mark;
assert(pos[-1].mark.count() == 1); assert(pos[-1].mark.is_singleton());
pos -= 2; pos -= 2;
break; break;
case acc_cond::acc_op::Inf: case acc_cond::acc_op::Inf:

View file

@ -660,7 +660,7 @@ get_inputs_states(const twa_graph_ptr& aut)
for (auto e : aut->edges()) for (auto e : aut->edges())
{ {
auto elements = e.acc & used; auto elements = e.acc & used;
if (elements.count() > 1) if (elements.has_many())
inputs[e.dst].insert(elements); inputs[e.dst].insert(elements);
} }
return inputs; return inputs;