Commit b3ee6831 authored by Maximilien Colange's avatar Maximilien Colange
Browse files

Automata with no state are no longer allowed.

* NEWS, spot/twa/twa.hh: Document the change.
* spot/twa/twagraph.hh, spot/kripke/kripkegraph.hh:
  Add an exception in get_init_state_number().
  get_init_state() now calls get_init_state_number().
* spot/twa/twagraph.cc, spot/twaalgos/simulation.cc,
  spot/twaalgos/powerset.cc, spot/twaalgos/complete.cc,
  spot/twaalgos/sccfilter.cc: Remove now useless tests.
* spot/twaalgos/hoa.cc: Remove now useless comment.
* spot/twaalgos/minimize.cc: Never return an automaton with no state.
parent da6fc955
New in spot 2.2.1.dev (Not yet released) New in spot 2.2.1.dev (Not yet released)
Library:
* A twa is required to have at least one state, the initial state.
Build: Build:
* If the system has an installed libltdl library, use it instead of * If the system has an installed libltdl library, use it instead of
......
...@@ -177,16 +177,15 @@ namespace spot ...@@ -177,16 +177,15 @@ namespace spot
graph_t::state get_init_state_number() const graph_t::state get_init_state_number() const
{ {
// If the kripke has no state, it has no initial state.
if (num_states() == 0) if (num_states() == 0)
const_cast<graph_t&>(g_).new_state(); throw std::runtime_error("kripke has no state at all");
return init_number_; return init_number_;
} }
virtual const kripke_graph_state* get_init_state() const override virtual const kripke_graph_state* get_init_state() const override
{ {
if (num_states() == 0) return state_from_number(get_init_state_number());
const_cast<graph_t&>(g_).new_state();
return state_from_number(init_number_);
} }
/// \brief Allow to get an iterator on the state we passed in /// \brief Allow to get an iterator on the state we passed in
......
...@@ -595,7 +595,8 @@ namespace spot ...@@ -595,7 +595,8 @@ namespace spot
/// Browsing a TωA is usually achieved using two methods: \c /// Browsing a TωA is usually achieved using two methods: \c
/// get_init_state(), and succ(). The former returns the initial /// get_init_state(), and succ(). The former returns the initial
/// state while the latter allows iterating over the outgoing edges /// state while the latter allows iterating over the outgoing edges
/// of any given state. /// of any given state. A TωA is always assumed to have at least
/// one state, the initial one.
/// ///
/// Note that although this is a transition-based automata, we never /// Note that although this is a transition-based automata, we never
/// represent edges in the API. Information about edges can be /// represent edges in the API. Information about edges can be
...@@ -605,7 +606,7 @@ namespace spot ...@@ -605,7 +606,7 @@ namespace spot
/// The interface presented here is what we call the on-the-fly /// The interface presented here is what we call the on-the-fly
/// interface of automata, because the TωA class can be subclassed /// interface of automata, because the TωA class can be subclassed
/// to implement an object that computes its successors on-the-fly. /// to implement an object that computes its successors on-the-fly.
/// The down-side is that all these methods are virtual, so you you /// The down-side is that all these methods are virtual, so you
/// pay the cost of virtual calls when iterating over automata /// pay the cost of virtual calls when iterating over automata
/// constructed on-the-fly. Also the interface assumes that each /// constructed on-the-fly. Also the interface assumes that each
/// successor state is a new object whose memory management is the /// successor state is a new object whose memory management is the
......
...@@ -154,8 +154,6 @@ namespace spot ...@@ -154,8 +154,6 @@ namespace spot
void twa_graph::purge_unreachable_states() void twa_graph::purge_unreachable_states()
{ {
unsigned num_states = g_.num_states(); unsigned num_states = g_.num_states();
if (SPOT_UNLIKELY(num_states == 0))
return;
// The TODO vector serves two purposes: // The TODO vector serves two purposes:
// - it is a stack of state to process, // - it is a stack of state to process,
// - it is a set of processed states. // - it is a set of processed states.
...@@ -166,7 +164,7 @@ namespace spot ...@@ -166,7 +164,7 @@ namespace spot
std::vector<unsigned> todo(num_states, 0); std::vector<unsigned> todo(num_states, 0);
const unsigned seen = 1 << (sizeof(unsigned)*8-1); const unsigned seen = 1 << (sizeof(unsigned)*8-1);
const unsigned mask = seen - 1; const unsigned mask = seen - 1;
todo[0] = init_number_; todo[0] = get_init_state_number();
todo[init_number_] |= seen; todo[init_number_] |= seen;
unsigned todo_pos = 1; unsigned todo_pos = 1;
do do
...@@ -197,16 +195,13 @@ namespace spot ...@@ -197,16 +195,13 @@ namespace spot
void twa_graph::purge_dead_states() void twa_graph::purge_dead_states()
{ {
unsigned num_states = g_.num_states(); unsigned num_states = g_.num_states();
if (num_states == 0)
return;
std::vector<unsigned> useful(num_states, 0); std::vector<unsigned> useful(num_states, 0);
// Make a DFS to compute a topological order. // Make a DFS to compute a topological order.
std::vector<unsigned> order; std::vector<unsigned> order;
order.reserve(num_states); order.reserve(num_states);
std::vector<std::pair<unsigned, unsigned>> todo; // state, trans std::vector<std::pair<unsigned, unsigned>> todo; // state, trans
useful[init_number_] = 1; useful[get_init_state_number()] = 1;
todo.emplace_back(init_number_, g_.state_storage(init_number_).succ); todo.emplace_back(init_number_, g_.state_storage(init_number_).succ);
do do
{ {
......
...@@ -264,16 +264,15 @@ namespace spot ...@@ -264,16 +264,15 @@ namespace spot
state_num get_init_state_number() const state_num get_init_state_number() const
{ {
// If the automaton has no state, it has no initial state.
if (num_states() == 0) if (num_states() == 0)
const_cast<graph_t&>(g_).new_state(); throw std::runtime_error("automaton has no state at all");
return init_number_; return init_number_;
} }
virtual const twa_graph_state* get_init_state() const override virtual const twa_graph_state* get_init_state() const override
{ {
if (num_states() == 0) return state_from_number(get_init_state_number());
const_cast<graph_t&>(g_).new_state();
return state_from_number(init_number_);
} }
virtual twa_succ_iterator* virtual twa_succ_iterator*
......
...@@ -23,11 +23,6 @@ namespace spot ...@@ -23,11 +23,6 @@ namespace spot
{ {
unsigned complete_here(twa_graph_ptr aut) unsigned complete_here(twa_graph_ptr aut)
{ {
// We do not use the initial state, but calling
// get_init_state_number() may create it and change the number of
// states. This has to be done before calling aut->num_states().
unsigned init = aut->get_init_state_number();
unsigned n = aut->num_states(); unsigned n = aut->num_states();
unsigned sink = -1U; unsigned sink = -1U;
...@@ -87,7 +82,7 @@ namespace spot ...@@ -87,7 +82,7 @@ namespace spot
// If the automaton is empty, pretend that state 0 is a sink. // If the automaton is empty, pretend that state 0 is a sink.
if (t == 0) if (t == 0)
sink = init; sink = aut->get_init_state_number();
// Now complete all states (excluding any newly added the sink). // Now complete all states (excluding any newly added the sink).
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i)
......
...@@ -312,16 +312,13 @@ namespace spot ...@@ -312,16 +312,13 @@ namespace spot
} }
} }
// Calling get_init_state_number() may add a state to empty
// automata, so it has to be done first.
unsigned init = aut->get_init_state_number();
metadata md(aut, implicit_labels, state_labels); metadata md(aut, implicit_labels, state_labels);
if (acceptance == Hoa_Acceptance_States && !md.has_state_acc) if (acceptance == Hoa_Acceptance_States && !md.has_state_acc)
acceptance = Hoa_Acceptance_Transitions; acceptance = Hoa_Acceptance_Transitions;
unsigned num_states = aut->num_states(); unsigned num_states = aut->num_states();
unsigned init = aut->get_init_state_number();
const char nl = newline ? '\n' : ' '; const char nl = newline ? '\n' : ' ';
os << (v1_1 ? "HOA: v1.1" : "HOA: v1") << nl; os << (v1_1 ? "HOA: v1.1" : "HOA: v1") << nl;
......
...@@ -171,6 +171,10 @@ namespace spot ...@@ -171,6 +171,10 @@ namespace spot
init_state->destroy(); init_state->destroy();
res->set_init_state(init_num); res->set_init_state(init_num);
} }
else
{
res->set_init_state(res->new_state());
}
return res; return res;
} }
......
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 2011, 2013, 2014, 2015 Laboratoire de // Copyright (C) 2009-2011, 2013-2016 Laboratoire de Recherche et
// Recherche et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6), // Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre // département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie. // et Marie Curie.
...@@ -101,11 +101,8 @@ namespace spot ...@@ -101,11 +101,8 @@ namespace spot
unsigned nap = number_of_variables(allap); unsigned nap = number_of_variables(allap);
// Call this before aut->num_states(), since it might add a state.
unsigned init_num = aut->get_init_state_number(); unsigned init_num = aut->get_init_state_number();
unsigned ns = aut->num_states(); unsigned ns = aut->num_states();
assert(ns > 0);
if ((-1UL / ns) >> nap == 0) if ((-1UL / ns) >> nap == 0)
throw std::runtime_error("too many atomic propositions (or states)"); throw std::runtime_error("too many atomic propositions (or states)");
......
...@@ -277,8 +277,6 @@ namespace spot ...@@ -277,8 +277,6 @@ namespace spot
scc_info* given_si, Args&&... args) scc_info* given_si, Args&&... args)
{ {
unsigned in_n = aut->num_states(); unsigned in_n = aut->num_states();
if (in_n == 0) // nothing to filter.
return make_twa_graph(aut, twa::prop_set::all());
twa_graph_ptr filtered = make_twa_graph(aut->get_dict()); twa_graph_ptr filtered = make_twa_graph(aut->get_dict());
filtered->copy_ap_of(aut); filtered->copy_ap_of(aut);
......
...@@ -161,14 +161,11 @@ namespace spot ...@@ -161,14 +161,11 @@ namespace spot
throw std::runtime_error throw std::runtime_error
("direct_simulation() requires separate Inf and Fin sets"); ("direct_simulation() requires separate Inf and Fin sets");
// Call get_init_state_number() before anything else as it
// might add a state.
unsigned init_state_number = in->get_init_state_number();
scc_info_.reset(new scc_info(in)); scc_info_.reset(new scc_info(in));
unsigned ns = in->num_states(); unsigned ns = in->num_states();
assert(ns > 0);
size_a_ = ns; size_a_ = ns;
unsigned init_state_number = in->get_init_state_number();
auto all_inf = in->get_acceptance().used_inf_fin_sets().first; auto all_inf = in->get_acceptance().used_inf_fin_sets().first;
all_inf_ = all_inf; all_inf_ = all_inf;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment