spot/spot/twaalgos/word.cc
Alexandre Duret-Lutz ac6b0c9432 include config.h in all *.cc files
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.
2018-02-21 17:59:09 +01:00

266 lines
7.3 KiB
C++

// -*- coding: utf-8 -*-
// Copyright (C) 2013-2018 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// 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 <spot/twaalgos/word.hh>
#include <spot/twa/bddprint.hh>
#include <spot/twa/bdddict.hh>
#include <spot/tl/parse.hh>
#include <spot/tl/simplify.hh>
#include <spot/tl/apcollect.hh>
namespace spot
{
twa_word::twa_word(const twa_run_ptr& run)
: dict_(run->aut->get_dict())
{
for (auto& i: run->prefix)
prefix.emplace_back(i.label);
for (auto& i: run->cycle)
cycle.emplace_back(i.label);
dict_->register_all_variables_of(run->aut, this);
}
twa_word::twa_word(const bdd_dict_ptr& dict)
: dict_(dict)
{
}
void
twa_word::simplify()
{
// If all the formulas on the cycle are compatible, reduce the
// cycle to a simple conjunction.
//
// For instance
// !a|!b; b; a&b; cycle{a; b; a&b}
// can be reduced to
// !a|!b; b; a&b; cycle{a&b}
{
bdd all = bddtrue;
for (auto& i: cycle)
all &= i;
if (all != bddfalse)
{
cycle.clear();
cycle.emplace_back(all);
}
}
// If the last formula of the prefix is compatible with the
// last formula of the cycle, we can shift the cycle and
// reduce the prefix.
//
// For instance
// !a|!b; b; a&b; cycle{a&b}
// can be reduced to
// !a|!b; cycle{a&b}
while (!prefix.empty())
{
bdd a = prefix.back() & cycle.back();
if (a == bddfalse)
break;
prefix.pop_back();
cycle.pop_back();
cycle.push_front(a);
}
// Get rid of any disjunction.
//
// For instance
// !a|!b; cycle{a&b}
// can be reduced to
// !a&!b; cycle{a&b}
for (auto& i: prefix)
i = bdd_satone(i);
for (auto& i: cycle)
i = bdd_satone(i);
}
std::ostream&
operator<<(std::ostream& os, const twa_word& w)
{
if (w.cycle.empty())
throw std::runtime_error("a twa_word may not have an empty cycle");
auto d = w.get_dict();
if (!w.prefix.empty())
for (auto& i: w.prefix)
{
bdd_print_formula(os, d, i);
os << "; ";
}
bool notfirst = false;
os << "cycle{";
for (auto& i: w.cycle)
{
if (notfirst)
os << "; ";
notfirst = true;
bdd_print_formula(os, d, i);
}
os << '}';
return os;
}
namespace
{
static void word_parse_error(const std::string& word,
size_t i, parsed_formula pf)
{
std::ostringstream os;
pf.format_errors(os, word, i);
throw parse_error(os.str());
}
static void word_parse_error(const std::string& word, size_t i,
const std::string& message)
{
if (i == std::string::npos)
i = word.size();
std::ostringstream s;
s << ">>> " << word << '\n';
for (auto j = i + 4; j > 0; --j)
s << ' ';
s << '^' << '\n';
s << message << '\n';
throw parse_error(s.str());
}
static size_t skip_next_formula(const std::string& word, size_t begin)
{
bool quoted = false;
auto size = word.size();
for (auto j = begin; j < size; ++j)
{
auto c = word[j];
if (!quoted && (c == ';' || c == '}'))
return j;
if (c == '"')
quoted = !quoted;
else if (quoted && c == '\\')
++j;
}
if (quoted)
word_parse_error(word, word.size(), "Unclosed string");
return std::string::npos;
}
}
twa_word_ptr parse_word(const std::string& word, const bdd_dict_ptr& dict)
{
atomic_prop_set aps;
tl_simplifier tls(dict);
twa_word_ptr tw = make_twa_word(dict);
size_t i = 0;
auto ind = i;
auto extract_bdd =
[&](typename twa_word::seq_t& seq)
{
auto sub = word.substr(i, ind - i);
auto pf = spot::parse_infix_boolean(sub);
if (!pf.errors.empty())
word_parse_error(word, i, pf);
atomic_prop_collect(pf.f, &aps);
seq.emplace_back(tls.as_bdd(pf.f));
if (word[ind] == '}')
return true;
// Skip blanks after semi-colon
i = word.find_first_not_of(' ', ind + 1);
return false;
};
// Parse the prefix part. Can be empty.
while (word.substr(i, 6) != std::string("cycle{"))
{
ind = skip_next_formula(word, i);
if (ind == std::string::npos)
word_parse_error(word, word.size(),
"A twa_word must contain a cycle");
if (word[ind] == '}')
word_parse_error(word, ind, "Expected ';' delimiter: "
"'}' stands for ending a cycle");
// Exract formula, convert it to bdd and add it to the prefix sequence
extract_bdd(tw->prefix);
if (i == std::string::npos)
word_parse_error(word, ind + 1, "Missing cycle in formula");
}
// Consume "cycle{"
i += 6;
while (true)
{
ind = skip_next_formula(word, i);
if (ind == std::string::npos)
word_parse_error(word, word.size(),
"Missing ';' or '}' after formula");
// Extract formula, convert it to bdd and add it to the cycle sequence
// Break if an '}' is encountered
if (extract_bdd(tw->cycle))
break;
if (i == std::string::npos)
word_parse_error(word, ind + 1,
"Missing end of cycle character: '}'");
}
if (ind != word.size() - 1)
word_parse_error(word, ind + 1, "Input should be finished after cycle");
for (auto ap: aps)
dict->register_proposition(ap, tw.get());
return tw;
}
twa_graph_ptr twa_word::as_automaton() const
{
twa_graph_ptr aut = make_twa_graph(dict_);
aut->prop_weak(true);
aut->prop_universal(true);
// Register the atomic propositions used in the word.
{
bdd support = bddtrue;
for (auto b: prefix)
support &= bdd_support(b);
for (auto b: cycle)
support &= bdd_support(b);
while (support != bddtrue)
{
int v = bdd_var(support);
support = bdd_high(support);
aut->register_ap(dict_->bdd_map[v].f);
}
}
size_t i = 0;
aut->new_states(prefix.size() + cycle.size());
for (auto b: prefix)
{
aut->new_edge(i, i + 1, b);
++i;
}
size_t j = i;
auto b = cycle.begin();
auto end = --cycle.end();
for (; b != end; ++b)
{
aut->new_edge(i, i + 1, *b);
++i;
}
// Close the loop
aut->new_edge(i, j, *b);
return aut;
}
}