bin: allow %l to be used to print serial numbers

* NEWS: Mention it.
* bin/autfilt.cc, bin/common_aoutput.cc, bin/common_aoutput.hh,
bin/common_output.cc, bin/common_output.hh, bin/dstar2tgba.cc,
bin/genaut.cc, bin/genltl.cc, bin/ltl2tgba.cc, bin/ltldo.cc,
bin/ltlfilt.cc, bin/ltlgrind.cc, bin/randaut.cc, bin/randltl.cc:
Implement it.
* doc/org/oaut.org: Add a short example.
* tests/core/serial.test: New file.
* tests/Makefile.am: Add it.
This commit is contained in:
Alexandre Duret-Lutz 2023-07-21 17:06:01 +02:00
parent 8369663380
commit 61b457a37e
18 changed files with 183 additions and 41 deletions

12
NEWS
View file

@ -1,5 +1,17 @@
New in spot 2.11.5.dev (not yet released) New in spot 2.11.5.dev (not yet released)
Command-line tools:
- In places that accept format strings with '%' sequences, like
options --stats, --name, or --output, the new '%l' can now be used
to produce the 0-based serial number of the produced object. This
differs from the existing '%L' that is usually related to the line
number of the input (when that makes sense). For instance to
split a file that contains many automaton into several files, one
per automata, do
autfilt input.hoa -o output-%l.hoa
Library: Library:
- The following new trivial simplifications have been implemented for SEREs: - The following new trivial simplifications have been implemented for SEREs:

View file

@ -1680,8 +1680,6 @@ namespace
return 0; return 0;
} }
++match_count;
if (aliases) if (aliases)
{ {
if (opt_aliases) if (opt_aliases)
@ -1690,7 +1688,9 @@ namespace
set_aliases(aut, {}); set_aliases(aut, {});
} }
printer.print(aut, timer, nullptr, haut->filename.c_str(), -1, printer.print(aut, timer, nullptr, haut->filename.c_str(), -1,
haut, prefix, suffix); match_count, haut, prefix, suffix);
++match_count;
if (opt_max_count >= 0 && match_count >= opt_max_count) if (opt_max_count >= 0 && match_count >= opt_max_count)
abort_run = true; abort_run = true;

View file

