Commit 393637f1 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

gtec: replace nsheap by a simple unordered_map

nsheap was an horror full of virtual functions required to
customize gtec to implement inclusion-based emptiness-check
in GreatSPN support.  Since this support has been removed, we
can remove the nsheap cruft as well.  Note that nsheap was
also used in emptinessta for no good reason (the code from
emptinessta was simply copied from gtec without cleanup).

* src/tgbaalgos/gtec/nsheap.cc, src/tgbaalgos/gtec/nsheap.hh:
Delete.
* src/tgbaalgos/gtec/Makefile.am: Adjust.
* src/taalgos/emptinessta.cc, src/taalgos/emptinessta.hh,
src/taalgos/tgba2ta.cc, src/tgbaalgos/gtec/ce.cc,
src/tgbaalgos/gtec/gtec.cc, src/tgbaalgos/gtec/gtec.hh,
src/tgbaalgos/gtec/status.cc, src/tgbaalgos/gtec/status.hh:
Use a simple unordered_map.
parent 46e4408a
......@@ -58,8 +58,7 @@ namespace spot
// * h: a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
numbered_state_heap* h =
numbered_state_heap_hash_map_factory::instance()->build();
hash_type h;
// * num: the number of visited nodes. Used to set the order of each
// visited node,
......@@ -107,13 +106,13 @@ namespace spot
state_ta_product* init = new state_ta_product(
(ta_init_it_->current_state()), kripke_init_state->clone());
numbered_state_heap::state_index_p h_init = h->find(init);
if (!h.insert(std::make_pair(init, num + 1)).second)
{
init->destroy();
continue;
}
if (h_init.first)
continue;
h->insert(init, ++num);
scc.push(num);
scc.push(++num);
arc.push(bddfalse);
ta_succ_iterator_product* iter = a_->succ_iter(init);
......@@ -143,29 +142,25 @@ namespace spot
// Backtrack TODO.
todo.pop();
dec_depth();
trace
<< "PASS 1 : backtrack" << std::endl;
trace << "PASS 1 : backtrack\n";
if (a_->is_livelock_accepting_state(curr)
&& !a_->is_accepting_state(curr))
{
livelock_acceptance_states_not_found = false;
trace
<< "PASS 1 : livelock accepting state found" << std::endl;
trace << "PASS 1 : livelock accepting state found\n";
}
// fill rem with any component removed,
numbered_state_heap::state_index_p spi =
h->index(curr->clone());
assert(spi.first);
auto i = h.find(curr);
assert(i != h.end());
scc.rem().push_front(curr);
inc_depth();
// set the h value of the Backtracked state to negative value.
// colour[curr] = BLUE;
*spi.second = -std::abs(*spi.second);
i->second = -std::abs(i->second);
// Backtrack livelock_roots.
if (activate_heuristic && !livelock_roots.empty()
......@@ -176,21 +171,11 @@ namespace spot
// remove that SSCC from the ROOT stacks. We must
// discard from H all reachable states from this SSCC.
assert(!scc.empty());
if (scc.top().index == std::abs(*spi.second))
if (scc.top().index == std::abs(i->second))
{
// removing states
std::list<state*>::iterator i;
for (i = scc.rem().begin(); i != scc.rem().end(); ++i)
{
numbered_state_heap::state_index_p spi = h->index(
(*i)->clone());
assert(spi.first->compare(*i) == 0);
assert(*spi.second != -1);
*spi.second = -1;
//colour[*i] = BLACK;
}
for (auto j: scc.rem())
h[j] = -1; //colour[*i] = BLACK;
dec_depth(scc.rem().size());
scc.pop();
assert(!arc.empty());
......@@ -205,8 +190,7 @@ namespace spot
// We have a successor to look at.
inc_transitions();
trace
<< "PASS 1: transition" << std::endl;
trace << "PASS 1: transition\n";
// Fetch the values destination state we are interested in...
state* dest = succ->current_state();
......@@ -232,15 +216,12 @@ namespace spot
// We do not need SUCC from now on.
// Are we going to a new state?
numbered_state_heap::state_index_p spi = h->find(dest);
// Is this a new state?
if (!spi.first)
auto p = h.insert(std::make_pair(dest, num + 1));
if (p.second)
{
// Number it, stack it, and register its successors
// for later processing.
h->insert(dest, ++num);
scc.push(num);
scc.push(++num);
arc.push(acc_cond);
ta_succ_iterator_product* iter = a_->succ_iter(dest);
......@@ -258,7 +239,7 @@ namespace spot
}
// If we have reached a dead component, ignore it.
if (*spi.second == -1)
if (p.first->second == -1)
continue;
// Now this is the most interesting case. We have reached a
......@@ -272,12 +253,11 @@ namespace spot
// ROOT is ascending: we just have to merge all SSCCs from the
// top of ROOT that have an index greater to the one of
// the SSCC of S2 (called the "threshold").
int threshold = std::abs(*spi.second);
int threshold = std::abs(p.first->second);
std::list<state*> rem;
bool acc = false;
trace
<< "***PASS 1: CYCLE***" << std::endl;
trace << "***PASS 1: CYCLE***\n";
while (threshold < scc.top().index)
{
......@@ -310,15 +290,15 @@ namespace spot
if (is_accepting_sscc)
{
trace
<< "PASS 1: SUCCESS : a_->is_livelock_accepting_state(curr): "
<< a_->is_livelock_accepting_state(curr) << std::endl;
<< "PASS 1: SUCCESS: a_->is_livelock_accepting_state(curr): "
<< a_->is_livelock_accepting_state(curr) << '\n';
trace
<< "PASS 1: scc.top().condition : "
<< bdd_format_accset(a_->get_dict(), scc.top().condition)
<< std::endl;
<< '\n';
trace
<< "PASS 1: a_->all_acceptance_conditions() : "
<< (a_->all_acceptance_conditions()) << std::endl;
<< (a_->all_acceptance_conditions()) << '\n';
trace
<< ("PASS 1 CYCLE and (scc.top().condition == "
"a_->all_acceptance_conditions()) : ")
......@@ -326,12 +306,12 @@ namespace spot
== a_->all_acceptance_conditions()) << std::endl;
trace
<< "PASS 1: bddtrue : " << (a_->all_acceptance_conditions()
== bddtrue) << std::endl;
<< "PASS 1: bddtrue: " << (a_->all_acceptance_conditions()
== bddtrue) << '\n';
trace
<< "PASS 1: bddfalse : " << (a_->all_acceptance_conditions()
== bddfalse) << std::endl;
<< "PASS 1: bddfalse: " << (a_->all_acceptance_conditions()
== bddfalse) << '\n';
clear(h, todo, ta_init_it_);
return true;
......@@ -341,9 +321,8 @@ namespace spot
if (activate_heuristic && a_->is_livelock_accepting_state(curr)
&& is_stuttering_transition)
{
trace
<< "PASS 1: heuristic livelock detection " << std::endl;
const state* dest = spi.first;
trace << "PASS 1: heuristic livelock detection \n";
const state* dest = p.first->first;
std::set<const state*, state_ptr_less_than> liveset_dest =
liveset[dest];
......@@ -352,28 +331,23 @@ namespace spot
int h_livelock_root = 0;
if (!livelock_roots.empty())
h_livelock_root = *(h->find((livelock_roots.top()))).second;
h_livelock_root = h[livelock_roots.top()];
if (heuristic_livelock_detection(dest, h, h_livelock_root,
liveset_curr))
liveset_curr))
{
clear(h, todo, ta_init_it_);
return true;
}
std::set<const state*, state_ptr_less_than>::const_iterator it;
for (it = liveset_dest.begin(); it != liveset_dest.end(); ++it)
{
const state* succ = (*it);
if (heuristic_livelock_detection(succ, h, h_livelock_root,
liveset_curr))
{
clear(h, todo, ta_init_it_);
return true;
}
}
for (const state* succ: liveset_dest)
if (heuristic_livelock_detection(succ, h, h_livelock_root,
liveset_curr))
{
clear(h, todo, ta_init_it_);
return true;
}
}
}
......@@ -389,26 +363,23 @@ namespace spot
bool
ta_check::heuristic_livelock_detection(const state * u,
numbered_state_heap* h, int h_livelock_root, std::set<const state*,
hash_type& h, int h_livelock_root, std::set<const state*,
state_ptr_less_than> liveset_curr)
{
numbered_state_heap::state_index_p hu = h->find(u);
int hu = h[u];
if (*hu.second > 0) // colour[u] == GREY
if (hu > 0) // colour[u] == GREY
{
if (*hu.second >= h_livelock_root)
if (hu >= h_livelock_root)
{
trace
<< "PASS 1: heuristic livelock detection SUCCESS" << std::endl;
trace << "PASS 1: heuristic livelock detection SUCCESS\n";
return true;
}
liveset_curr.insert(u);
}
return false;
}
bool
......@@ -421,8 +392,7 @@ namespace spot
// * h: a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
numbered_state_heap* h =
numbered_state_heap_hash_map_factory::instance()->build();
hash_type h;
// * num: the number of visited nodes. Used to set the order of each
// visited node,
......@@ -448,7 +418,6 @@ namespace spot
{
state* init_state = (*it);
ta_init_it_.push(init_state);
}
while (!ta_init_it_.empty())
......@@ -457,19 +426,19 @@ namespace spot
{
state* init = ta_init_it_.front();
ta_init_it_.pop();
numbered_state_heap::state_index_p h_init = h->find(init);
if (h_init.first)
continue;
if (!h.insert(std::make_pair(init, num + 1)).second)
{
init->destroy();
continue;
}
h->insert(init, ++num);
sscc.push(num);
sscc.top().is_accepting = t->is_livelock_accepting_state(init);
ta_succ_iterator_product* iter = t->succ_iter(init);
iter->first();
todo.emplace(init, iter);
inc_depth();
}
while (!todo.empty())
......@@ -488,13 +457,11 @@ namespace spot
// Backtrack TODO.
todo.pop();
dec_depth();
trace
<< "PASS 2 : backtrack" << std::endl;
trace << "PASS 2 : backtrack\n";
// fill rem with any component removed,
numbered_state_heap::state_index_p spi =
h->index(curr->clone());
assert(spi.first);
auto i = h.find(curr);
assert(i != h.end());
sscc.rem().push_front(curr);
inc_depth();
......@@ -503,19 +470,11 @@ namespace spot
// remove that SSCC from the ROOT stacks. We must
// discard from H all reachable states from this SSCC.
assert(!sscc.empty());
if (sscc.top().index == *spi.second)
if (sscc.top().index == i->second)
{
// removing states
std::list<state*>::iterator i;
for (i = sscc.rem().begin(); i != sscc.rem().end(); ++i)
{
numbered_state_heap::state_index_p spi = h->index(
(*i)->clone());
assert(spi.first->compare(*i) == 0);
assert(*spi.second != -1);
*spi.second = -1;
}
for (auto j: sscc.rem())
h[j] = -1;
dec_depth(sscc.rem().size());
sscc.pop();
}
......@@ -528,8 +487,7 @@ namespace spot
// We have a successor to look at.
inc_transitions();
trace
<< "PASS 2 : transition" << std::endl;
trace << "PASS 2 : transition\n";
// Fetch the values destination state we are interested in...
state* dest = succ->current_state();
......@@ -539,10 +497,10 @@ namespace spot
succ->next();
// We do not need SUCC from now on.
numbered_state_heap::state_index_p spi = h->find(dest);
auto i = h.find(dest);
// Is this a new state?
if (!spi.first)
if (i == h.end())
{
// Are we going to a new state through a stuttering transition?
......@@ -555,7 +513,7 @@ namespace spot
// Number it, stack it, and register its successors
// for later processing.
h->insert(dest, ++num);
h[dest] = ++num;
sscc.push(num);
sscc.top().is_accepting = t->is_livelock_accepting_state(dest);
......@@ -565,24 +523,26 @@ namespace spot
inc_depth();
continue;
}
else
{
dest->destroy();
}
// If we have reached a dead component, ignore it.
if (*spi.second == -1)
if (i->second == -1)
continue;
//self loop state
if (!curr->compare(spi.first))
if (!curr->compare(i->first))
{
state * self_loop_state = (curr);
state* self_loop_state = curr;
if (t->is_livelock_accepting_state(self_loop_state))
{
clear(h, todo, ta_init_it_);
trace
<< "PASS 2: SUCCESS" << std::endl;
trace << "PASS 2: SUCCESS\n";
return true;
}
}
// Now this is the most interesting case. We have reached a
......@@ -596,7 +556,7 @@ namespace spot
// ROOT is ascending: we just have to merge all SSCCs from the
// top of ROOT that have an index greater to the one of
// the SSCC of S2 (called the "threshold").
int threshold = *spi.second;
int threshold = i->second;
std::list<state*> rem;
bool acc = false;
......@@ -634,11 +594,11 @@ namespace spot
}
void
ta_check::clear(numbered_state_heap* h, std::stack<pair_state_iter> todo,
ta_check::clear(hash_type& h, std::stack<pair_state_iter> todo,
std::queue<spot::state*> init_states)
{
set_states(states() + h->size());
set_states(states() + h.size());
while (!init_states.empty())
{
......@@ -653,15 +613,14 @@ namespace spot
todo.pop();
dec_depth();
}
delete h;
}
void
ta_check::clear(numbered_state_heap* h, std::stack<pair_state_iter> todo,
ta_check::clear(hash_type& h, std::stack<pair_state_iter> todo,
spot::ta_succ_iterator* init_states_it)
{
set_states(states() + h->size());
set_states(states() + h.size());
delete init_states_it;
......@@ -672,7 +631,6 @@ namespace spot
todo.pop();
dec_depth();
}
delete h;
}
std::ostream&
......
// -*- coding: utf-8 -*-
// Copyright (C) 2008, 2012, 2013 Laboratoire de Recherche et
// Copyright (C) 2008, 2012, 2013, 2014 Laboratoire de Recherche et
// Dévelopment de l'Epita (LRDE).
// Copyright (C) 2003, 2004, 2005, 2006 Laboratoire d'Informatique de
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
......@@ -25,7 +25,6 @@
#include "ta/taproduct.hh"
#include "misc/optionmap.hh"
#include "tgbaalgos/gtec/nsheap.hh"
#include "tgbaalgos/emptiness_stats.hh"
#include <stack>
#include <queue>
......@@ -87,6 +86,8 @@ namespace spot
/// See the paper cited above.
class SPOT_API ta_check : public ec_statistics
{
typedef std::unordered_map<const state*, int,
state_ptr_hash, state_ptr_equal> hash_type;
public:
ta_check(const ta_product* a, option_map o = option_map());
virtual
......@@ -126,18 +127,18 @@ namespace spot
protected:
void
clear(numbered_state_heap* h, std::stack<pair_state_iter> todo, std::queue<
clear(hash_type& h, std::stack<pair_state_iter> todo, std::queue<
spot::state*> init_set);
void
clear(numbered_state_heap* h, std::stack<pair_state_iter> todo,
clear(hash_type& h, std::stack<pair_state_iter> todo,
spot::ta_succ_iterator* init_states_it);
/// the heuristic for livelock-accepting runs detection, it's described
/// in the paper cited above
bool
heuristic_livelock_detection(const state * stuttering_succ,
numbered_state_heap* h, int h_livelock_root, std::set<const state*,
hash_type& h, int h_livelock_root, std::set<const state*,
state_ptr_less_than> liveset_curr);
const ta_product* a_; ///< The automaton.
......
// -*- coding utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2013 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2010, 2011, 2012, 2013, 2014 Laboratoire de Recherche
// et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
......@@ -35,7 +35,6 @@
#include "ltlvisit/tostring.hh"
#include <iostream>
#include "tgba/bddprint.hh"
#include "tgbaalgos/gtec/nsheap.hh"
#include <stack>
#include "tgba2ta.hh"
#include "taalgos/statessetbuilder.hh"
......@@ -164,9 +163,9 @@ namespace spot
// * h: a hash of all visited nodes, with their order,
// (it is called "Hash" in Couvreur's paper)
numbered_state_heap* h =
numbered_state_heap_hash_map_factory::instance()->build();
///< Heap of visited states.
typedef std::unordered_map<const state*, int,
state_ptr_hash, state_ptr_equal> hash_type;
hash_type h; ///< Heap of visited states.
// * num: the number of visited nodes. Used to set the order of each
// visited node,
......@@ -182,13 +181,8 @@ namespace spot
// * init: the set of the depth-first search initial states
std::stack<state*> init_set;
ta::states_set_t::const_iterator it;
ta::states_set_t init_states = testing_automata->get_initial_states_set();
for (it = init_states.begin(); it != init_states.end(); ++it)
{
state* init_state = (*it);
init_set.push(init_state);
}
for (state* s: testing_automata->get_initial_states_set())
init_set.push(s);
while (!init_set.empty())
{
......@@ -196,31 +190,31 @@ namespace spot
{
state_ta_explicit* init =
down_cast<state_ta_explicit*> (init_set.top());
down_cast<state_ta_explicit*> (init_set.top());
init_set.pop();
state_ta_explicit* init_clone = init;
numbered_state_heap::state_index_p h_init = h->find(init_clone);
if (h_init.first)
continue;
if (!h.insert(std::make_pair(init, num + 1)).second)
{
init->destroy();
continue;
}
h->insert(init_clone, ++num);
sscc.push(num);
sscc.push(++num);
arc.push(bddfalse);
sscc.top().is_accepting
= testing_automata->is_accepting_state(init);
tgba_succ_iterator* iter = testing_automata->succ_iter(init);
iter->first();
todo.push(pair_state_iter(init, iter));
todo.emplace(init, iter);
}
while (!todo.empty())
{
state* curr = todo.top().first;
numbered_state_heap::state_index_p spi = h->find(curr);
auto i = h.find(curr);
// If we have reached a dead component, ignore it.
if (*spi.second == -1)
if (i != h.end() && i->second == -1)
{
todo.pop();
continue;
......@@ -238,16 +232,14 @@ namespace spot
todo.pop();
// fill rem with any component removed,
numbered_state_heap::state_index_p spi = h->index(curr);
assert(spi.first);
assert(i != h.end());
sscc.rem().push_front(curr);
// When backtracking the root of an SSCC, we must also
// remove that SSCC from the ROOT stacks. We must
// discard from H all reachable states from this SSCC.
assert(!sscc.empty());
if (sscc.top().index == *spi.second)
if (sscc.top().index == i->second)
{
// removing states
std::list<state*>::iterator i;
......@@ -256,25 +248,20 @@ namespace spot
|| (sscc.top().condition ==
testing_automata->all_acceptance_conditions()));
trace << "*** sscc.size() = ***"
<< sscc.size() << std::endl;
for (i = sscc.rem().begin(); i != sscc.rem().end(); ++i)
trace << "*** sscc.size() = ***" << sscc.size() << '\n';
for (auto j: sscc.rem())
{
numbered_state_heap::state_index_p spi =
h->index((*i));
assert(spi.first->compare(*i) == 0);
assert(*spi.second != -1);
*spi.second = -1;
h[j] = -1;
if (is_livelock_accepting_sscc)
{
// if it is an accepting sscc add the state to
// G (=the livelock-accepting states set)
trace << "*** sscc.size() > 1: states: ***"
<< testing_automata->format_state(*i)
<< std::endl;
state_ta_explicit * livelock_accepting_state =