This helps working around missing C functions like strcasecmp that do not exist everywhere (e.g. on Cygwin), and for which lib/ supplies a replacement. Unfortunately we do not have such build in our current continuous integration suite, so we cannot easily detect files where such config.h inclusion would be useful. Therefore this patch simply makes it mandatory to include config.h in *.cc files. Including this in public *.hh file is currently forbidden. * spot/gen/automata.cc, spot/gen/formulas.cc, spot/kripke/fairkripke.cc, spot/kripke/kripke.cc, spot/ltsmin/ltsmin.cc, spot/misc/game.cc, spot/parseaut/fmterror.cc, spot/parsetl/fmterror.cc, spot/parsetl/parsetl.yy, spot/priv/bddalloc.cc, spot/priv/freelist.cc, spot/priv/satcommon.cc, spot/priv/trim.cc, spot/priv/weight.cc, spot/ta/ta.cc, spot/ta/taexplicit.cc, spot/ta/taproduct.cc, spot/ta/tgtaexplicit.cc, spot/ta/tgtaproduct.cc, spot/taalgos/dot.cc, spot/taalgos/emptinessta.cc, spot/taalgos/minimize.cc, spot/taalgos/reachiter.cc, spot/taalgos/statessetbuilder.cc, spot/taalgos/stats.cc, spot/taalgos/tgba2ta.cc, spot/tl/apcollect.cc, spot/tl/contain.cc, spot/tl/declenv.cc, spot/tl/defaultenv.cc, spot/tl/dot.cc, spot/tl/exclusive.cc, spot/tl/hierarchy.cc, spot/tl/length.cc, spot/tl/ltlf.cc, spot/tl/mark.cc, spot/tl/mutation.cc, spot/tl/nenoform.cc, spot/tl/print.cc, spot/tl/randomltl.cc, spot/tl/relabel.cc, spot/tl/remove_x.cc, spot/tl/simplify.cc, spot/tl/snf.cc, spot/tl/unabbrev.cc, spot/twa/acc.cc, spot/twa/bdddict.cc, spot/twa/bddprint.cc, spot/twa/formula2bdd.cc, spot/twa/taatgba.cc, spot/twa/twa.cc, spot/twa/twagraph.cc, spot/twa/twaproduct.cc, spot/twaalgos/aiger.cc, spot/twaalgos/alternation.cc, spot/twaalgos/are_isomorphic.cc, spot/twaalgos/bfssteps.cc, spot/twaalgos/canonicalize.cc, spot/twaalgos/cleanacc.cc, spot/twaalgos/cobuchi.cc, spot/twaalgos/complement.cc, spot/twaalgos/complete.cc, spot/twaalgos/compsusp.cc, spot/twaalgos/couvreurnew.cc, spot/twaalgos/cycles.cc, spot/twaalgos/degen.cc, spot/twaalgos/determinize.cc, spot/twaalgos/dot.cc, spot/twaalgos/dtbasat.cc, spot/twaalgos/dtwasat.cc, spot/twaalgos/dualize.cc, spot/twaalgos/emptiness.cc, spot/twaalgos/gtec/ce.cc, spot/twaalgos/gtec/gtec.cc, spot/twaalgos/gtec/sccstack.cc, spot/twaalgos/gtec/status.cc, spot/twaalgos/gv04.cc, spot/twaalgos/hoa.cc, spot/twaalgos/iscolored.cc, spot/twaalgos/isdet.cc, spot/twaalgos/isunamb.cc, spot/twaalgos/isweakscc.cc, spot/twaalgos/langmap.cc, spot/twaalgos/lbtt.cc, spot/twaalgos/ltl2taa.cc, spot/twaalgos/ltl2tgba_fm.cc, spot/twaalgos/magic.cc, spot/twaalgos/mask.cc, spot/twaalgos/minimize.cc, spot/twaalgos/neverclaim.cc, spot/twaalgos/parity.cc, spot/twaalgos/postproc.cc, spot/twaalgos/powerset.cc, spot/twaalgos/product.cc, spot/twaalgos/rabin2parity.cc, spot/twaalgos/randomgraph.cc, spot/twaalgos/randomize.cc, spot/twaalgos/reachiter.cc, spot/twaalgos/relabel.cc, spot/twaalgos/remfin.cc, spot/twaalgos/remprop.cc, spot/twaalgos/sbacc.cc, spot/twaalgos/sccfilter.cc, spot/twaalgos/sccinfo.cc, spot/twaalgos/se05.cc, spot/twaalgos/sepsets.cc, spot/twaalgos/simulation.cc, spot/twaalgos/split.cc, spot/twaalgos/stats.cc, spot/twaalgos/strength.cc, spot/twaalgos/stripacc.cc, spot/twaalgos/stutter.cc, spot/twaalgos/sum.cc, spot/twaalgos/tau03.cc, spot/twaalgos/tau03opt.cc, spot/twaalgos/totgba.cc, spot/twaalgos/toweak.cc, spot/twaalgos/translate.cc, spot/twaalgos/word.cc, tests/core/acc.cc, tests/core/bitvect.cc, tests/core/checkpsl.cc, tests/core/checkta.cc, tests/core/consterm.cc, tests/core/emptchk.cc, tests/core/equalsf.cc, tests/core/graph.cc, tests/core/ikwiad.cc, tests/core/intvcmp2.cc, tests/core/intvcomp.cc, tests/core/kind.cc, tests/core/kripkecat.cc, tests/core/length.cc, tests/core/ltlrel.cc, tests/core/ngraph.cc, tests/core/parity.cc, tests/core/randtgba.cc, tests/core/readltl.cc, tests/core/reduc.cc, tests/core/safra.cc, tests/core/sccif.cc, tests/core/syntimpl.cc, tests/core/taatgba.cc, tests/core/tostring.cc, tests/core/trival.cc, tests/core/twagraph.cc, tests/ltsmin/modelcheck.cc, spot/parseaut/scanaut.ll, spot/parsetl/scantl.ll: Include config.h. * spot/gen/Makefile.am, spot/graph/Makefile.am, spot/kripke/Makefile.am, spot/ltsmin/Makefile.am, spot/parseaut/Makefile.am, spot/parsetl/Makefile.am, spot/priv/Makefile.am, spot/ta/Makefile.am, spot/taalgos/Makefile.am, spot/tl/Makefile.am, spot/twa/Makefile.am, spot/twaalgos/Makefile.am, spot/twaalgos/gtec/Makefile.am, tests/Makefile.am: Add the -I lib/ flags. * tests/sanity/includes.test: Catch missing config.h in *.cc, and diagnose config.h in *.hh. * tests/sanity/style.test: Better diagnostics.
437 lines
11 KiB
C++
437 lines
11 KiB
C++
// -*- coding: utf-8 -*-
|
|
// Copyright (C) 2008, 2011-2018 Laboratoire de Recherche et
|
|
// Développement de l'Epita (LRDE).
|
|
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
|
// et Marie Curie.
|
|
//
|
|
// This file is part of Spot, a model checking library.
|
|
//
|
|
// Spot is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
// License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "config.h"
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <spot/twa/twa.hh>
|
|
#include <spot/twaalgos/stats.hh>
|
|
#include <spot/twaalgos/reachiter.hh>
|
|
#include <spot/tl/print.hh>
|
|
#include <spot/twaalgos/isdet.hh>
|
|
#include <spot/twaalgos/isweakscc.hh>
|
|
#include <cstring>
|
|
|
|
namespace spot
|
|
{
|
|
namespace
|
|
{
|
|
class stats_bfs: public twa_reachable_iterator_breadth_first
|
|
{
|
|
public:
|
|
stats_bfs(const const_twa_ptr& a, twa_statistics& s)
|
|
: twa_reachable_iterator_breadth_first(a), s_(s)
|
|
{
|
|
}
|
|
|
|
void
|
|
process_state(const state*, int, twa_succ_iterator*) override final
|
|
{
|
|
++s_.states;
|
|
}
|
|
|
|
void
|
|
process_link(const state*, int, const state*, int,
|
|
const twa_succ_iterator*) override
|
|
{
|
|
++s_.edges;
|
|
}
|
|
|
|
private:
|
|
twa_statistics& s_;
|
|
};
|
|
|
|
class sub_stats_bfs final: public stats_bfs
|
|
{
|
|
public:
|
|
sub_stats_bfs(const const_twa_ptr& a, twa_sub_statistics& s)
|
|
: stats_bfs(a, s), s_(s), seen_(a->ap_vars())
|
|
{
|
|
}
|
|
|
|
void
|
|
process_link(const state*, int, const state*, int,
|
|
const twa_succ_iterator* it) override
|
|
{
|
|
++s_.edges;
|
|
bdd cond = it->cond();
|
|
while (cond != bddfalse)
|
|
{
|
|
cond -= bdd_satoneset(cond, seen_, bddtrue);
|
|
++s_.transitions;
|
|
}
|
|
}
|
|
|
|
private:
|
|
twa_sub_statistics& s_;
|
|
bdd seen_;
|
|
};
|
|
|
|
|
|
template<typename SU, typename EU>
|
|
void dfs(const const_twa_graph_ptr& ge, SU state_update, EU edge_update)
|
|
{
|
|
unsigned init = ge->get_init_state_number();
|
|
unsigned num_states = ge->num_states();
|
|
// The TODO vector serves two purposes:
|
|
// - it is a stack of states to process,
|
|
// - it is a set of processed states.
|
|
// The lower 31 bits of each entry is a state on the stack. (The
|
|
// next usable entry on the stack is indicated by todo_pos.) The
|
|
// 32th bit (i.e., the sign bit) of todo[x] indicates whether
|
|
// states number x has been seen.
|
|
std::vector<unsigned> todo(num_states, 0);
|
|
const unsigned seen = 1 << (sizeof(unsigned)*8-1);
|
|
const unsigned mask = seen - 1;
|
|
unsigned todo_pos = 0;
|
|
for (unsigned i: ge->univ_dests(init))
|
|
{
|
|
todo[todo_pos++] = i;
|
|
todo[i] |= seen;
|
|
}
|
|
do
|
|
{
|
|
state_update();
|
|
unsigned cur = todo[--todo_pos] & mask;
|
|
todo[todo_pos] ^= cur; // Zero the state
|
|
for (auto& t: ge->out(cur))
|
|
{
|
|
edge_update(t.cond);
|
|
for (unsigned dst: ge->univ_dests(t.dst))
|
|
if (!(todo[dst] & seen))
|
|
{
|
|
todo[dst] |= seen;
|
|
todo[todo_pos++] |= dst;
|
|
}
|
|
}
|
|
}
|
|
while (todo_pos > 0);
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
|
|
std::ostream& twa_statistics::dump(std::ostream& out) const
|
|
{
|
|
out << "edges: " << edges << '\n';
|
|
out << "states: " << states << '\n';
|
|
return out;
|
|
}
|
|
|
|
std::ostream& twa_sub_statistics::dump(std::ostream& out) const
|
|
{
|
|
out << "transitions: " << transitions << '\n';
|
|
this->twa_statistics::dump(out);
|
|
return out;
|
|
}
|
|
|
|
twa_statistics
|
|
stats_reachable(const const_twa_ptr& g)
|
|
{
|
|
twa_statistics s;
|
|
auto ge = std::dynamic_pointer_cast<const twa_graph>(g);
|
|
if (!ge)
|
|
{
|
|
stats_bfs d(g, s);
|
|
d.run();
|
|
}
|
|
else
|
|
{
|
|
dfs(ge,
|
|
[&s](){ ++s.states; },
|
|
[&s](bdd){ ++s.edges; });
|
|
}
|
|
return s;
|
|
}
|
|
|
|
twa_sub_statistics
|
|
sub_stats_reachable(const const_twa_ptr& g)
|
|
{
|
|
twa_sub_statistics s;
|
|
auto ge = std::dynamic_pointer_cast<const twa_graph>(g);
|
|
if (!ge)
|
|
{
|
|
sub_stats_bfs d(g, s);
|
|
d.run();
|
|
}
|
|
else
|
|
{
|
|
dfs(ge,
|
|
[&s](){ ++s.states; },
|
|
[&s, &ge](bdd cond)
|
|
{
|
|
++s.edges;
|
|
while (cond != bddfalse)
|
|
{
|
|
cond -= bdd_satoneset(cond, ge->ap_vars(), bddtrue);
|
|
++s.transitions;
|
|
}
|
|
});
|
|
}
|
|
return s;
|
|
}
|
|
|
|
void printable_formula::print(std::ostream& os, const char*) const
|
|
{
|
|
print_psl(os, val_);
|
|
}
|
|
|
|
void printable_scc_info::print(std::ostream& os, const char* pos) const
|
|
{
|
|
unsigned n = val_->scc_count();
|
|
if (*pos != '[')
|
|
{
|
|
os << n;
|
|
return;
|
|
}
|
|
bool accepting = false;
|
|
bool rejecting = false;
|
|
bool trivial = false;
|
|
bool non_trivial = false;
|
|
bool terminal = false;
|
|
bool non_terminal = false;
|
|
bool weak = false;
|
|
bool non_weak = false;
|
|
bool inherently_weak = false;
|
|
bool non_inherently_weak = false;
|
|
bool complete = false;
|
|
bool non_complete = false;
|
|
|
|
const char* beg = pos;
|
|
auto error = [&](std::string str)
|
|
{
|
|
std::ostringstream tmp;
|
|
const char* end = std::strchr(pos, ']');
|
|
tmp << "unknown option '" << str << "' in '%"
|
|
<< std::string(beg, end + 2) << '\'';
|
|
throw std::runtime_error(tmp.str());
|
|
};
|
|
|
|
do
|
|
{
|
|
++pos;
|
|
switch (*pos)
|
|
{
|
|
case 'a':
|
|
case 'R':
|
|
accepting = true;
|
|
break;
|
|
case 'A':
|
|
case 'r':
|
|
rejecting = true;
|
|
break;
|
|
case 'c':
|
|
complete = true;
|
|
break;
|
|
case 'C':
|
|
non_complete = true;
|
|
break;
|
|
case 't':
|
|
terminal = true;
|
|
break;
|
|
case 'T':
|
|
non_terminal = true;
|
|
break;
|
|
case 'v':
|
|
trivial = true;
|
|
break;
|
|
case 'V':
|
|
non_trivial = true;
|
|
break;
|
|
case 'w':
|
|
weak = true;
|
|
break;
|
|
case 'W':
|
|
non_weak = true;
|
|
break;
|
|
case 'i':
|
|
if (pos[1] == 'w')
|
|
{
|
|
inherently_weak = true;
|
|
++pos;
|
|
}
|
|
else
|
|
{
|
|
error(std::string(pos, pos + 2));
|
|
}
|
|
break;
|
|
case 'I':
|
|
if (pos[1] == 'W')
|
|
{
|
|
non_inherently_weak = true;
|
|
++pos;
|
|
}
|
|
else
|
|
{
|
|
error(std::string(pos, pos + 2));
|
|
}
|
|
break;
|
|
case ' ':
|
|
case '\t':
|
|
case '\n':
|
|
case ',':
|
|
case ']':
|
|
break;
|
|
default:
|
|
error(std::string(pos, pos + 1));
|
|
}
|
|
}
|
|
while (*pos != ']');
|
|
|
|
val_->determine_unknown_acceptance();
|
|
unsigned count = 0U;
|
|
|
|
for (unsigned i = 0; i < n; ++i)
|
|
{
|
|
if (accepting && val_->is_rejecting_scc(i))
|
|
continue;
|
|
if (rejecting && val_->is_accepting_scc(i))
|
|
continue;
|
|
if (trivial && !val_->is_trivial(i))
|
|
continue;
|
|
if (non_trivial && val_->is_trivial(i))
|
|
continue;
|
|
if (complete && !is_complete_scc(*val_, i))
|
|
continue;
|
|
if (non_complete && is_complete_scc(*val_, i))
|
|
continue;
|
|
if (terminal && !is_terminal_scc(*val_, i))
|
|
continue;
|
|
if (non_terminal && is_terminal_scc(*val_, i))
|
|
continue;
|
|
if (weak && !is_weak_scc(*val_, i))
|
|
continue;
|
|
if (non_weak && is_weak_scc(*val_, i))
|
|
continue;
|
|
if (inherently_weak && !is_inherently_weak_scc(*val_, i))
|
|
continue;
|
|
if (non_inherently_weak && is_inherently_weak_scc(*val_, i))
|
|
continue;
|
|
++count;
|
|
}
|
|
|
|
os << count;
|
|
}
|
|
|
|
void printable_acc_cond::print(std::ostream& os, const char* pos) const
|
|
{
|
|
if (*pos != '[')
|
|
{
|
|
os << val_.get_acceptance();
|
|
return;
|
|
}
|
|
const char* beg = pos;
|
|
++pos;
|
|
const char* end = strchr(pos, ']');
|
|
try
|
|
{
|
|
os << val_.name(std::string(pos, end).c_str());
|
|
}
|
|
catch (const std::runtime_error& e)
|
|
{
|
|
std::ostringstream tmp;
|
|
tmp << "while processing %"
|
|
<< std::string(beg, end + 2) << ", ";
|
|
tmp << e.what();
|
|
throw std::runtime_error(tmp.str());
|
|
|
|
}
|
|
}
|
|
|
|
|
|
stat_printer::stat_printer(std::ostream& os, const char* format)
|
|
: format_(format)
|
|
{
|
|
declare('a', &acc_);
|
|
declare('c', &scc_);
|
|
declare('d', &deterministic_);
|
|
declare('e', &edges_);
|
|
declare('f', &form_);
|
|
declare('g', &gen_acc_);
|
|
declare('n', &nondetstates_);
|
|
declare('p', &complete_);
|
|
declare('s', &states_);
|
|
declare('S', &scc_); // Historical. Deprecated. Use %c instead.
|
|
declare('t', &trans_);
|
|
set_output(os);
|
|
if (format)
|
|
prime(format);
|
|
}
|
|
|
|
std::ostream&
|
|
stat_printer::print(const const_twa_graph_ptr& aut, formula f)
|
|
{
|
|
form_ = f;
|
|
|
|
if (has('t'))
|
|
{
|
|
twa_sub_statistics s = sub_stats_reachable(aut);
|
|
states_ = s.states;
|
|
edges_ = s.edges;
|
|
trans_ = s.transitions;
|
|
}
|
|
else if (has('s') || has('e'))
|
|
{
|
|
twa_statistics s = stats_reachable(aut);
|
|
states_ = s.states;
|
|
edges_ = s.edges;
|
|
}
|
|
|
|
if (has('a'))
|
|
acc_ = aut->num_sets();
|
|
|
|
// %S was renamed to %c in Spot 1.2, so that autfilt could use %S
|
|
// and %s to designate the state numbers in input and output
|
|
// automate. We still recognize %S an obsolete and undocumented
|
|
// alias for %c, if it is not overridden by a subclass.
|
|
if (has('c') || has('S'))
|
|
scc_.automaton(aut);
|
|
|
|
if (has('n'))
|
|
{
|
|
nondetstates_ = count_nondet_states(aut);
|
|
deterministic_ = (nondetstates_ == 0);
|
|
}
|
|
else if (has('d'))
|
|
{
|
|
// This is more efficient than calling count_nondet_state().
|
|
deterministic_ = is_deterministic(aut);
|
|
}
|
|
|
|
if (has('p'))
|
|
{
|
|
complete_ = is_complete(aut);
|
|
}
|
|
|
|
if (has('g'))
|
|
gen_acc_ = aut->acc();
|
|
|
|
auto& os = format(format_);
|
|
// Make sure we do not hold a pointer to the automaton or the
|
|
// formula, as these may prevent atomic proposition to be freed
|
|
// before a next job.
|
|
scc_.reset();
|
|
form_ = nullptr;
|
|
return os;
|
|
}
|
|
|
|
}
|