@ -198,6 +198,8 @@ static const argp_option io_options[] =
" minuscules for output):", 4 }, " minuscules for output):", 4 },
{ "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, F_doc, 0 }, { "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, F_doc, 0 },
{ "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, L_doc, 0 }, { "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, L_doc, 0 },
{ "%l", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"serial number of the output automaton (0-based)", 0 },
{ "%H, %h", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%H, %h", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the automaton in HOA format on a single line (use %[opt]H or %[opt]h " "the automaton in HOA format on a single line (use %[opt]H or %[opt]h "
"to specify additional options as in --hoa=opt)", 0 }, "to specify additional options as in --hoa=opt)", 0 },
@ -269,6 +271,8 @@ static const argp_option o_options[] =
"the following interpreted sequences:", 4 }, "the following interpreted sequences:", 4 },
{ "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, F_doc, 0 }, { "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, F_doc, 0 },
{ "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, L_doc, 0 }, { "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, L_doc, 0 },
{ "%l", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"serial number of the output automaton (0-based)", 0 },
{ "%h", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%h", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the automaton in HOA format on a single line (use %[opt]h " "the automaton in HOA format on a single line (use %[opt]h "
"to specify additional options as in --hoa=opt)", 0 }, "to specify additional options as in --hoa=opt)", 0 },
@ -442,6 +446,7 @@ hoa_stat_printer::hoa_stat_printer(std::ostream& os, const char* format,
if (input != ltl_input) if (input != ltl_input)
declare('f', &filename_); // Override the formula printer. declare('f', &filename_); // Override the formula printer.
declare('h', &output_aut_); declare('h', &output_aut_);
declare('l', &index_);
declare('m', &aut_name_); declare('m', &aut_name_);
declare('u', &aut_univbranch_); declare('u', &aut_univbranch_);
declare('w', &aut_word_); declare('w', &aut_word_);
@ -453,11 +458,12 @@ hoa_stat_printer::print(const spot::const_parsed_aut_ptr& haut,
const spot::const_twa_graph_ptr& aut, const spot::const_twa_graph_ptr& aut,
spot::formula f, spot::formula f,
const char* filename, int loc, const char* filename, int loc,
unsigned index,
const spot::process_timer& ptimer, const spot::process_timer& ptimer,
const char* csv_prefix, const char* csv_suffix) const char* csv_prefix, const char* csv_suffix)
{ {
timer_ = ptimer; timer_ = ptimer;
index_ = index;
filename_ = filename ? filename : ""; filename_ = filename ? filename : "";
csv_prefix_ = csv_prefix ? csv_prefix : ""; csv_prefix_ = csv_prefix ? csv_prefix : "";
csv_suffix_ = csv_suffix ? csv_suffix : ""; csv_suffix_ = csv_suffix ? csv_suffix : "";
@ -599,6 +605,7 @@ automaton_printer::print(const spot::twa_graph_ptr& aut,
// Input location for errors and statistics. // Input location for errors and statistics.
const char* filename, const char* filename,
int loc, int loc,
unsigned index,
// input automaton for statistics // input automaton for statistics
const spot::const_parsed_aut_ptr& haut, const spot::const_parsed_aut_ptr& haut,
const char* csv_prefix, const char* csv_prefix,
@ -622,7 +629,8 @@ automaton_printer::print(const spot::twa_graph_ptr& aut,
if (opt_name) if (opt_name)
{ {
name.str(""); name.str("");
namer.print(haut, aut, f, filename, loc, ptimer, csv_prefix, csv_suffix); namer.print(haut, aut, f, filename, loc, index,
ptimer, csv_prefix, csv_suffix);
aut->set_named_prop("automaton-name", new std::string(name.str())); aut->set_named_prop("automaton-name", new std::string(name.str()));
} }
@ -630,8 +638,8 @@ automaton_printer::print(const spot::twa_graph_ptr& aut,
if (opt_output) if (opt_output)
{ {
outputname.str(""); outputname.str("");
outputnamer.print(haut, aut, f, filename, loc, ptimer, outputnamer.print(haut, aut, f, filename, loc, index,
csv_prefix, csv_suffix); ptimer, csv_prefix, csv_suffix);
std::string fname = outputname.str(); std::string fname = outputname.str();
auto [it, b] = outputfiles.try_emplace(fname, nullptr); auto [it, b] = outputfiles.try_emplace(fname, nullptr);
if (b) if (b)
@ -660,8 +668,8 @@ automaton_printer::print(const spot::twa_graph_ptr& aut,
break; break;
case Stats: case Stats:
statistics.set_output(*out); statistics.set_output(*out);
statistics.print(haut, aut, f, filename, loc, ptimer, statistics.print(haut, aut, f, filename, loc, index,
csv_prefix, csv_suffix) << '\n'; ptimer, csv_prefix, csv_suffix) << '\n';
break; break;
} }
flush_cout(); flush_cout();

View file

@ -133,10 +133,10 @@ public:
void print(std::ostream& os, const char* pos) const override; void print(std::ostream& os, const char* pos) const override;
}; };
/// \brief prints various statistics about a TGBA /// \brief prints various statistics about a TwA
/// ///
/// This object can be configured to display various statistics /// This object can be configured to display various statistics
/// about a TGBA. Some %-sequence of characters are interpreted in /// about a TwA. Some %-sequence of characters are interpreted in
/// the format string, and replaced by the corresponding statistics. /// the format string, and replaced by the corresponding statistics.
class hoa_stat_printer: protected spot::stat_printer class hoa_stat_printer: protected spot::stat_printer
{ {
@ -153,10 +153,12 @@ public:
/// to be output. /// to be output.
std::ostream& std::ostream&
print(const spot::const_parsed_aut_ptr& haut, print(const spot::const_parsed_aut_ptr& haut,
const spot::const_twa_graph_ptr& aut, const spot::const_twa_graph_ptr& aut,
spot::formula f, spot::formula f,
const char* filename, int loc, const spot::process_timer& ptimer, const char* filename, int loc,
const char* csv_prefix, const char* csv_suffix); unsigned index,
const spot::process_timer& ptimer,
const char* csv_prefix, const char* csv_suffix);
private: private:
spot::printable_value<const char*> filename_; spot::printable_value<const char*> filename_;
@ -165,6 +167,7 @@ private:
spot::printable_value<std::string> aut_name_; spot::printable_value<std::string> aut_name_;
spot::printable_value<std::string> aut_word_; spot::printable_value<std::string> aut_word_;
spot::printable_value<std::string> haut_word_; spot::printable_value<std::string> haut_word_;
spot::printable_value<unsigned> index_;
spot::printable_acc_cond haut_gen_acc_; spot::printable_acc_cond haut_gen_acc_;
spot::printable_size haut_states_; spot::printable_size haut_states_;
spot::printable_size haut_edges_; spot::printable_size haut_edges_;
@ -206,6 +209,8 @@ public:
// Input location for errors and statistics. // Input location for errors and statistics.
const char* filename = nullptr, const char* filename = nullptr,
int loc = -1, int loc = -1,
// serial numbner
unsigned index = 0,
// Time and input automaton for statistics // Time and input automaton for statistics
const spot::const_parsed_aut_ptr& haut = nullptr, const spot::const_parsed_aut_ptr& haut = nullptr,
const char* csv_prefix = nullptr, const char* csv_prefix = nullptr,

View file

@ -160,6 +160,7 @@ namespace
spot::formula f; spot::formula f;
const char* filename; const char* filename;
const char* line; const char* line;
unsigned index;
const char* prefix; const char* prefix;
const char* suffix; const char* suffix;
}; };
@ -237,6 +238,7 @@ namespace
declare('R', &timer_); declare('R', &timer_);
declare('r', &timer_); declare('r', &timer_);
declare('L', &line_); declare('L', &line_);
declare('l', &index_);
declare('s', &size_); declare('s', &size_);
declare('h', &class_); declare('h', &class_);
declare('n', &nesting_); declare('n', &nesting_);
@ -248,7 +250,8 @@ namespace
} }
std::ostream& std::ostream&
print(const formula_with_location& fl, spot::process_timer* ptimer) print(const formula_with_location& fl,
spot::process_timer* ptimer)
{ {
if (has('R') || has('r')) if (has('R') || has('r'))
timer_ = *ptimer; timer_ = *ptimer;
@ -256,6 +259,7 @@ namespace
fl_ = &fl; fl_ = &fl;
filename_ = fl.filename ? fl.filename : ""; filename_ = fl.filename ? fl.filename : "";
line_ = fl.line; line_ = fl.line;
index_ = fl.index;
prefix_ = fl.prefix ? fl.prefix : ""; prefix_ = fl.prefix ? fl.prefix : "";
suffix_ = fl.suffix ? fl.suffix : ""; suffix_ = fl.suffix ? fl.suffix : "";
auto f = fl_.val()->f; auto f = fl_.val()->f;
@ -288,6 +292,7 @@ namespace
printable_timer timer_; printable_timer timer_;
spot::printable_value<const char*> filename_; spot::printable_value<const char*> filename_;
spot::printable_value<const char*> line_; spot::printable_value<const char*> line_;
spot::printable_value<unsigned> index_;
spot::printable_value<const char*> prefix_; spot::printable_value<const char*> prefix_;
spot::printable_value<const char*> suffix_; spot::printable_value<const char*> suffix_;
spot::printable_value<int> size_; spot::printable_value<int> size_;
@ -356,6 +361,7 @@ static void
output_formula(std::ostream& out, output_formula(std::ostream& out,
spot::formula f, spot::process_timer* ptimer, spot::formula f, spot::process_timer* ptimer,
const char* filename, const char* linenum, const char* filename, const char* linenum,
unsigned index,
const char* prefix, const char* suffix) const char* prefix, const char* suffix)
{ {
if (!format) if (!format)
@ -391,7 +397,8 @@ output_formula(std::ostream& out,
} }
else else
{ {
formula_with_location fl = { f, filename, linenum, prefix, suffix }; formula_with_location fl = { f, filename, linenum,
index, prefix, suffix };
format->print(fl, ptimer); format->print(fl, ptimer);
} }
} }
@ -399,6 +406,7 @@ output_formula(std::ostream& out,
void void
output_formula_checked(spot::formula f, spot::process_timer* ptimer, output_formula_checked(spot::formula f, spot::process_timer* ptimer,
const char* filename, const char* linenum, const char* filename, const char* linenum,
unsigned index,
const char* prefix, const char* suffix) const char* prefix, const char* suffix)
{ {
if (output_format == count_output) if (output_format == count_output)
@ -414,7 +422,8 @@ output_formula_checked(spot::formula f, spot::process_timer* ptimer,
if (outputnamer) if (outputnamer)
{ {
outputname.str(""); outputname.str("");
formula_with_location fl = { f, filename, linenum, prefix, suffix }; formula_with_location fl = { f, filename, linenum,
index, prefix, suffix };
outputnamer->print(fl, ptimer); outputnamer->print(fl, ptimer);
std::string fname = outputname.str(); std::string fname = outputname.str();
auto [it, b] = outputfiles.try_emplace(fname, nullptr); auto [it, b] = outputfiles.try_emplace(fname, nullptr);
@ -422,7 +431,7 @@ output_formula_checked(spot::formula f, spot::process_timer* ptimer,
it->second.reset(new output_file(fname.c_str())); it->second.reset(new output_file(fname.c_str()));
out = &it->second->ostream(); out = &it->second->ostream();
} }
output_formula(*out, f, ptimer, filename, linenum, prefix, suffix); output_formula(*out, f, ptimer, filename, linenum, index, prefix, suffix);
*out << output_terminator; *out << output_terminator;
// Make sure we abort if we can't write to std::cout anymore // Make sure we abort if we can't write to std::cout anymore
// (like disk full or broken pipe with SIGPIPE ignored). // (like disk full or broken pipe with SIGPIPE ignored).
@ -432,10 +441,12 @@ output_formula_checked(spot::formula f, spot::process_timer* ptimer,
void output_formula_checked(spot::formula f, void output_formula_checked(spot::formula f,
spot::process_timer* ptimer, spot::process_timer* ptimer,
const char* filename, int linenum, const char* filename, int linenum,
unsigned index,
const char* prefix, const char* prefix,
const char* suffix) const char* suffix)
{ {
output_formula_checked(f, ptimer, filename, output_formula_checked(f, ptimer, filename,
std::to_string(linenum).c_str(), std::to_string(linenum).c_str(),
index,
prefix, suffix); prefix, suffix);
} }

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2018 Laboratoire de Recherche et Développement // Copyright (C) 2012-2018, 2023 Laboratoire de Recherche et Développement
// de l'Epita (LRDE). // de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -81,11 +81,13 @@ void output_formula_checked(spot::formula f,
spot::process_timer* ptimer = nullptr, spot::process_timer* ptimer = nullptr,
const char* filename = nullptr, const char* filename = nullptr,
const char* linenum = nullptr, const char* linenum = nullptr,
unsigned output_index = 0U,
const char* prefix = nullptr, const char* prefix = nullptr,
const char* suffix = nullptr); const char* suffix = nullptr);
void output_formula_checked(spot::formula f, void output_formula_checked(spot::formula f,
spot::process_timer* ptimer, spot::process_timer* ptimer,
const char* filename, int linenum, const char* filename, int linenum,
unsigned output_index,
const char* prefix = nullptr, const char* prefix = nullptr,
const char* suffix = nullptr); const char* suffix = nullptr);

View file

@ -129,7 +129,9 @@ namespace
timer.start(); timer.start();
auto aut = post.run(haut->aut, nullptr); auto aut = post.run(haut->aut, nullptr);
timer.stop(); timer.stop();
printer.print(aut, timer, nullptr, haut->filename.c_str(), -1, haut); static unsigned index = 0;
printer.print(aut, timer, nullptr, haut->filename.c_str(), -1,
index++, haut);
flush_cout(); flush_cout();
return 0; return 0;
} }

View file

@ -122,7 +122,8 @@ output_pattern(gen::aut_pattern_id pattern, int n)
twa_graph_ptr aut = spot::gen::aut_pattern(pattern, n); twa_graph_ptr aut = spot::gen::aut_pattern(pattern, n);
timer.stop(); timer.stop();
automaton_printer printer; automaton_printer printer;
printer.print(aut, timer, nullptr, aut_pattern_name(pattern), n); static unsigned serial = 0;
printer.print(aut, timer, nullptr, aut_pattern_name(pattern), n, serial++);
} }
static void static void

View file

@ -192,6 +192,8 @@ static const argp_option options[] =
"the formula (in the selected syntax)", 0 }, "the formula (in the selected syntax)", 0 },
{ "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the name of the pattern", 0 }, "the name of the pattern", 0 },
{ "%l", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"serial number of the output formula (0-based)", 0 },
{ "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the argument of the pattern", 0 }, "the argument of the pattern", 0 },
{ "%%", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%%", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
@ -287,6 +289,8 @@ parse_opt(int key, char* arg, struct argp_state*)
} }
static unsigned output_count = 0U;
static void static void
output_pattern(gen::ltl_pattern_id pattern, int n, int n2) output_pattern(gen::ltl_pattern_id pattern, int n, int n2)
{ {
@ -303,14 +307,14 @@ output_pattern(gen::ltl_pattern_id pattern, int n, int n2)
if (opt_positive || !opt_negative) if (opt_positive || !opt_negative)
{ {
output_formula_checked(f, nullptr, gen::ltl_pattern_name(pattern), output_formula_checked(f, nullptr, gen::ltl_pattern_name(pattern),
args.c_str()); args.c_str(), output_count++);
} }
if (opt_negative) if (opt_negative)
{ {
std::string tmp = "!"; std::string tmp = "!";
tmp += gen::ltl_pattern_name(pattern); tmp += gen::ltl_pattern_name(pattern);
output_formula_checked(formula::Not(f), nullptr, tmp.c_str(), output_formula_checked(formula::Not(f), nullptr, tmp.c_str(),
args.c_str()); args.c_str(), output_count++);
} }
} }

