Commit f831f729 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

homogenize dstar_parse() and parse_aut() outputs

* src/dstarparse/dstarparse.yy, src/dstarparse/dstarscan.ll
src/dstarparse/parsedecl.hh, src/dstarparse/public.hh:
Adjust to return the same return types as parse_aut.
* src/dstarparse/fmterror.cc: Delete, we can use
the one of parse_aut.
* src/dstarparse/Makefile.am: Adjust.
* src/tests/ikwiad.cc, src/bin/dstar2tgba.cc,
src/bin/ltldo.cc: Adjust usage.
* src/bin/ltlcross.cc: The the result of dstar_parse() as-is, now that
it is a TωA like those produced by parse_aut().  As a consequence,
get rid of all the code storing statistics about the input
automaton.
* src/tests/ltlcross3.test, src/tests/ltl2dstar.test: Adjust expected
CSV output.
* doc/org/ltlcross.org, src/bin/man/ltlcross.x: Adjust to not
mention that %D performs a tranformation to Büchi.
parent 62f5b976
......@@ -145,10 +145,8 @@ tools:
--output-format=hoa %L %O~' deterministic Streett output in HOA,
as supported since version 0.5.2 of =ltl2dstar=.
- '=ltl2dstar --ltl2nba=spin:path/to/ltl2tgba@-sD %L %D=' (Rabin
output in DSTAR format, as supported in older version of
=ltl2dstar=. Note that when reading this format, =ltl2dstar=
automatically converts the Rabin automaton into a Büchi automaton
for historical reason.)
output in DSTAR format, as supported in older versions of
=ltl2dstar=.
- '=ltl2dstar --ltl2nba=spin:path/to/ltl2tgba@-sD %L - | dstar2tgba
-s >%O=' (external conversion from Rabin to Büchi done by
=dstar2tgba= for more reduction of the Büchi automaton than what
......@@ -420,20 +418,6 @@ All the values that follow will be missing if =exit_status= is not
equal to "=ok=". (You may instruct =ltlcross= not to output lines with
such missing data with the option =--omit-missing=.)
The columns =in_type=, =in_states=, =in_edges=, =in_transitions=,
=in_acc=, and =in_scc= are only output if one of the translator
produces Rabin or Streett automata in =ltl2dstar='s format (i.e., if
=%D= is used to specify one output filename for any translator). In
that case these columns give the type (DRA or DSA) of the produced
automaton, as well as its size (states, edges, transitions, number of
acceptance pairs, and number of SCCs). This input automaton is then
converted by =ltlcross= into a TGBA before being checked the result of
other translators, and all the following columns are measures of that
converted automaton. This conversion to TGBA is historical. When the
automata are produced in the HOA format (i.e., not in =ltl2dstar='s
format) then no conversion occur, and =ltlcross= works directly with
the given acceptance condition.
=states=, =edges=, =transitions=, =acc= are size measures for the
automaton that was translated. =acc= counts the number of acceptance
sets. When building (degeneralized) Büchi automata, it will always be
......@@ -647,9 +631,9 @@ positive and negative formulas by the ith translator).
coverage. Using '=ltl2tgba -lD %f >%O=' will produce
deterministic automata for all obligation properties and many
recurrence properties. Using '=ltl2dstar
--ltl2nba=spin:pathto/ltl2tgba@-sD %L %D=' is more expansive, but
it will produce a deterministic Büchi automaton whenever one
exists.
--ltl2nba=spin:pathto/ltl2tgba@-Ds %L %D=' will systematically
produce a deterministic Rabin automaton (that =ltlcross= can
complement easily).
- Cross-comparison checks: for some state-space $S$,
all $P_i\otimes S$ are either all empty, or all non-empty.
......
......@@ -266,7 +266,7 @@ namespace
/// The \a f argument is not needed if the Formula does not need
/// to be output.
std::ostream&
print(const spot::const_dstar_aut_ptr& daut,
print(const spot::const_parsed_aut_ptr& daut,
const spot::const_twa_graph_ptr& aut,
const char* filename, double run_time)
{
......@@ -347,9 +347,9 @@ namespace
int
process_file(const char* filename)
{
spot::dstar_parse_error_list pel;
spot::parse_aut_error_list pel;
auto daut = spot::dstar_parse(filename, pel, spot::make_bdd_dict());
if (spot::format_dstar_parse_errors(std::cerr, filename, pel))
if (spot::format_parse_aut_errors(std::cerr, filename, pel))
return 2;
if (!daut)
error(2, 0, "failed to read automaton from %s", filename);
......
......@@ -199,7 +199,6 @@ static int seed = 0;
static unsigned products = 1;
static bool products_avg = true;
static bool opt_omit = false;
static bool has_sr = false; // Has Streett or Rabin automata to process.
static const char* bogus_output_filename = 0;
static output_file* bogus_output = 0;
static output_file* grind_output = 0;
......@@ -240,16 +239,9 @@ struct statistics
{
statistics()
: ok(false),
has_in(false),
status_str(0),
status_code(0),
time(0),
in_type(0),
in_states(0),
in_edges(0),
in_transitions(0),
in_acc(0),
in_scc(0),
states(0),
edges(0),
transitions(0),
......@@ -270,17 +262,9 @@ struct statistics
// If OK is false, only the status_str, status_code, and time fields
// should be valid.
bool ok;
// has in_* data to display.
bool has_in;
const char* status_str;
int status_code;
double time;
const char* in_type;
unsigned in_states;
unsigned in_edges;
unsigned in_transitions;
unsigned in_acc;
unsigned in_scc;
unsigned states;
unsigned edges;
unsigned transitions;
......@@ -303,15 +287,12 @@ struct statistics
std::string hoa_str;
static void
fields(std::ostream& os, bool show_exit, bool show_sr)
fields(std::ostream& os, bool show_exit)
{
if (show_exit)
os << "\"exit_status\",\"exit_code\",";
os << "\"time\",";
if (show_sr)
os << ("\"in_type\",\"in_states\",\"in_edges\",\"in_transitions\","
"\"in_acc\",\"in_scc\",");
os << ("\"states\","
os << ("\"time\","
"\"states\","
"\"edges\","
"\"transitions\","
"\"acc\","
......@@ -335,7 +316,7 @@ struct statistics
}
void
to_csv(std::ostream& os, bool show_exit, bool show_sr, const char* na = "",
to_csv(std::ostream& os, bool show_exit, const char* na = "",
bool csv_escape = true)
{
if (show_exit)
......@@ -343,16 +324,6 @@ struct statistics
os << time << ',';
if (ok)
{
if (has_in)
os << '"' << in_type << "\","
<< in_states << ','
<< in_edges << ','
<< in_transitions << ','
<< in_acc << ','
<< in_scc << ',';
else if (show_sr)
os << na << ',' << na << ',' << na << ','
<< na << ',' << na << ',' << na << ',';
os << states << ','
<< edges << ','
<< transitions << ','
......@@ -396,7 +367,7 @@ struct statistics
{
size_t m = products_avg ? 1U : products;
m *= 3;
m += 15 + show_sr * 6;
m += 15;
os << na;
for (size_t i = 0; i < m; ++i)
os << ',' << na;
......@@ -509,7 +480,6 @@ namespace
xtranslator_runner(spot::bdd_dict_ptr dict)
: translator_runner(dict)
{
has_sr = has('D');
}
spot::twa_graph_ptr
......@@ -580,7 +550,7 @@ namespace
{
case printable_result_filename::Dstar:
{
spot::dstar_parse_error_list pel;
spot::parse_aut_error_list pel;
std::string filename = output.val()->name();
auto aut = spot::dstar_parse(filename, pel, dict);
if (!pel.empty())
......@@ -591,43 +561,13 @@ namespace
std::ostream& err = global_error();
err << "error: failed to parse the produced DSTAR"
" output.\n";
spot::format_dstar_parse_errors(err, filename, pel);
spot::format_parse_aut_errors(err, filename, pel);
end_error();
res = nullptr;
}
else
{
const char* type = 0;
switch (aut->type)
{
case spot::Rabin:
type = "DRA";
break;
case spot::Streett:
type = "DSA";
break;
}
assert(type);
// Gather statistics about the input automaton
if (want_stats)
{
statistics* st = &(*fstats)[translator_num];
st->has_in = true;
st->in_type = type;
spot::tgba_sub_statistics s =
sub_stats_reachable(aut->aut);
st->in_states= s.states;
st->in_edges = s.transitions;
st->in_transitions = s.sub_transitions;
st->in_acc = aut->aut->num_sets() / 2;
st->in_scc = spot::scc_info(aut->aut).scc_count();
}
// convert it into TGBA for further processing
if (verbose)
std::cerr << "info: converting " << type << " to TGBA\n";
res = remove_fin(aut->aut);
res = aut->aut;
}
break;
}
......@@ -1407,7 +1347,7 @@ print_stats_csv(const char* filename)
// Do not output the header line if we append to a file.
// (Even if that file was empty initially.)
out << "\"formula\",\"tool\",";
statistics::fields(out, !opt_omit, has_sr);
statistics::fields(out, !opt_omit);
out << '\n';
}
for (unsigned r = 0; r < rounds; ++r)
......@@ -1419,7 +1359,7 @@ print_stats_csv(const char* filename)
out << "\",\"";
spot::escape_rfc4180(out, translators[t].name);
out << "\",";
vstats[r][t].to_csv(out, !opt_omit, has_sr);
vstats[r][t].to_csv(out, !opt_omit);
out << '\n';
}
}
......@@ -1452,7 +1392,7 @@ print_stats_json(const char* filename)
spot::escape_str(out, formulas[r]);
}
out << ("\"\n ],\n \"fields\": [\n \"formula\",\"tool\",");
statistics::fields(out, !opt_omit, has_sr);
statistics::fields(out, !opt_omit);
out << "\n ],\n \"inputs\": [ 0, 1 ],";
out << "\n \"results\": [";
bool notfirst = false;
......@@ -1464,7 +1404,7 @@ print_stats_json(const char* filename)
out << ',';
notfirst = true;
out << "\n [ " << r << ',' << t << ',';
vstats[r][t].to_csv(out, !opt_omit, has_sr, "null", false);
vstats[r][t].to_csv(out, !opt_omit, "null", false);
out << " ]";
}
out << "\n ]\n}\n";
......
......@@ -173,7 +173,7 @@ namespace
{
case printable_result_filename::Dstar:
{
spot::dstar_parse_error_list pel;
spot::parse_aut_error_list pel;
std::string filename = output.val()->name();
auto aut = spot::dstar_parse(filename, pel, dict);
if (!pel.empty())
......@@ -181,7 +181,7 @@ namespace
problem = true;
std::cerr << "error: failed to parse the output of \""
<< cmd << "\" as a DSTAR automaton.\n";
spot::format_dstar_parse_errors(std::cerr, filename, pel);
spot::format_parse_aut_errors(std::cerr, filename, pel);
res = nullptr;
}
else
......
......@@ -50,38 +50,31 @@ distinguish and understand these three formats.
.PP
Rabin or Streett automata output by
.B ltl2dstar
can be read from a
in its historical format can be read from a
file specified with \f(CW%D\fR instead of \f(CW%O\fR. For instance:
.PP
.in +4n
.nf
.ft C
% ltlcross \-F input.ltl \e
'ltl2dstar \-\-ltl2nba=spin:ltl2tgba@\-s %L %D' \e
'ltl2dstar \-\-automata=streett \-\-ltl2nba=spin:ltl2tgba@\-s %L %D' \e
'ltl2dstar \-\-ltl2nba=spin:ltl2tgba@\-Ds %L %D' \e
'ltl2dstar \-\-automata=streett \-\-ltl2nba=spin:ltl2tgba@\-Ds %L %D' \e
.fi
.PP
However, for historical reasons these Rabin and
Streett automata are immediately converted to TGBA before further
processing by
.BR ltlcross .
This is still interesting to search for bugs
in translators to Rabin or Streett automata, but the statistics might
not be very relevant. If statistics matters to you and you do not want
this conversion to occur, use the HOA format to interface with ltl2dstar:
However, we now recommand to use the HOA output of
.BR ltl2dstar ,
as supported since version 0.5.2:
.PP
.in +4n
.nf
.ft C
% ltlcross \-F input.ltl \e
'ltl2dstar \-\-output\-format=hoa \-\-ltl2nba=spin:ltl2tgba@\-s %L %O' \e
'ltl2dstar \-\-output\-format=hoa \-\-automata=streett \-\-ltl2nba=spin:ltl2tgba@\-s %L %O' \e
'ltl2dstar \-\-output\-format=hoa \-\-ltl2nba=spin:ltl2tgba@\-Ds %L %O' \e
'ltl2dstar \-\-output\-format=hoa \-\-automata=streett \-\-ltl2nba=spin:ltl2tgba@\-Ds %L %O' \e
.fi
.PP
If you use ltlcross in an automated testsuite just to check for
potential problems, avoid the \fB\-\-csv\fR and \fB\-\-json\fR
options: ltlcross is faster when it does not have to compute these
statistics.
In more recent versions of ltl2dstar, \fB\-\-output\-format=hoa\fR can
be abbreviated \fB-H\fR.
[ENVIRONMENT VARIABLES]
.TP
......@@ -151,16 +144,6 @@ This is reported for all executions, even failling ones.
Unless the \fB\-\-omit\-missing\fR option is used, data for all the
following columns might be missing.
.TP
\fBin_type\fR, \fBin_states\fR, \fBin_edges\fR, \fBin_transitions\fR,
\fBin_acc\fR , \fBin_scc\fR These columns are only output if
\f(CW%D\fR appears in any command specification, i.e., if any of the
tools output some Streett or Rabin automata. In this case
\fBin_type\fR contains a string that is either \f(CWDRA\fR
(Deterministic Rabin Automaton) or \f(CWDSA\fR (Deterministic Streett
Automaton). The other columns respectively give the number of states,
edges, transitions, acceptance pairs, and strongly connected
components in that automaton.
.TP
\fBstates\fR, \fBedges\fR, \fBtransitions\fR, \fBacc\fR
The number of states, edges, transitions, and acceptance sets in the
translated automaton. Column \fBedges\fR counts the number of edges
......
......@@ -51,7 +51,6 @@ $(FROM_DSTARPARSE_YY_OTHERS): $(DSTARPARSE_YY)
EXTRA_DIST = $(DSTARPARSE_YY)
libdstarparse_la_SOURCES = \
fmterror.cc \
$(FROM_DSTARPARSE_YY) \
dstarscan.ll \
parsedecl.hh
......@@ -24,7 +24,7 @@
%name-prefix "dstaryy"
%debug
%error-verbose
%lex-param { spot::dstar_parse_error_list& error_list }
%lex-param { spot::parse_aut_error_list& error_list }
%define api.location.type "spot::location"
%code requires
......@@ -38,9 +38,12 @@
{
typedef std::map<int, bdd> map_t;
enum dstar_type { Rabin, Streett };
struct result_
{
spot::dstar_aut_ptr d;
spot::parsed_aut_ptr d;
dstar_type type;
spot::ltl::environment* env;
std::vector<bdd> guards;
std::vector<bdd>::const_iterator cur_guard;
......@@ -70,7 +73,7 @@
}
}
%parse-param {spot::dstar_parse_error_list& error_list}
%parse-param {spot::parse_aut_error_list& error_list}
%parse-param {result_& result}
%union
{
......@@ -118,19 +121,20 @@
%%
dstar: header ENDOFHEADER eols states
{ result.d->loc = @$; }
eols : EOL | eols EOL
opt_eols: | opt_eols EOL
auttype: DRA
{
result.d->type = spot::Rabin;
result.type = Rabin;
result.plus = 1;
result.minus = 0;
}
| DSA
{
result.d->type = spot::Streett;
result.type = Streett;
result.plus = 0;
result.minus = 1;
}
......@@ -185,7 +189,7 @@ sizes:
result.accpair_count = $4;
result.accpair_count_seen = true;
result.d->aut->set_acceptance(2 * $4,
result.d->type == spot::Rabin ?
result.type == Rabin ?
spot::acc_cond::acc_code::rabin($4) :
spot::acc_cond::acc_code::streett($4));
}
......@@ -332,9 +336,9 @@ dstaryy::parser::error(const location_type& location,
namespace spot
{
dstar_aut_ptr
parsed_aut_ptr
dstar_parse(const std::string& name,
dstar_parse_error_list& error_list,
parse_aut_error_list& error_list,
const bdd_dict_ptr& dict,
ltl::environment& env,
bool debug)
......@@ -343,10 +347,10 @@ namespace spot
{
error_list.emplace_back(spot::location(),
std::string("Cannot open file ") + name);
return 0;
return nullptr;
}
result_ r;
r.d = std::make_shared<spot::dstar_aut>();
r.d = std::make_shared<spot::parsed_aut>();
r.d->aut = make_twa_graph(dict);
r.d->aut->prop_deterministic(true);
r.d->aut->prop_state_based_acc(true);
......@@ -355,9 +359,6 @@ namespace spot
parser.set_debug_level(debug);
parser.parse();
dstaryyclose();
if (!r.d->aut)
return nullptr;
return r.d;
}
}
......
......@@ -72,7 +72,7 @@ eol2 (\n\r)+|(\r\n)+
if (errno || yylval->num != n)
{
error_list.push_back(
spot::dstar_parse_error(*yylloc,
spot::parse_aut_error(*yylloc,
"value too large"));
yylval->num = 0;
}
......@@ -88,7 +88,7 @@ eol2 (\n\r)+|(\r\n)+
"*"+"/" BEGIN(INITIAL);
<<EOF>> {
error_list.push_back(
spot::dstar_parse_error(*yylloc,
spot::parse_aut_error(*yylloc,
"unclosed comment"));
return 0;
}
......@@ -105,7 +105,7 @@ eol2 (\n\r)+|(\r\n)+
[^\\\"]+ s.append(yytext, yyleng);
<<EOF>> {
error_list.push_back(
spot::dstar_parse_error(*yylloc,
spot::parse_aut_error(*yylloc,
"unclosed string"));
return 0;
}
......
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014 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 <ostream>
#include "public.hh"
namespace spot
{
bool
format_dstar_parse_errors(std::ostream& os,
const std::string& filename,
dstar_parse_error_list& error_list)
{
bool printed = false;
spot::dstar_parse_error_list::iterator it;
for (it = error_list.begin(); it != error_list.end(); ++it)
{
if (filename != "-")
os << filename << ':';
os << it->first << ": ";
os << it->second << std::endl;
printed = true;
}
return printed;
}
}
// -*- coding: utf-8 -*-
// Copyright (C) 2013 Laboratoire de Recherche et Développement
// Copyright (C) 2013, 2015 Laboratoire de Recherche et Développement
// de l'EPITA.
//
// This file is part of Spot, a model checking library.
......@@ -22,11 +22,12 @@
#include <string>
#include "dstarparse.hh"
#include "misc/location.hh"
#include "parseaut/public.hh"
# define YY_DECL \
int dstaryylex(dstaryy::parser::semantic_type *yylval, \
spot::location *yylloc, \
spot::dstar_parse_error_list& error_list)
spot::parse_aut_error_list& error_list)
YY_DECL;
namespace spot
......
......@@ -22,6 +22,7 @@
#include "twa/twagraph.hh"
#include "misc/location.hh"
#include "ltlenv/defaultenv.hh"
#include "parseaut/public.hh"
#include <string>
#include <list>
#include <utility>
......@@ -32,28 +33,7 @@ namespace spot
/// \addtogroup twa_io
/// @{
/// \brief A parse diagnostic with its location.
typedef std::pair<spot::location, std::string> dstar_parse_error;
/// \brief A list of parser diagnostics, as filled by parse.
typedef std::list<dstar_parse_error> dstar_parse_error_list;
enum dstar_type { Rabin, Streett };
/// \brief Temporary encoding of an omega automaton produced by
/// ltl2dstar.
struct SPOT_API dstar_aut
{
// Transition structure of the automaton.
// This is encoded as a TGBA without acceptance condition.
twa_graph_ptr aut;
/// Type of the acceptance.
dstar_type type;
};
typedef std::shared_ptr<dstar_aut> dstar_aut_ptr;
typedef std::shared_ptr<const dstar_aut> const_dstar_aut_ptr;
/// \brief Build a spot::twa_graph from ltl2dstar's output.
/// \brief Build a spot::twa_graph_ptr from ltl2dstar's output.
/// \param filename The name of the file to parse.
/// \param error_list A list that will be filled with
/// parse errors that occured during parsing.
......@@ -70,22 +50,12 @@ namespace spot
/// was parsed succesfully, check \a error_list for emptiness.
///
/// \warning This function is not reentrant.
SPOT_API dstar_aut_ptr
SPOT_API parsed_aut_ptr
dstar_parse(const std::string& filename,
dstar_parse_error_list& error_list,
parse_aut_error_list& error_list,
const bdd_dict_ptr& dict,
ltl::environment& env = ltl::default_environment::instance(),
bool debug = false);
/// \brief Format diagnostics produced by spot::dstar_parse.
/// \param os Where diagnostics should be output.
/// \param filename The filename that should appear in the diagnostics.
/// \param error_list The error list filled by spot::ltl::parse while
/// parsing \a ltl_string.
/// \return \c true iff any diagnostic was output.
SPOT_API bool
format_dstar_parse_errors(std::ostream& os,
const std::string& filename,
dstar_parse_error_list& error_list);
/// @}
}
......@@ -598,7 +598,7 @@ checked_main(int argc, char** argv)
{
tm.start("reading -P's argument");
spot::dstar_parse_error_list pel;
spot::parse_aut_error_list pel;
auto daut = spot::parse_aut(argv[formula_index] + 2, pel,
dict, env, debug_opt);
if (spot::format_parse_aut_errors(std::cerr,
......@@ -961,11 +961,11 @@ checked_main(int argc, char** argv)
{
case ReadDstar:
{
spot::dstar_parse_error_list pel;
spot::parse_aut_error_list pel;
tm.start("parsing dstar");
auto daut = spot::dstar_parse(input, pel, dict, env, debug_opt);
tm.stop("parsing dstar");
if (spot::format_dstar_parse_errors(std::cerr, input, pel))
if (spot::format_parse_aut_errors(std::cerr, input, pel))
return 2;
tm.start("dstar2tgba");
if (nra2nba)
......@@ -984,7 +984,7 @@ checked_main(int argc, char** argv)
break;
case ReadHoa:
{
spot::dstar_parse_error_list pel;
spot::parse_aut_error_list pel;
tm.start("parsing hoa");
auto daut = spot::parse_aut(input, pel, dict, env, debug_opt);
tm.stop("parsing hoa");
......
......@@ -57,12 +57,6 @@ $ltlcross -F - -f 'GFa & GFb & GFc' -f '(GFa -> GFb) & (GFc -> GFd)' \
"ltl2dstar $STR --ltl2nba=spin:$ltl2tgba@-s %L - | $dstar2tgba --low -s >%N" \
--csv=out.csv