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.
1258 lines
38 KiB
C++
1258 lines
38 KiB
C++
// -*- coding: utf-8 -*-
|
|
// Copyright (C) 2008-2012, 2014-2018 Laboratoire de Recherche et
|
|
// Développement de l'Epita (LRDE).
|
|
// Copyright (C) 2004, 2005 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 <cassert>
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <set>
|
|
#include <vector>
|
|
#include <spot/tl/parse.hh>
|
|
#include <spot/tl/apcollect.hh>
|
|
#include <spot/tl/randomltl.hh>
|
|
#include <spot/tl/print.hh>
|
|
#include <spot/tl/length.hh>
|
|
#include <spot/tl/simplify.hh>
|
|
#include <spot/twaalgos/randomgraph.hh>
|
|
#include <spot/twaalgos/hoa.hh>
|
|
#include <spot/twaalgos/stats.hh>
|
|
#include <spot/tl/defaultenv.hh>
|
|
#include <spot/twaalgos/dot.hh>
|
|
#include <spot/misc/random.hh>
|
|
#include <spot/misc/optionmap.hh>
|
|
#include <spot/twaalgos/degen.hh>
|
|
#include <spot/twaalgos/product.hh>
|
|
#include <spot/misc/timer.hh>
|
|
|
|
#include <spot/twaalgos/ltl2tgba_fm.hh>
|
|
|
|
#include <spot/twaalgos/emptiness.hh>
|
|
#include <spot/twaalgos/emptiness_stats.hh>
|
|
|
|
struct ec_algo
|
|
{
|
|
std::string name;
|
|
spot::emptiness_check_instantiator_ptr inst;
|
|
};
|
|
|
|
const char* default_algos[] = {
|
|
"Cou99(!poprem)",
|
|
"Cou99(!poprem shy !group)",
|
|
"Cou99(!poprem shy group)",
|
|
"Cou99(poprem)",
|
|
"Cou99(poprem shy !group)",
|
|
"Cou99(poprem shy group)",
|
|
"Cou99new",
|
|
"Cou99abs",
|
|
"CVWY90",
|
|
"CVWY90(bsh=4K)",
|
|
"GV04",
|
|
"SE05",
|
|
"SE05(bsh=4K)",
|
|
"Tau03",
|
|
"Tau03_opt",
|
|
"Tau03_opt(condstack)",
|
|
"Tau03_opt(condstack ordering)",
|
|
"Tau03_opt(condstack ordering !weights)",
|
|
nullptr
|
|
};
|
|
|
|
std::vector<ec_algo> ec_algos;
|
|
|
|
static spot::emptiness_check_ptr
|
|
cons_emptiness_check(int num, spot::const_twa_graph_ptr a,
|
|
const spot::const_twa_graph_ptr& degen,
|
|
unsigned int n_acc)
|
|
{
|
|
auto inst = ec_algos[num].inst;
|
|
if (n_acc < inst->min_sets() || n_acc > inst->max_sets())
|
|
a = degen;
|
|
if (a)
|
|
return inst->instantiate(a);
|
|
return nullptr;
|
|
}
|
|
|
|
static void
|
|
syntax(char* prog)
|
|
{
|
|
std::cerr << "Usage: "<< prog << " [OPTIONS...] PROPS..." << std::endl
|
|
<< std::endl
|
|
<< "General Options:" << std::endl
|
|
<< " -0 suppress default output, just generate the graph"
|
|
<< " in memory" << std::endl
|
|
<< " -1 produce minimal output (for our paper)" << std::endl
|
|
<< " -g output graph in dot format" << std::endl
|
|
<< " -s N seed for the random number generator" << std::endl
|
|
<< " -z display statistics about emptiness-check algorithms"
|
|
<< std::endl
|
|
<< " -Z like -z, but print extra statistics after the run"
|
|
<< " of each algorithm" << std::endl
|
|
<< std::endl
|
|
<< "Graph Generation Options:" << std::endl
|
|
<< " -a N F number of acceptance conditions and probability that"
|
|
<< " one is true" << std::endl
|
|
<< " [0 0.0]" << std::endl
|
|
<< " -d F density of the graph [0.2]" << std::endl
|
|
<< " -n N number of nodes of the graph [20]" << std::endl
|
|
<< " -t F probability of the atomic propositions to be true"
|
|
<< " [0.5]" << std::endl
|
|
<< " -det generate a deterministic and complete graph [false]"
|
|
<< std::endl
|
|
<< "LTL Formula Generation Options:" << std::endl
|
|
<< " -dp dump priorities, do not generate any formula"
|
|
<< std::endl
|
|
<< " -f N size of the formula [15]" << std::endl
|
|
<< " -F N number of formulae to generate [0]" << std::endl
|
|
<< " -l N simplify formulae using all available reductions"
|
|
<< " and reject those" << std::endl
|
|
<< " strictly smaller than N" << std::endl
|
|
<< " -i FILE do not generate formulae, read them from FILE"
|
|
<< std::endl
|
|
<< " -p S priorities to use" << std::endl
|
|
<< " -S N skip N formulae before starting to use them"
|
|
<< std::endl
|
|
<< " (useful to replay a specific seed when -u is used)"
|
|
<< std::endl
|
|
<< " -u generate unique formulae" << std::endl
|
|
<< std::endl
|
|
<< "Emptiness-Check Options:" << std::endl
|
|
<< " -A FILE use all algorithms listed in FILE" << std::endl
|
|
<< " -D degeneralize TGBA for emptiness-check algorithms that"
|
|
<< " would" << std::endl
|
|
<< " otherwise be skipped (implies -e)" << std::endl
|
|
<< " -e N compare result of all "
|
|
<< "emptiness checks on N randomly generated graphs" << std::endl
|
|
<< " -m try to reduce runs, in a second pass (implies -r)"
|
|
<< std::endl
|
|
<< " -R N repeat each emptiness-check and accepting run "
|
|
<< "computation N times" << std::endl
|
|
<< " -r compute and replay accepting runs (implies -e)"
|
|
<< std::endl
|
|
<< " ar:MODE select the mode MODE for accepting runs computation "
|
|
<< "(implies -r)" << std::endl
|
|
<< std::endl
|
|
<< "Where:" << std::endl
|
|
<< " F are floats between 0.0 and 1.0 inclusive" << std::endl
|
|
<< " E are floating values" << std::endl
|
|
<< " S are `KEY=E, KEY=E, ...' strings" << std::endl
|
|
<< " N are positive integers" << std::endl
|
|
<< " PROPS are the atomic properties to use on transitions"
|
|
<< std::endl
|
|
<< "Use -dp to see the list of KEYs." << std::endl
|
|
<< std::endl
|
|
<< "When -F or -i is used, a random graph a synchronized with"
|
|
<< " each formula." << std::endl << "If -e N is additionally used"
|
|
<< " N random graphs are generated for each formula." << std::endl;
|
|
exit(2);
|
|
}
|
|
|
|
|
|
static int
|
|
to_int(const char* s)
|
|
{
|
|
char* endptr;
|
|
int res = strtol(s, &endptr, 10);
|
|
if (*endptr)
|
|
{
|
|
std::cerr << "Failed to parse `" << s << "' as an integer." << std::endl;
|
|
exit(1);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
to_int_pos(const char* s, const char* arg)
|
|
{
|
|
int res = to_int(s);
|
|
if (res <= 0)
|
|
{
|
|
std::cerr << "argument of " << arg
|
|
<< " (" << res << ") must be positive" << std::endl;
|
|
exit(1);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
to_int_nonneg(const char* s, const char* arg)
|
|
{
|
|
int res = to_int(s);
|
|
if (res < 0)
|
|
{
|
|
std::cerr << "argument of " << arg
|
|
<< " (" << res << ") must be nonnegative" << std::endl;
|
|
exit(1);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static float
|
|
to_float(const char* s)
|
|
{
|
|
char* endptr;
|
|
// Do not use strtof(), it does not exist on Solaris 9.
|
|
float res = strtod(s, &endptr);
|
|
if (*endptr)
|
|
{
|
|
std::cerr << "Failed to parse `" << s << "' as a float." << std::endl;
|
|
exit(1);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static float
|
|
to_float_nonneg(const char* s, const char* arg)
|
|
{
|
|
float res = to_float(s);
|
|
if (res < 0)
|
|
{
|
|
std::cerr << "argument of " << arg
|
|
<< " (" << res << ") must be nonnegative" << std::endl;
|
|
exit(1);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// Convertors using for statistics:
|
|
|
|
template <typename T>
|
|
T
|
|
id(const char*, unsigned x)
|
|
{
|
|
return static_cast<T>(x);
|
|
}
|
|
|
|
spot::twa_statistics prod_stats;
|
|
|
|
static float
|
|
prod_conv(const char* name, unsigned x)
|
|
{
|
|
float y = static_cast<float>(x);
|
|
if (!strcmp(name, "transitions"))
|
|
return y / prod_stats.edges * 100.0;
|
|
return y / prod_stats.states * 100.0;
|
|
}
|
|
|
|
template <typename T, T (*convertor)(const char*, unsigned) = id<T> >
|
|
struct stat_collector
|
|
{
|
|
struct one_stat
|
|
{
|
|
T min;
|
|
T max;
|
|
T tot;
|
|
unsigned n;
|
|
|
|
one_stat()
|
|
: n(0)
|
|
{
|
|
}
|
|
|
|
void
|
|
count(T val)
|
|
{
|
|
if (n++)
|
|
{
|
|
min = std::min(min, val);
|
|
max = std::max(max, val);
|
|
tot += val;
|
|
}
|
|
else
|
|
{
|
|
max = min = tot = val;
|
|
}
|
|
}
|
|
};
|
|
|
|
typedef std::map<std::string, one_stat> alg_1stat_map;
|
|
typedef std::map<std::string, alg_1stat_map> stats_alg_map;
|
|
stats_alg_map stats;
|
|
|
|
bool
|
|
empty()
|
|
{
|
|
return stats.empty();
|
|
}
|
|
|
|
void
|
|
count(const std::string& algorithm, const spot::unsigned_statistics* s)
|
|
{
|
|
if (!s)
|
|
return;
|
|
spot::unsigned_statistics::stats_map::const_iterator i;
|
|
for (i = s->stats.begin(); i != s->stats.end(); ++i)
|
|
{
|
|
auto u = (s->*i->second)();
|
|
auto t = convertor(i->first, u);
|
|
stats[i->first][algorithm].count(t);
|
|
}
|
|
}
|
|
|
|
std::ostream&
|
|
display(std::ostream& os,
|
|
const alg_1stat_map& m, const std::string& title,
|
|
bool total = true) const
|
|
{
|
|
std::ios::fmtflags old = os.flags();
|
|
os << std::setw(25) << "" << " | "
|
|
<< std::setw(30) << std::left << title << std::right << '|' << std::endl
|
|
<< std::setw(25) << "algorithm"
|
|
<< " | min < mean < max | total | n"
|
|
<< std::endl
|
|
<< std::setw(64) << std::setfill('-') << "" << std::setfill(' ')
|
|
<< std::endl;
|
|
os << std::right << std::fixed << std::setprecision(1);
|
|
for (typename alg_1stat_map::const_iterator i = m.begin();
|
|
i != m.end(); ++i)
|
|
{
|
|
os << std::setw(25) << i->first << " |"
|
|
<< std::setw(6) << i->second.min
|
|
<< ' '
|
|
<< std::setw(8)
|
|
<< static_cast<float>(i->second.tot) / i->second.n
|
|
<< ' '
|
|
<< std::setw(6) << i->second.max
|
|
<< " |";
|
|
if (total)
|
|
os << std::setw(6) << i->second.tot;
|
|
else
|
|
os << " ";
|
|
os << " |"
|
|
<< std::setw(4) << i->second.n
|
|
<< std::endl;
|
|
}
|
|
os << std::setw(64) << std::setfill('-') << "" << std::setfill(' ')
|
|
<< std::endl;
|
|
os << std::setiosflags(old);
|
|
return os;
|
|
}
|
|
|
|
std::ostream&
|
|
display(std::ostream& os, bool total = true) const
|
|
{
|
|
typename stats_alg_map::const_iterator i;
|
|
for (i = stats.begin(); i != stats.end(); ++i)
|
|
display(os, i->second, i->first, total);
|
|
return os;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
struct ar_stat
|
|
{
|
|
int min_prefix;
|
|
int max_prefix;
|
|
int tot_prefix;
|
|
int min_cycle;
|
|
int max_cycle;
|
|
int tot_cycle;
|
|
int min_run;
|
|
int max_run;
|
|
int n;
|
|
|
|
ar_stat()
|
|
: n(0)
|
|
{
|
|
}
|
|
|
|
void
|
|
count(const spot::const_twa_run_ptr& run)
|
|
{
|
|
int p = run->prefix.size();
|
|
int c = run->cycle.size();
|
|
if (n++)
|
|
{
|
|
min_prefix = std::min(min_prefix, p);
|
|
max_prefix = std::max(max_prefix, p);
|
|
tot_prefix += p;
|
|
min_cycle = std::min(min_cycle, c);
|
|
max_cycle = std::max(max_cycle, c);
|
|
tot_cycle += c;
|
|
min_run = std::min(min_run, c + p);
|
|
max_run = std::max(max_run, c + p);
|
|
}
|
|
else
|
|
{
|
|
min_prefix = max_prefix = tot_prefix = p;
|
|
min_cycle = max_cycle = tot_cycle = c;
|
|
min_run = max_run = c + p;
|
|
}
|
|
}
|
|
};
|
|
|
|
stat_collector<unsigned> sc_ec;
|
|
stat_collector<unsigned> sc_arc;
|
|
|
|
typedef stat_collector<float, prod_conv> ec_ratio_stat_type;
|
|
ec_ratio_stat_type glob_ec_ratio_stats;
|
|
typedef std::map<int, ec_ratio_stat_type > ec_ratio_stats_type;
|
|
ec_ratio_stats_type ec_ratio_stats;
|
|
|
|
ec_ratio_stat_type arc_ratio_stats;
|
|
|
|
typedef std::map<std::string, ar_stat> ar_stats_type;
|
|
ar_stats_type ar_stats; // Statistics about accepting runs.
|
|
ar_stats_type mar_stats; // ... about minimized accepting runs.
|
|
|
|
|
|
static void
|
|
print_ar_stats(ar_stats_type& ar_stats, const std::string& s)
|
|
{
|
|
std::ios::fmtflags old = std::cout.flags();
|
|
std::cout << std::endl << s << std::endl;
|
|
std::cout << std::right << std::fixed << std::setprecision(1);
|
|
|
|
std::cout << std::setw(25) << ""
|
|
<< " | prefix | cycle |"
|
|
<< std::endl
|
|
<< std::setw(25) << "algorithm"
|
|
<< " | min < mean < max | min < mean < max | n"
|
|
<< std::endl
|
|
<< std::setw(79) << std::setfill('-') << "" << std::setfill(' ')
|
|
<< std::endl;
|
|
for (ar_stats_type::const_iterator i = ar_stats.begin();
|
|
i != ar_stats.end(); ++i)
|
|
std::cout << std::setw(25) << i->first << " |"
|
|
<< std::setw(6) << i->second.min_prefix
|
|
<< ' '
|
|
<< std::setw(8)
|
|
<< static_cast<float>(i->second.tot_prefix) / i->second.n
|
|
<< ' '
|
|
<< std::setw(6) << i->second.max_prefix
|
|
<< " |"
|
|
<< std::setw(6) << i->second.min_cycle
|
|
<< ' '
|
|
<< std::setw(8)
|
|
<< static_cast<float>(i->second.tot_cycle) / i->second.n
|
|
<< ' '
|
|
<< std::setw(6) << i->second.max_cycle
|
|
<< " |"
|
|
<< std::setw(4) << i->second.n
|
|
<< std::endl;
|
|
std::cout << std::setw(79) << std::setfill('-') << "" << std::setfill(' ')
|
|
<< std::endl
|
|
<< std::setw(25) << ""
|
|
<< " | runs | total |"
|
|
<< std::endl <<
|
|
std::setw(25) << "algorithm"
|
|
<< " | min < mean < max | pre. cyc. runs | n"
|
|
<< std::endl
|
|
<< std::setw(79) << std::setfill('-') << "" << std::setfill(' ')
|
|
<< std::endl;
|
|
for (ar_stats_type::const_iterator i = ar_stats.begin();
|
|
i != ar_stats.end(); ++i)
|
|
std::cout << std::setw(25) << i->first << " |"
|
|
<< std::setw(6)
|
|
<< i->second.min_run
|
|
<< ' '
|
|
<< std::setw(8)
|
|
<< static_cast<float>(i->second.tot_prefix
|
|
+ i->second.tot_cycle) / i->second.n
|
|
<< ' '
|
|
<< std::setw(6)
|
|
<< i->second.max_run
|
|
<< " |"
|
|
<< std::setw(6) << i->second.tot_prefix
|
|
<< ' '
|
|
<< std::setw(6) << i->second.tot_cycle
|
|
<< ' '
|
|
<< std::setw(8) << i->second.tot_prefix + i->second.tot_cycle
|
|
<< " |"
|
|
<< std::setw(4) << i->second.n
|
|
<< std::endl;
|
|
std::cout << std::setiosflags(old);
|
|
}
|
|
|
|
static spot::formula
|
|
generate_formula(const spot::random_ltl& rl,
|
|
spot::tl_simplifier& simp,
|
|
int opt_f, int opt_s,
|
|
int opt_l = 0, bool opt_u = false)
|
|
{
|
|
static std::set<std::string> unique;
|
|
|
|
int max_tries_u = 1000;
|
|
while (max_tries_u--)
|
|
{
|
|
spot::srand(opt_s++);
|
|
spot::formula f;
|
|
int max_tries_l = 1000;
|
|
while (max_tries_l--)
|
|
{
|
|
f = rl.generate(opt_f);
|
|
if (opt_l)
|
|
{
|
|
f = simp.simplify(f);
|
|
if (spot::length(f) < opt_l)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
assert(spot::length(f) <= opt_f);
|
|
}
|
|
break;
|
|
}
|
|
if (max_tries_l < 0)
|
|
{
|
|
assert(opt_l);
|
|
std::cerr << "Failed to generate non-reducible formula "
|
|
<< "of size " << opt_l << " or more." << std::endl;
|
|
return nullptr;
|
|
}
|
|
std::string txt = spot::str_psl(f);
|
|
if (!opt_u || unique.insert(txt).second)
|
|
return f;
|
|
}
|
|
assert(opt_u);
|
|
std::cerr << "Failed to generate another unique formula."
|
|
<< std::endl;
|
|
return nullptr;
|
|
}
|
|
|
|
int
|
|
main(int argc, char** argv)
|
|
{
|
|
bool opt_paper = false;
|
|
bool opt_dp = false;
|
|
int opt_f = 15;
|
|
int opt_F = 0;
|
|
char* opt_p = nullptr;
|
|
char* opt_i = nullptr;
|
|
std::istream *formula_file = nullptr;
|
|
int opt_l = 0;
|
|
bool opt_u = false;
|
|
int opt_S = 0;
|
|
|
|
int opt_n_acc = 0;
|
|
float opt_a = 0.0;
|
|
float opt_d = 0.2;
|
|
int opt_n = 20;
|
|
float opt_t = 0.5;
|
|
bool opt_det = false;
|
|
|
|
bool opt_0 = false;
|
|
bool opt_z = false;
|
|
bool opt_Z = false;
|
|
|
|
int opt_R = 0;
|
|
|
|
bool opt_dot = false;
|
|
int opt_ec = 0;
|
|
int opt_ec_seed = 0;
|
|
bool opt_reduce = false;
|
|
bool opt_replay = false;
|
|
bool opt_degen = false;
|
|
int argn = 0;
|
|
|
|
int exit_code = 0;
|
|
|
|
spot::twa_graph_ptr formula = nullptr;
|
|
spot::twa_graph_ptr product = nullptr;
|
|
|
|
spot::option_map options;
|
|
|
|
auto& env = spot::default_environment::instance();
|
|
spot::atomic_prop_set* ap = new spot::atomic_prop_set;
|
|
auto dict = spot::make_bdd_dict();
|
|
|
|
spot::tl_simplifier_options simpopt(true, true, true, true, true);
|
|
spot::tl_simplifier simp(simpopt);
|
|
|
|
if (argc <= 1)
|
|
syntax(argv[0]);
|
|
|
|
while (++argn < argc)
|
|
{
|
|
if (!strcmp(argv[argn], "-0"))
|
|
{
|
|
opt_0 = true;
|
|
}
|
|
else if (!strcmp(argv[argn], "-1"))
|
|
{
|
|
opt_paper = true;
|
|
opt_z = true;
|
|
}
|
|
else if (!strcmp(argv[argn], "-a"))
|
|
{
|
|
if (argc < argn + 3)
|
|
syntax(argv[0]);
|
|
opt_n_acc = to_int_nonneg(argv[++argn], "-a");
|
|
opt_a = to_float_nonneg(argv[++argn], "-a");
|
|
}
|
|
else if (!strcmp(argv[argn], "-A"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
if (!opt_ec)
|
|
opt_ec = 1;
|
|
std::istream* in;
|
|
if (strcmp(argv[++argn], "-"))
|
|
{
|
|
in = new std::ifstream(argv[argn]);
|
|
if (!*in)
|
|
{
|
|
delete in;
|
|
std::cerr << "Failed to open " << argv[argn] << std::endl;
|
|
exit(2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
in = &std::cin;
|
|
}
|
|
|
|
while (in->good())
|
|
{
|
|
std::string input;
|
|
if (std::getline(*in, input, '\n').fail())
|
|
break;
|
|
else if (input == "")
|
|
break;
|
|
ec_algo a = { input, nullptr };
|
|
ec_algos.push_back(a);
|
|
}
|
|
|
|
if (in != &std::cin)
|
|
delete in;
|
|
}
|
|
else if (!strncmp(argv[argn], "ar:", 3))
|
|
{
|
|
if (options.parse_options(argv[argn]))
|
|
{
|
|
std::cerr << "Failed to parse " << argv[argn] << std::endl;
|
|
exit(2);
|
|
}
|
|
}
|
|
else if (!strcmp(argv[argn], "-d"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_d = to_float_nonneg(argv[++argn], "-d");
|
|
}
|
|
else if (!strcmp(argv[argn], "-D"))
|
|
{
|
|
opt_degen = true;
|
|
if (!opt_ec)
|
|
opt_ec = 1;
|
|
}
|
|
else if (!strcmp(argv[argn], "-det"))
|
|
{
|
|
opt_det = true;
|
|
}
|
|
else if (!strcmp(argv[argn], "-e"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_ec = to_int_nonneg(argv[++argn], "-e");
|
|
}
|
|
else if (!strcmp(argv[argn], "-g"))
|
|
{
|
|
opt_dot = true;
|
|
}
|
|
else if (!strcmp(argv[argn], "-i"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_i = argv[++argn];
|
|
if (strcmp(opt_i, "-"))
|
|
{
|
|
formula_file = new std::ifstream(opt_i);
|
|
if (!*formula_file)
|
|
{
|
|
delete formula_file;
|
|
std::cerr << "Failed to open " << opt_i << std::endl;
|
|
exit(2);
|
|
}
|
|
}
|
|
else
|
|
formula_file = &std::cin;
|
|
}
|
|
else if (!strcmp(argv[argn], "-m"))
|
|
{
|
|
opt_reduce = true;
|
|
opt_replay = true;
|
|
if (!opt_ec)
|
|
opt_ec = 1;
|
|
}
|
|
else if (!strcmp(argv[argn], "-n"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_n = to_int_pos(argv[++argn], "-n");
|
|
}
|
|
else if (!strcmp(argv[argn], "-r"))
|
|
{
|
|
opt_replay = true;
|
|
if (!opt_ec)
|
|
opt_ec = 1;
|
|
}
|
|
else if (!strcmp(argv[argn], "-R"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_R = to_int_pos(argv[++argn], "-R");
|
|
}
|
|
else if (!strcmp(argv[argn], "-s"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_ec_seed = to_int_nonneg(argv[++argn], "-s");
|
|
spot::srand(opt_ec_seed);
|
|
}
|
|
else if (!strcmp(argv[argn], "-S"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_S = to_int_pos(argv[++argn], "-S");
|
|
}
|
|
else if (!strcmp(argv[argn], "-t"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_t = to_float_nonneg(argv[++argn], "-t");
|
|
}
|
|
else if (!strcmp(argv[argn], "-z"))
|
|
{
|
|
opt_z = true;
|
|
}
|
|
else if (!strcmp(argv[argn], "-Z"))
|
|
{
|
|
opt_Z = opt_z = true;
|
|
}
|
|
else if (!strcmp(argv[argn], "-dp"))
|
|
{
|
|
opt_dp = true;
|
|
}
|
|
else if (!strcmp(argv[argn], "-f"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_f = to_int_pos(argv[++argn], "-f");
|
|
}
|
|
else if (!strcmp(argv[argn], "-F"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_F = to_int_nonneg(argv[++argn], "-F");
|
|
}
|
|
else if (!strcmp(argv[argn], "-p"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_p = argv[++argn];
|
|
}
|
|
else if (!strcmp(argv[argn], "-l"))
|
|
{
|
|
if (argc < argn + 2)
|
|
syntax(argv[0]);
|
|
opt_l = to_int_nonneg(argv[++argn], "-l");
|
|
}
|
|
else if (!strcmp(argv[argn], "-u"))
|
|
{
|
|
opt_u = true;
|
|
}
|
|
else
|
|
{
|
|
ap->insert(env.require(argv[argn]));
|
|
}
|
|
}
|
|
|
|
spot::random_ltl rl(ap);
|
|
const char* tok = rl.parse_options(opt_p);
|
|
if (tok)
|
|
{
|
|
std::cerr << "failed to parse probabilities near `"
|
|
<< tok << '\'' << std::endl;
|
|
exit(2);
|
|
}
|
|
|
|
if (opt_l > opt_f)
|
|
{
|
|
std::cerr << "-l's argument (" << opt_l << ") should not be larger than "
|
|
<< "-f's (" << opt_f << ')' << std::endl;
|
|
exit(2);
|
|
}
|
|
|
|
if (opt_dp)
|
|
{
|
|
rl.dump_priorities(std::cout);
|
|
exit(0);
|
|
}
|
|
|
|
if (ec_algos.empty())
|
|
{
|
|
const char** i = default_algos;
|
|
while (*i)
|
|
{
|
|
ec_algo a = { *(i++), nullptr };
|
|
ec_algos.push_back(a);
|
|
}
|
|
}
|
|
|
|
spot::timer_map tm_ec;
|
|
spot::timer_map tm_ar;
|
|
std::set<int> failed_seeds;
|
|
int init_opt_ec = opt_ec;
|
|
spot::atomic_prop_set* apf = new spot::atomic_prop_set;
|
|
|
|
if (opt_ec)
|
|
{
|
|
for (unsigned i = 0; i < ec_algos.size(); ++i)
|
|
{
|
|
const char* err;
|
|
ec_algos[i].inst =
|
|
spot::make_emptiness_check_instantiator(ec_algos[i].name.c_str(),
|
|
&err);
|
|
if (!ec_algos[i].inst)
|
|
{
|
|
std::cerr << "Parse error after `" << err << '\'' << std::endl;
|
|
exit(1);
|
|
}
|
|
ec_algos[i].inst->options().set(options);
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
if (opt_F)
|
|
{
|
|
spot::formula f =
|
|
generate_formula(rl, simp, opt_f, opt_ec_seed, opt_l, opt_u);
|
|
if (!f)
|
|
exit(1);
|
|
formula = spot::ltl_to_tgba_fm(f, dict, true);
|
|
}
|
|
else if (opt_i)
|
|
{
|
|
if (formula_file->good())
|
|
{
|
|
std::string input;
|
|
if (std::getline(*formula_file, input, '\n').fail())
|
|
break;
|
|
else if (input == "")
|
|
break;
|
|
auto pf = spot::parse_infix_psl(input, env);
|
|
if (pf.format_errors(std::cerr))
|
|
{
|
|
exit_code = 1;
|
|
break;
|
|
}
|
|
formula = spot::ltl_to_tgba_fm(pf.f, dict, true);
|
|
auto* tmp = spot::atomic_prop_collect(pf.f);
|
|
for (auto i: *tmp)
|
|
apf->insert(i);
|
|
delete tmp;
|
|
}
|
|
else
|
|
{
|
|
if (formula_file->bad())
|
|
std::cerr << "Failed to read " << opt_i << std::endl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (auto i: *ap)
|
|
apf->insert(i);
|
|
|
|
if (!opt_S)
|
|
{
|
|
do
|
|
{
|
|
if (opt_ec && !opt_paper)
|
|
std::cout << "seed: " << opt_ec_seed << std::endl;
|
|
spot::srand(opt_ec_seed);
|
|
|
|
|
|
spot::twa_graph_ptr a =
|
|
spot::random_graph(opt_n, opt_d, apf, dict,
|
|
opt_n_acc, opt_a, opt_t, opt_det);
|
|
if (formula)
|
|
a = spot::product(formula, a);
|
|
|
|
int real_n_acc = a->acc().num_sets();
|
|
|
|
if (opt_dot)
|
|
{
|
|
print_dot(std::cout, a);
|
|
}
|
|
if (!opt_ec)
|
|
{
|
|
if (!opt_0 && !opt_dot)
|
|
print_hoa(std::cout, a, nullptr);
|
|
}
|
|
else
|
|
{
|
|
spot::twa_graph_ptr degen = nullptr;
|
|
if (opt_degen && real_n_acc > 1)
|
|
degen = degeneralize_tba(a);
|
|
|
|
int n_alg = ec_algos.size();
|
|
int n_ec = 0;
|
|
int n_empty = 0;
|
|
int n_non_empty = 0;
|
|
int n_maybe_empty = 0;
|
|
|
|
for (int i = 0; i < n_alg; ++i)
|
|
{
|
|
auto ec = cons_emptiness_check(i, a, degen, real_n_acc);
|
|
if (!ec)
|
|
continue;
|
|
++n_ec;
|
|
const std::string algo = ec_algos[i].name;
|
|
if (!opt_paper)
|
|
{
|
|
std::cout.width(32);
|
|
std::cout << algo << ": ";
|
|
}
|
|
tm_ec.start(algo);
|
|
spot::emptiness_check_result_ptr res;
|
|
for (int count = opt_R;;)
|
|
{
|
|
res = ec->check();
|
|
if (count-- <= 0)
|
|
break;
|
|
ec = cons_emptiness_check(i, a, degen, real_n_acc);
|
|
}
|
|
tm_ec.stop(algo);
|
|
auto ecs = ec->statistics();
|
|
if (opt_z && res)
|
|
{
|
|
// Notice that ratios are computed w.r.t. the
|
|
// generalized automaton a.
|
|
prod_stats = spot::stats_reachable(a);
|
|
}
|
|
else
|
|
{
|
|
// To trigger a division by 0 if used erroneously.
|
|
prod_stats.states = 0;
|
|
prod_stats.edges = 0;
|
|
}
|
|
|
|
if (opt_z && ecs)
|
|
{
|
|
sc_ec.count(algo, ecs);
|
|
if (res)
|
|
{
|
|
ec_ratio_stats[real_n_acc].count(algo, ecs);
|
|
glob_ec_ratio_stats.count(algo, ecs);
|
|
}
|
|
}
|
|
|
|
if (res)
|
|
{
|
|
if (!opt_paper)
|
|
std::cout << "acc. run";
|
|
++n_non_empty;
|
|
if (opt_replay)
|
|
{
|
|
spot::twa_run_ptr run;
|
|
tm_ar.start(algo);
|
|
for (int count = opt_R;;)
|
|
{
|
|
run = res->accepting_run();
|
|
if (count-- <= 0 || !run)
|
|
break;
|
|
}
|
|
if (!run)
|
|
tm_ar.cancel(algo);
|
|
else
|
|
tm_ar.stop(algo);
|
|
|
|
const spot::unsigned_statistics* s
|
|
= res->statistics();
|
|
if (opt_z)
|
|
{
|
|
// Count only the last run (the
|
|
// other way would be to divide
|
|
// the stats by opt_R).
|
|
sc_arc.count(algo, s);
|
|
arc_ratio_stats.count(algo, s);
|
|
}
|
|
if (!run)
|
|
{
|
|
if (!opt_paper)
|
|
std::cout << " exists, not computed";
|
|
}
|
|
else
|
|
{
|
|
std::ostringstream s;
|
|
if (!run->replay(s))
|
|
{
|
|
if (!opt_paper)
|
|
std::cout << ", but could not replay "
|
|
<< "it (ERROR!)";
|
|
failed_seeds.insert(opt_ec_seed);
|
|
}
|
|
else
|
|
{
|
|
if (!opt_paper)
|
|
std::cout << ", computed";
|
|
if (opt_z)
|
|
ar_stats[algo].count(run);
|
|
}
|
|
if (opt_z && !opt_paper)
|
|
std::cout << " [" << run->prefix.size()
|
|
<< '+' << run->cycle.size()
|
|
<< ']';
|
|
|
|
if (opt_reduce)
|
|
{
|
|
auto redrun = run->reduce();
|
|
if (!redrun->replay(s))
|
|
{
|
|
if (!opt_paper)
|
|
std::cout
|
|
<< ", but could not replay "
|
|
<< "its minimization (ERROR!)";
|
|
failed_seeds.insert(opt_ec_seed);
|
|
}
|
|
else
|
|
{
|
|
if (!opt_paper)
|
|
std::cout << ", reduced";
|
|
if (opt_z)
|
|
mar_stats[algo].count(redrun);
|
|
}
|
|
if (opt_z && !opt_paper)
|
|
{
|
|
std::cout << " ["
|
|
<< redrun->prefix.size()
|
|
<< '+'
|
|
<< redrun->cycle.size()
|
|
<< ']';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!opt_paper)
|
|
std::cout << std::endl;
|
|
}
|
|
else
|
|
{
|
|
if (ec->safe())
|
|
{
|
|
if (!opt_paper)
|
|
std::cout << "empty language" << std::endl;
|
|
++n_empty;
|
|
}
|
|
else
|
|
{
|
|
if (!opt_paper)
|
|
std::cout << "maybe empty language"
|
|
<< std::endl;
|
|
++n_maybe_empty;
|
|
}
|
|
|
|
}
|
|
|
|
if (opt_Z && !opt_paper)
|
|
ec->print_stats(std::cout);
|
|
}
|
|
|
|
assert(n_empty + n_non_empty + n_maybe_empty == n_ec);
|
|
|
|
if ((n_empty == 0 && (n_non_empty + n_maybe_empty) != n_ec)
|
|
|| (n_empty != 0 && n_non_empty != 0))
|
|
{
|
|
std::cout << "ERROR: not all algorithms agree"
|
|
<< std::endl;
|
|
failed_seeds.insert(opt_ec_seed);
|
|
}
|
|
}
|
|
|
|
if (opt_ec)
|
|
{
|
|
--opt_ec;
|
|
++opt_ec_seed;
|
|
}
|
|
}
|
|
while (opt_ec);
|
|
}
|
|
else
|
|
{
|
|
--opt_S;
|
|
opt_ec_seed += init_opt_ec;
|
|
}
|
|
|
|
if (opt_F)
|
|
--opt_F;
|
|
opt_ec = init_opt_ec;
|
|
apf->clear();
|
|
}
|
|
while (opt_F || opt_i);
|
|
|
|
if (!opt_paper && opt_z)
|
|
{
|
|
if (!sc_ec.empty())
|
|
{
|
|
std::cout << std::endl
|
|
<< "Statistics about emptiness checks:"
|
|
<< std::endl;
|
|
sc_ec.display(std::cout);
|
|
}
|
|
if (!sc_arc.empty())
|
|
{
|
|
std::cout << std::endl
|
|
<< "Statistics about accepting run computations:"
|
|
<< std::endl;
|
|
sc_arc.display(std::cout);
|
|
}
|
|
if (!glob_ec_ratio_stats.empty())
|
|
{
|
|
std::cout << std::endl
|
|
<< "Emptiness check ratios for non-empty automata:"
|
|
<< std::endl << "all tests"
|
|
<< std::endl;
|
|
glob_ec_ratio_stats.display(std::cout, false);
|
|
if (ec_ratio_stats.size() > 1)
|
|
for (ec_ratio_stats_type::const_iterator i = ec_ratio_stats.begin();
|
|
i != ec_ratio_stats.end(); ++i)
|
|
{
|
|
std::cout << "tests with " << i->first
|
|
<< " acceptance conditions"
|
|
<< std::endl;
|
|
i->second.display(std::cout, false);
|
|
}
|
|
}
|
|
if (!ar_stats.empty())
|
|
print_ar_stats(ar_stats, "Statistics about accepting runs:");
|
|
if (!mar_stats.empty())
|
|
print_ar_stats(mar_stats, "Statistics about reduced accepting runs:");
|
|
if (!arc_ratio_stats.empty())
|
|
{
|
|
std::cout << std::endl
|
|
<< "Accepting run ratios:" << std::endl;
|
|
arc_ratio_stats.display(std::cout, false);
|
|
}
|
|
if (!tm_ec.empty())
|
|
{
|
|
std::cout << std::endl
|
|
<< "emptiness checks cumulated timings:" << std::endl;
|
|
tm_ec.print(std::cout);
|
|
}
|
|
if (!tm_ar.empty())
|
|
{
|
|
std::cout << std::endl
|
|
<< "accepting runs cumulated timings:" << std::endl;
|
|
tm_ar.print(std::cout);
|
|
}
|
|
}
|
|
else if (opt_paper)
|
|
{
|
|
std::cout << "Emptiness check ratios" << std::endl;
|
|
std::cout << std::right << std::fixed << std::setprecision(1);
|
|
ec_ratio_stat_type::stats_alg_map& stats = glob_ec_ratio_stats.stats;
|
|
typedef ec_ratio_stat_type::alg_1stat_map::const_iterator ec_iter;
|
|
|
|
for (unsigned ai = 0; ai < ec_algos.size(); ++ai)
|
|
{
|
|
const std::string algo = ec_algos[ai].name;
|
|
|
|
int n = -1;
|
|
|
|
std::cout << std::setw(25) << algo << ' ' << std::setw(8);
|
|
|
|
ec_iter i = stats["states"].find(algo);
|
|
if (i != stats["states"].end())
|
|
{
|
|
std::cout << i->second.tot / i->second.n;
|
|
n = i->second.n;
|
|
}
|
|
else
|
|
std::cout << "";
|
|
std::cout << ' ' << std::setw(8);
|
|
|
|
i = stats["transitions"].find(algo);
|
|
if (i != stats["transitions"].end())
|
|
{
|
|
std::cout << i->second.tot / i->second.n;
|
|
n = i->second.n;
|
|
}
|
|
else
|
|
std::cout << "";
|
|
std::cout << ' ' << std::setw(8);
|
|
|
|
i = stats["max. depth"].find(algo);
|
|
if (i != stats["max. depth"].end())
|
|
{
|
|
std::cout << i->second.tot / i->second.n;
|
|
n = i->second.n;
|
|
}
|
|
else
|
|
std::cout << "";
|
|
if (n >= 0)
|
|
std::cout << ' ' << std::setw(8) << n;
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
std::cout << std::endl << "Accepting run ratios" << std::endl;
|
|
std::cout << std::right << std::fixed << std::setprecision(1);
|
|
ec_ratio_stat_type::stats_alg_map& stats2 = arc_ratio_stats.stats;
|
|
|
|
for (unsigned ai = 0; ai < ec_algos.size(); ++ai)
|
|
{
|
|
const std::string algo = ec_algos[ai].name;
|
|
|
|
std::cout << std::setw(25) << algo << ' ' << std::setw(8);
|
|
|
|
ec_iter i = stats2["search space states"].find(algo);
|
|
if (i != stats2["search space states"].end())
|
|
std::cout << i->second.tot / i->second.n;
|
|
else
|
|
std::cout << "";
|
|
std::cout << ' ' << std::setw(8);
|
|
|
|
i = stats2["(non unique) states for cycle"].find(algo);
|
|
if (i != stats2["(non unique) states for cycle"].end())
|
|
std::cout << i->second.tot / i->second.n;
|
|
else
|
|
std::cout << "";
|
|
std::cout << std::endl;
|
|
}
|
|
}
|
|
|
|
if (!failed_seeds.empty())
|
|
{
|
|
exit_code = 1;
|
|
std::cout << "The check failed for the following seeds:";
|
|
for (std::set<int>::const_iterator i = failed_seeds.begin();
|
|
i != failed_seeds.end(); ++i)
|
|
std::cout << ' ' << *i;
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
if (opt_i && strcmp(opt_i, "-"))
|
|
{
|
|
dynamic_cast<std::ifstream*>(formula_file)->close();
|
|
delete formula_file;
|
|
}
|
|
|
|
delete ap;
|
|
delete apf;
|
|
return exit_code;
|
|
}
|