View file

@ -155,8 +155,9 @@ namespace
auto aut = trans.run(&f); auto aut = trans.run(&f);
timer.stop(); timer.stop();
printer.print(aut, timer, f, filename, linenum, nullptr, static unsigned index = 0;
prefix, suffix); printer.print(aut, timer, f, filename, linenum, index++,
nullptr, prefix, suffix);
// If we keep simplification caches around, atomic propositions // If we keep simplification caches around, atomic propositions
// will still be defined, and one translation may influence the // will still be defined, and one translation may influence the
// variable order of the next one. // variable order of the next one.

View file

@ -360,8 +360,7 @@ namespace
const char* csv_prefix, const char* csv_suffix) const char* csv_prefix, const char* csv_suffix)
{ {
static long int output_count = 0; static long int output_count = 0;
++output_count; printer.print(aut, ptimer, f, filename, loc, output_count++, nullptr,
printer.print(aut, ptimer, f, filename, loc, nullptr,
csv_prefix, csv_suffix); csv_prefix, csv_suffix);
if (opt_max_count >= 0 && output_count >= opt_max_count) if (opt_max_count >= 0 && output_count >= opt_max_count)
abort_run = true; abort_run = true;
@ -420,8 +419,8 @@ namespace
aut = post.run(aut, f); aut = post.run(aut, f);
if (best_type) if (best_type)
{ {
best_printer.print(nullptr, aut, f, filename, linenum, timer, best_printer.print(nullptr, aut, f, filename, linenum, 0,
prefix, suffix); timer, prefix, suffix);
std::string aut_stats = best_stream.str(); std::string aut_stats = best_stream.str();
if (!best_aut || if (!best_aut ||
(strverscmp(best_stats.c_str(), aut_stats.c_str()) (strverscmp(best_stats.c_str(), aut_stats.c_str())

View file

@ -254,6 +254,8 @@ static const argp_option options[] =
"the formula (in the selected syntax)", 0 }, "the formula (in the selected syntax)", 0 },
{ "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the name of the input file", 0 }, "the name of the input file", 0 },
{ "%l", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the serial number of the output formula", 0 },
{ "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the original line number in the input file", 0 }, "the original line number in the input file", 0 },
{ "%r", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%r", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
@ -852,7 +854,8 @@ namespace
std::to_string(linenum).c_str()) << ")\n"; std::to_string(linenum).c_str()) << ")\n";
} }
one_match = true; one_match = true;
output_formula_checked(f, &timer, filename, linenum, prefix, suffix); output_formula_checked(f, &timer, filename, linenum,
match_count, prefix, suffix);
++match_count; ++match_count;
} }
return 0; return 0;

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2014-2019, 2022 Laboratoire de Recherche et // Copyright (C) 2014-2019, 2022, 2023 Laboratoire de Recherche et
// Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -87,6 +87,8 @@ static const argp_option options[] = {
"the formula (in the selected syntax)", 0 }, "the formula (in the selected syntax)", 0 },
{ "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%F", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the name of the input file", 0 }, "the name of the input file", 0 },
{ "%l", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the serial number of the output formula (0-based)", 0 },
{ "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the original line number in the input file", 0 }, "the original line number in the input file", 0 },
{ "%<", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%<", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
@ -112,6 +114,8 @@ static const argp_child children[] = {
namespace namespace
{ {
static unsigned output_count = 0;
class mutate_processor final: public job_processor class mutate_processor final: public job_processor
{ {
public: public:
@ -122,7 +126,8 @@ namespace
auto mutations = auto mutations =
spot::mutate(f, mut_opts, max_output, mutation_nb, opt_sort); spot::mutate(f, mut_opts, max_output, mutation_nb, opt_sort);
for (auto g: mutations) for (auto g: mutations)
output_formula_checked(g, nullptr, filename, linenum, prefix, suffix); output_formula_checked(g, nullptr, filename, linenum,
output_count++, prefix, suffix);
return 0; return 0;
} }
}; };

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2016, 2018-2020, 2022 Laboratoire de Recherche // Copyright (C) 2012-2016, 2018-2020, 2022, 2023 Laboratoire de Recherche
// et Développement de l'Epita (LRDE). // et Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -406,7 +406,8 @@ main(int argc, char** argv)
timer.stop(); timer.stop();
printer.print(aut, timer, nullptr, printer.print(aut, timer, nullptr,
opt_seed_str, automaton_num, nullptr); opt_seed_str, automaton_num,
automaton_num, nullptr);
++automaton_num; ++automaton_num;
if (opt_automata > 0 && automaton_num >= opt_automata) if (opt_automata > 0 && automaton_num >= opt_automata)

View file

@ -115,8 +115,10 @@ static const argp_option options[] =
"the following interpreted sequences:", -19 }, "the following interpreted sequences:", -19 },
{ "%f", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%f", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the formula (in the selected syntax)", 0 }, "the formula (in the selected syntax)", 0 },
{ "%l", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the (serial) number of the formula (0-based)", 0 },
{ "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%L", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"the (serial) number of the formula", 0 }, "the (serial) number of the formula (1-based)", 0 },
{ "%%", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%%", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"a single %", 0 }, "a single %", 0 },
COMMON_LTL_OUTPUT_SPECS, COMMON_LTL_OUTPUT_SPECS,
@ -305,9 +307,9 @@ main(int argc, char** argv)
exit(0); exit(0);
} }
int count = 0;
while (opt_formulas < 0 || opt_formulas--) while (opt_formulas < 0 || opt_formulas--)
{ {
static int count = 0;
spot::formula f = rg.next(); spot::formula f = rg.next();
if (!f) if (!f)
{ {
@ -316,7 +318,8 @@ main(int argc, char** argv)
} }
else else
{ {
output_formula_checked(f, nullptr, nullptr, ++count); output_formula_checked(f, nullptr, nullptr, count + 1, count);
++count;
} }
}; };
flush_cout(); flush_cout();

