ltlfilt: add support for --relabel=io, --ins, and --outs

* bin/common_ioap.cc, bin/common_ioap.hh (relabel_io): New function.
* bin/ltlfilt.cc: Implement the above options.
* doc/org/ltlfilt.org, NEWS: Illustrate them.
* tests/core/ltlfilt.test: Add some quick tests.
This commit is contained in:
Alexandre Duret-Lutz 2024-08-23 17:22:17 +02:00
parent bea1713f4e
commit 6fa42c90b8
6 changed files with 222 additions and 3 deletions

View file

@ -164,3 +164,37 @@ filter_list_of_aps(spot::formula f, const char* filename, int linenum)
}
return {matched[0], matched[1]};
}
spot::formula relabel_io(spot::formula f, spot::relabeling_map& fro,
const char* filename, int linenum)
{
auto [ins, outs] = filter_list_of_aps(f, filename, linenum);
// Different implementation of unordered_set, usinged in
// filter_list_of_aps can cause aps to be output in different order.
// Let's sort everything for the sake of determinism.
std::sort(ins.begin(), ins.end());
std::sort(outs.begin(), outs.end());
spot::relabeling_map to;
unsigned ni = 0;
for (std::string& i: ins)
{
std::ostringstream s;
s << 'i' << ni++;
spot::formula a1 = spot::formula::ap(i);
spot::formula a2 = spot::formula::ap(s.str());
fro[a2] = a1;
to[a1] = a2;
}
unsigned no = 0;
for (std::string& o: outs)
{
std::ostringstream s;
s << 'o' << no++;
spot::formula a1 = spot::formula::ap(o);
spot::formula a2 = spot::formula::ap(s.str());
fro[a2] = a1;
to[a1] = a2;
}
return spot::relabel_apply(f, &to);
}

View file

@ -25,6 +25,7 @@
#include <vector>
#include <unordered_map>
#include <spot/tl/formula.hh>
#include <spot/tl/relabel.hh>
// --ins and --outs, as supplied on the command-line
extern std::optional<std::vector<std::string>> all_output_aps;
@ -49,3 +50,8 @@ extern std::unordered_map<std::string, bool> identifier_map;
// regex_out, and identifier_map.
std::pair<std::vector<std::string>, std::vector<std::string>>
filter_list_of_aps(spot::formula f, const char* filename, int linenum);
// Relabel APs incrementally, based on i/o class.
spot::formula relabel_io(spot::formula f, spot::relabeling_map& fro,
const char* filename, int linenum);

View file

@ -31,6 +31,7 @@
#include "common_output.hh"
#include "common_cout.hh"
#include "common_conv.hh"
#include "common_ioap.hh"
#include "common_r.hh"
#include "common_range.hh"
@ -86,6 +87,7 @@ enum {
OPT_IGNORE_ERRORS,
OPT_IMPLIED_BY,
OPT_IMPLY,
OPT_INS,
OPT_LIVENESS,
OPT_LTL,
OPT_NEGATE,
@ -117,6 +119,7 @@ enum {
OPT_SYNTACTIC_SAFETY,
OPT_SYNTACTIC_SI,
OPT_TO_DELTA2,
OPT_OUTS,
OPT_UNABBREVIATE,
OPT_UNIVERSAL,
};
@ -141,7 +144,7 @@ static const argp_option options[] =
{ "sonf-aps", OPT_SONF_APS, "FILENAME", OPTION_ARG_OPTIONAL,
"when used with --sonf, output the newly introduced atomic "
"propositions", 0 },
{ "relabel", OPT_RELABEL, "abc|pnn", OPTION_ARG_OPTIONAL,
{ "relabel", OPT_RELABEL, "abc|pnn|io", OPTION_ARG_OPTIONAL,
"relabel all atomic propositions, alphabetically unless " \
"specified otherwise", 0 },
{ "relabel-bool", OPT_RELABEL_BOOL, "abc|pnn", OPTION_ARG_OPTIONAL,
@ -178,6 +181,12 @@ static const argp_option options[] =
{ "from-ltlf", OPT_FROM_LTLF, "alive", OPTION_ARG_OPTIONAL,
"transform LTLf (finite LTL) to LTL by introducing some 'alive'"
" proposition", 0 },
{ "ins", OPT_INS, "PROPS", 0,
"comma-separated list of input atomic propositions to use with "
"--relabel=io, interpreted as a regex if enclosed in slashes", 0 },
{ "outs", OPT_OUTS, "PROPS", 0,
"comma-separated list of output atomic propositions to use with "
"--relabel=io, interpreted as a regex if enclosed in slashes", 0 },
DECLARE_OPT_R,
LEVEL_DOC(4),
/**************************************************/
@ -341,6 +350,7 @@ static range size = { -1, -1 };
static range bsize = { -1, -1 };
enum relabeling_mode { NoRelabeling = 0,
ApRelabeling,
IOApRelabeling,
BseRelabeling,
OverlappingRelabeling };
static relabeling_mode relabeling = NoRelabeling;
@ -391,9 +401,12 @@ parse_relabeling_style(const char* arg, const char* optname)
style = spot::Abc;
else if (!strncasecmp(arg, "pnn", 4))
style = spot::Pnn;
else if (!*optname && !strncasecmp(arg, "io", 2))
relabeling = IOApRelabeling; // style is actually not supported
else
error(2, 0, "invalid argument for --relabel%s: '%s'\n"
"expecting 'abc' or 'pnn'", optname, arg);
"expecting %s", optname, arg,
*optname ? "'abc' or 'pnn'" : "'abc', 'pnn', or 'io'");
}
@ -502,6 +515,12 @@ parse_opt(int key, char* arg, struct argp_state*)
opt->imply = spot::formula::And({opt->imply, i});
break;
}
case OPT_INS:
{
all_input_aps.emplace(std::vector<std::string>{});
split_aps(arg, *all_input_aps);
break;
}
case OPT_LIVENESS:
liveness = true;
break;
@ -517,6 +536,12 @@ parse_opt(int key, char* arg, struct argp_state*)
case OPT_NNF:
nnf = true;
break;
case OPT_OUTS:
{
all_output_aps.emplace(std::vector<std::string>{});
split_aps(arg, *all_output_aps);
break;
}
case OPT_SONF:
sonf = arg ? arg : "sonf_";
break;
@ -752,6 +777,12 @@ namespace
f = spot::relabel(f, style, &relmap);
break;
}
case IOApRelabeling:
{
relmap.clear();
f = relabel_io(f, relmap, filename, linenum);
break;
}
case BseRelabeling:
{
relmap.clear();
@ -948,6 +979,9 @@ main(int argc, char** argv)
if (jobs.empty())
jobs.emplace_back("-", job_type::LTL_FILENAME);
if (relabeling == IOApRelabeling)
process_io_options();
if (boolean_to_isop && simplification_level == 0)
simplification_level = 1;
spot::tl_simplifier_options tlopt(simplification_level);