View file

@ -725,7 +725,8 @@ randaut --help | sed -n '/ sequences:/,/^$/p' | sed '1d;$d'
(iw) inherently weak. Use uppercase letters to (iw) inherently weak. Use uppercase letters to
negate them. negate them.
%d 1 if the output is deterministic, 0 otherwise %d 1 if the output is deterministic, 0 otherwise
%e number of reachable edges %e, %[LETTER]e number of edges (add one LETTER to select (r)
reachable [default], (u) unreachable, (a) all).
%F seed number %F seed number
%g, %[LETTERS]g acceptance condition (in HOA syntax); add brackets %g, %[LETTERS]g acceptance condition (in HOA syntax); add brackets
to print an acceptance name instead and LETTERS to to print an acceptance name instead and LETTERS to
@ -740,6 +741,7 @@ randaut --help | sed -n '/ sequences:/,/^$/p' | sed '1d;$d'
%[opt]h to specify additional options as in %[opt]h to specify additional options as in
--hoa=opt) --hoa=opt)
%L automaton number %L automaton number
%l serial number of the output automaton (0-based)
%m name of the automaton %m name of the automaton
%n number of nondeterministic states in output %n number of nondeterministic states in output
%p 1 if the output is complete, 0 otherwise %p 1 if the output is complete, 0 otherwise
@ -749,8 +751,11 @@ randaut --help | sed -n '/ sequences:/,/^$/p' | sed '1d;$d'
LETTERS to restrict to(u) user time, (s) system LETTERS to restrict to(u) user time, (s) system
time, (p) parent process, or (c) children time, (p) parent process, or (c) children
processes. processes.
%s number of reachable states %s, %[LETTER]s number of states (add one LETTER to select (r)
%t number of reachable transitions reachable [default], (u) unreachable, (a) all).
%t, %[LETTER]t number of transitions (add one LETTER to select
(r) reachable [default], (u) unreachable, (a)
all).
%u, %[e]u number of states (or [e]dges) with universal %u, %[e]u number of states (or [e]dges) with universal
branching branching
%u, %[LETTER]u 1 if the automaton contains some universal %u, %[LETTER]u 1 if the automaton contains some universal
@ -996,6 +1001,14 @@ randaut -D -n 20 -Q2 1 -o '>>out-det%d.hoa'
(You need the quotes so that the shell does not interpret =>>=.) (You need the quotes so that the shell does not interpret =>>=.)
The =%l= sequence is a number that is incremented for each output
automaton. For instance if =input.hoa= contains multiple automata,
you can separate them into separate files with:
#+BEGIN_SRC sh :exports code
autilt input.hoa -o output-%l.hoa
#+END_SRC
#+BEGIN_SRC sh :results silent :exports results #+BEGIN_SRC sh :results silent :exports results
rm -f out-det0.hoa out-det1.hoa rm -f out-det0.hoa out-det1.hoa
#+END_SRC #+END_SRC

View file

@ -230,6 +230,7 @@ TESTS_twa = \
core/cube.test \ core/cube.test \
core/alternating.test \ core/alternating.test \
core/gamehoa.test \ core/gamehoa.test \
core/serial.test \
core/ltlcross3.test \ core/ltlcross3.test \
core/ltlcross5.test \ core/ltlcross5.test \
core/taatgba.test \ core/taatgba.test \

71
tests/core/serial.test Executable file
View file

@ -0,0 +1,71 @@
#!/bin/sh
# -*- coding: utf-8 -*-
# Copyright (C) 2023 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/>.
. ./defs
set -e
# all tools should be able to use %l as serial number for their output
# Make sure serial numbers count the output automata
randaut -n10 --name='aut %l' 2 |
autfilt -N3..5 --name='%M/out %l' |
autfilt --stats=%M >out
cat >exp <<EOF
aut 2/out 0
aut 3/out 1
aut 4/out 2
EOF
diff out exp
# Create different files
randaut -n3 2 -oaut-%l.hoa
test -f aut-0.hoa
test -f aut-1.hoa
test -f aut-2.hoa
# Split an output
cat aut-0.hoa aut-1.hoa aut-2.hoa > aut.hoa
rm aut-?.hoa
autfilt aut.hoa -o aut-%l.hoa
# check serial output in various tools
genaut --m-nba=2..3 --name='%F=%L/%l' | autfilt --stats=%M >out
genltl --and-f=2..3 --stats=%F=%L/%l >> out
ltl2tgba a b --name=%f/%l | autfilt --stats=%M >> out
ltldo -f a -f b ltl2tgba --name=%f/%l | autfilt --stats=%M >> out
genltl --or-g=2..5 --stats=%L,%l,%f |
ltlfilt -F -/3 -N 2..3 --stats='%<,%l' >>out
randltl -n10 3 --stats=%l,%f |
ltlfilt -F -/2 -N 2..3 --stats='%<,%l' >> out
cat >exp<<EOF
m-nba=2/0
m-nba=3/1
and-f=2/0
and-f=3/1
a/0
b/1
a/0
b/1
3,1,0
4,2,1
1,0
2,1
EOF
diff -u out exp