Adding ltlgrind as a command-line tool

* src/bin/ltlgrind.cc: New file, command-line tool to get mutations of a
formula.
* src/bin/Makefile.am: Add it.
* src/ltlvisit/mutation.hh, src/ltlvisit/mutation.cc:
New files providing the get_mutations function.
* src/ltlvisit/Makefile.am: Add it.
* src/ltltest/ltlgrind.test: Test it.
* src/ltltest/Makefile.am: Add it.
* src/bin/man/ltlgrind.x: Document it.
* src/bin/man/Makefile.am: Add it.
* doc/org/ltlgrind.org: Document it.
* doc/org/tools.org: Add link to ltlgrind documentation page.
This commit is contained in:
Thibaud Michaud 2014-09-12 15:39:01 +02:00 committed by Alexandre Duret-Lutz
parent 51fe5108fe
commit e327f6ea11
11 changed files with 923 additions and 1 deletions

View file

@ -43,7 +43,7 @@ libcommon_a_SOURCES = \
common_sys.hh
bin_PROGRAMS = ltlfilt genltl randltl ltl2tgba ltl2tgta ltlcross \
dstar2tgba
dstar2tgba ltlgrind
# Dummy program used just to generate man/spot-x.7 in a way that is
# consistent with the other man pages (e.g., with a version number that
@ -56,6 +56,7 @@ randltl_SOURCES = randltl.cc
ltl2tgba_SOURCES = ltl2tgba.cc
ltl2tgta_SOURCES = ltl2tgta.cc
ltlcross_SOURCES = ltlcross.cc
ltlgrind_SOURCES = ltlgrind.cc
dstar2tgba_SOURCES = dstar2tgba.cc
spot_x_SOURCES = spot-x.cc
ltlcross_LDADD = $(LDADD) $(LIB_GETHRXTIME)

207
src/bin/ltlgrind.cc Normal file
View file

@ -0,0 +1,207 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012, 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 "common_sys.hh"
#include <argp.h>
#include <limits>
#include "common_setup.hh"
#include "common_finput.hh"
#include "common_output.hh"
#include "error.h"
#include "ltlast/allnodes.hh"
#include "ltlvisit/clone.hh"
#include "ltlvisit/apcollect.hh"
#include "ltlvisit/length.hh"
#include "ltlvisit/mutation.hh"
#define OPT_AP2CONST 1
#define OPT_SIMPLIFY_BOUNDS 2
#define OPT_REMOVE_MULTOP_OPERANDS 3
#define OPT_REMOVE_OPS 4
#define OPT_SPLIT_OPS 5
#define OPT_REWRITE_OPS 6
#define OPT_REMOVE_ONE_AP 7
#define OPT_SORT 8
static unsigned mutation_nb = 1;
static int max_output = std::numeric_limits<int>::max();
static unsigned opt_all = 0xfff;
static unsigned mut_opts = 0;
static bool opt_sort = false;
const char * argp_program_doc = "List formulas that are similar to but " \
"simpler than a given formula.";
static const argp_option options[] = {
{"mutations", 'm', "N", 0, "number of mutations to apply to the " \
"formulae (default: 1)", -1},
{"sort", OPT_SORT, 0, 0, "sort the result by formula size", 0},
{0, 0, 0, 0, "Transformation rules:", 15},
{"ap-to-const", OPT_AP2CONST, 0, 0,
"atomic propositions are replaced with true/false", 15},
{"remove-one-ap", OPT_REMOVE_ONE_AP, 0, 0,
"all occurrences of an atomic proposition are replaced with another" \
"atomic proposition used in the formula", 15},
{"remove-multop-operands", OPT_REMOVE_MULTOP_OPERANDS, 0, 0,
"remove one operand from multops", 15},
{"remove-ops", OPT_REMOVE_OPS, 0, 0,
"replace unary/binary operators with one of their operands",
15},
{"split-ops", OPT_SPLIT_OPS, 0, 0,
"when an operator can be expressed as a conjunction/disjunction using " \
"simpler operators, each term of the conjunction/disjunction is a " \
"mutation. e.g. a <-> b can be written as ((a & b) | (!a & !b)) or as " \
"((a -> b) & (b -> a)) so those four terms can be a mutation of a <-> b", 0},
{"rewrite-ops", OPT_REWRITE_OPS, 0, 0,
"rewrite operators that have a semantically simpler form: a U b becomes " \
"a W b, etc.", 0},
{"simplify-bounds", OPT_SIMPLIFY_BOUNDS, 0, 0,
"on a bounded unary operator, decrement one of the bounds, or set min to " \
"0 or max to " \
"unbounded.", 15},
{0, 0, 0, 0, "Output options:", 20},
{"max-output", 'n', "N", 0, "maximum number of mutations to output", 20},
{0, 0, 0, 0, "Miscellaneous options:", -1},
{0, 0, 0, 0, 0, 0}
};
static const argp_child children[] = {
{&finput_argp, 0, 0, 10},
{&output_argp, 0, 0, 20},
{&misc_argp, 0, 0, -1},
{0, 0, 0, 0}
};
static int
to_int(const char *s)
{
char* endptr;
unsigned res = strtol(s, &endptr, 10);
if (*endptr)
error(2, 0, "failed to parse '%s' as an unsigned integer.", s);
return res;
}
static unsigned
to_unsigned (const char *s)
{
char* endptr;
unsigned res = strtoul(s, &endptr, 10);
if (*endptr)
error(2, 0, "failed to parse '%s' as an unsigned integer.", s);
return res;
}
namespace
{
using namespace spot::ltl;
class mutate_processor:
public job_processor
{
public:
int
process_formula(const formula* f, const char *filename = 0,
int linenum = 0)
{
std::vector<const formula*> mutations =
get_mutations(f, mut_opts, opt_sort, max_output, mutation_nb);
f->destroy();
std::vector<const formula*>::iterator it;
for (it = mutations.begin(); it != mutations.end(); ++it)
{
output_formula_checked(*it, filename, linenum);
(*it)->destroy();
}
return 0;
}
};
}
int
parse_opt(int key, char* arg, struct argp_state*)
{
switch (key)
{
case 'm':
mutation_nb = to_unsigned(arg);
break;
case 'n':
max_output = to_int(arg);
break;
case OPT_AP2CONST:
opt_all = 0;
mut_opts |= MUT_AP2CONST;
break;
case OPT_REMOVE_ONE_AP:
opt_all = 0;
mut_opts |= MUT_REMOVE_ONE_AP;
break;
case OPT_REMOVE_MULTOP_OPERANDS:
opt_all = 0;
mut_opts |= MUT_REMOVE_MULTOP_OPERANDS;
break;
case OPT_REMOVE_OPS:
opt_all = 0;
mut_opts |= MUT_REMOVE_OPS;
break;
case OPT_SPLIT_OPS:
opt_all = 0;
mut_opts |= MUT_SPLIT_OPS;
break;
case OPT_REWRITE_OPS:
opt_all = 0;
mut_opts |= MUT_REWRITE_OPS;
break;
case OPT_SIMPLIFY_BOUNDS:
opt_all = 0;
mut_opts |= MUT_SIMPLIFY_BOUNDS;
break;
case OPT_SORT:
opt_sort = true;
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
int
main(int argc, char* argv[])
{
setup(argv);
const argp ap = { options, parse_opt, 0, argp_program_doc, children, 0, 0 };
if (int err = argp_parse(&ap, argc, argv, 0, 0, 0))
exit(err);
mut_opts |= opt_all;
if (jobs.empty())
jobs.push_back(job("-", 1));
mutate_processor processor;
if (processor.run())
return 2;
return 0;
}

View file

@ -29,6 +29,7 @@ dist_man1_MANS = \
ltl2tgta.1 \
ltlcross.1 \
ltlfilt.1 \
ltlgrind.1 \
randltl.1
dist_man7_MANS = \
spot-x.7
@ -59,3 +60,6 @@ randltl.1: $(common_dep) $(srcdir)/randltl.x $(srcdir)/../randltl.cc
spot-x.7: $(common_dep) $(srcdir)/spot-x.x $(srcdir)/../spot-x.cc
$(convman) ../spot-x$(EXEEXT) $(srcdir)/spot-x.x $@
ltlgrind.1: $(common_dep) $(srcdir)/ltlgrind.x $(srcdir)/../ltlgrind.cc
$(convman) ../ltlgrind$(EXEEXT) $(srcdir)/ltlgrind.x $@

6
src/bin/man/ltlgrind.x Normal file
View file

@ -0,0 +1,6 @@
[NAME]
ltlgrind \- list mutations of a formula.
[DESCRIPTION]
.\" Add any additional description here
[SEE ALSO]
.BR ltlcross (1),

View file

@ -98,6 +98,7 @@ TESTS = \
kind.test \
remove_x.test \
ltlrel.test \
ltlgrind.test \
ltlfilt.test \
latex.test \
lbt.test \

166
src/ltltest/ltlgrind.test Executable file
View file

@ -0,0 +1,166 @@
#! /bin/sh
# Copyright (C) 2013 Laboratoire de Recherche et Developement to
# 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 || exit 1
set -e
checkopt()
{
cat >exp
run 0 ../../bin/ltlgrind "$@" > out
diff exp out
}
checkopt -f 'Xp1 U (p4 | (p3 xor (p4 W p0)))' <<EOF
1
Xp1
p4 | (p3 xor (p4 W p0))
Xp1 W (p4 | (p3 xor (p4 W p0)))
Xp1 U (p3 xor (p4 W p0))
Xp1 U p4
Xp1 U (p3 | p4)
Xp1 U (p4 | (p4 W p0))
Xp1 U (p4 | (p3 & !(p4 W p0)))
Xp1 U (p4 | (!p3 & (p4 W p0)))
Xp1 U (p4 | (p3 xor p4))
Xp1 U (p4 | (p0 xor p3))
Xp1 U (!p3 | p4)
Xp1 U (p4 | (p3 xor (p4 W 0)))
Xp1 U (p4 | !(p4 W p0))
p1 U (p4 | (p3 xor (p4 W p0)))
1 U (p4 | (p3 xor (p4 W p0)))
Xp4 U (p4 | (p3 xor (p4 W p0)))
Xp3 U (p4 | (p3 xor (p4 W p0)))
Xp0 U (p4 | (p3 xor (p4 W p0)))
Xp1 U (p1 | (p3 xor (p1 W p0)))
Xp1 U (p3 | (p3 xor (p3 W p0)))
Xp1 U (p0 | (p0 xor p3))
Xp1 U (p4 | (p1 xor (p4 W p0)))
Xp1 U (p4 | (p4 xor (p4 W p0)))
Xp1 U (p4 | (p0 xor (p4 W p0)))
Xp1 U (p4 | (p3 xor (p4 W p1)))
Xp1 U (p4 | (p3 xor (p4 W p3)))
EOF
checkopt -f '(Xp4 R p3) W !p0' --sort <<EOF
1
!p0
Xp4 R p3
p3 W !p0
Xp4 W !p0
(Xp4 R p3) W p0
(Xp4 R p3) W 0
(p4 R p3) W !p0
(0 R p3) W !p0
(p3 W Xp4) W !p0
(Xp3 R p3) W !p0
(Xp0 R p3) W !p0
(Xp4 R p4) W !p0
(Xp4 R p0) W !p0
(Xp4 R p3) W !p4
(Xp4 R p3) W !p3
EOF
checkopt -f 'F(!p2 & p3) | Fp0' -n 4 <<EOF
F(!p2 & p3)
Fp0
(!p2 & p3) | Fp0
Fp0 | Fp3
EOF
checkopt -f '{(a | b)[*4] & ((a | b)*; c)} <>-> G(d <-> e) xor f' --split-ops \
<<EOF
{{{a | b}}[*4] & {{{a | b}}[*];c}}<>-> (f & !G(d <-> e))
{{{a | b}}[*4] & {{{a | b}}[*];c}}<>-> (!f & G(d <-> e))
{{{a | b}}[*4] & {{{a | b}}[*];c}}<>-> (f xor G(d -> e))
{{{a | b}}[*4] & {{{a | b}}[*];c}}<>-> (f xor G(e -> d))
{{{a | b}}[*4] & {{{a | b}}[*];c}}<>-> (f xor G(d & e))
{{{a | b}}[*4] & {{{a | b}}[*];c}}<>-> (f xor G(!d & !e))
{{{{a | b}}[*];c} && {{{a | b}}[*4];[*]}}<>-> (f xor G(d <-> e))
{{{a | b}}[*4] && {{{a | b}}[*];c;[*]}}<>-> (f xor G(d <-> e))
EOF
checkopt -f '!(!XXp1 M X(p4 U p2))' --rewrite-ops <<EOF
!(!XXp1 R X(p4 U p2))
!(X(p4 U p2) U !XXp1)
!(!XXp1 M X(p4 W p2))
EOF
checkopt -f '!(p0 & !p2 & (p1 W 0))' --remove-multop-operands <<EOF
!(!p2 & (p1 W 0))
!(p0 & (p1 W 0))
!(p0 & !p2)
EOF
checkopt -f '{p1[*..2] | p2[*3..5] | p3[*6..]}[]-> 0' --simplify-bounds <<EOF
{p2[*3..5] | p3[*6..] | p1[*0..1]}[]-> 0
{p2[*3..5] | p3[*6..] | p1[*]}[]-> 0
{p1[*0..2] | p3[*6..] | p2[*2..5]}[]-> 0
{p1[*0..2] | p3[*6..] | p2[*0..5]}[]-> 0
{p1[*0..2] | p3[*6..] | p2[*3..4]}[]-> 0
{p1[*0..2] | p3[*6..] | p2[*3..]}[]-> 0
{p1[*0..2] | p2[*3..5] | p3[*5..]}[]-> 0
{p1[*0..2] | p2[*3..5] | p3[*]}[]-> 0
EOF
checkopt -f '!F(!X(Xp1 R p2) -> p4)' --remove-one-ap <<EOF
!F(!X(Xp2 R p2) -> p4)
!F(!X(Xp4 R p2) -> p4)
!F(!X(Xp1 R p1) -> p4)
!F(!X(Xp1 R p4) -> p4)
!F(!X(Xp1 R p2) -> p1)
!F(!X(Xp1 R p2) -> p2)
EOF
checkopt -f '!p4 & (p2 | {{!p1}[*]})' --ap-to-const <<EOF
0
!p4
p2 | {{!p1}[*]}
!p4 & {{!p1}[*]}
p2 & !p4
!p4 & (p2 | {[*]})
EOF
checkopt -f 'F(XXp0 | (p4 & Gp0))' --remove-ops <<EOF
XXp0 | (p4 & Gp0)
F(Xp0 | (p4 & Gp0))
F((p0 & p4) | XXp0)
EOF
checkopt -f '1 U (p3 <-> p4)' -m 2 <<EOF
1
0
p3
p4
p3 -> p4
p4 -> p3
p3 & p4
!p4
!p3
!p3 & !p4
1 U p3
1 U p4
1 U !p3
1 U !p4
1 U (p3 & !p4)
1 U (!p3 & p4)
EOF

View file

@ -34,6 +34,7 @@ ltlvisit_HEADERS = \
lbt.hh \
length.hh \
lunabbrev.hh \
mutation.hh \
nenoform.hh \
postfix.hh \
randomltl.hh \
@ -58,6 +59,7 @@ libltlvisit_la_SOURCES = \
lunabbrev.cc \
mark.cc \
mark.hh \
mutation.cc \
nenoform.cc \
postfix.cc \
randomltl.cc \

399
src/ltlvisit/mutation.cc Normal file
View file

@ -0,0 +1,399 @@
// Copyright (C) 2013 Laboratoire de Recherche et Developpement 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 <unordered_set>
#include <algorithm>
#include "ltlast/allnodes.hh"
#include "ltlvisit/apcollect.hh"
#include "ltlvisit/clone.hh"
#include "ltlvisit/mutation.hh"
#include "ltlvisit/length.hh"
#include "misc/hash.hh"
#define Implies_(x, y) \
spot::ltl::binop::instance(spot::ltl::binop::Implies, (x), (y))
#define And_(x, y) \
spot::ltl::multop::instance(spot::ltl::multop::And, (x), (y))
#define AndRat_(x, y) \
spot::ltl::multop::instance(spot::ltl::multop::AndRat, (x), (y))
#define AndNLM_(x) \
spot::ltl::multop::instance(spot::ltl::multop::AndNLM, (x))
#define Concat_(x, y) \
spot::ltl::multop::instance(spot::ltl::multop::Concat, (x), (y))
#define Not_(x) \
spot::ltl::unop::instance(spot::ltl::unop::Not, (x))
namespace spot
{
namespace ltl
{
namespace
{
class replace_visitor : public clone_visitor
{
public:
void visit(const atomic_prop* ap)
{
if (ap == (*ap1_))
result_ = (*ap2_)->clone();
else
result_ = ap->clone();
}
const formula*
replace(const formula* f,
atomic_prop_set::iterator ap1, atomic_prop_set::iterator ap2)
{
ap1_ = ap1;
ap2_ = ap2;
return recurse(f);
}
private:
atomic_prop_set::iterator ap1_;
atomic_prop_set::iterator ap2_;
};
typedef std::vector<const formula*> vec;
class mutation_visitor : public clone_visitor
{
public:
mutation_visitor(const formula* f, unsigned opts) : f_(f), opts_(opts)
{
}
void visit(const atomic_prop* ap)
{
result_ = 0;
if (opts_ & MUT_AP2CONST)
{
if (mutation_counter_-- == 0)
result_ = constant::true_instance();
if (mutation_counter_-- == 0)
result_ = constant::false_instance();
}
if (!result_)
result_ = ap->clone();
}
void visit(const unop* uo)
{
result_ = 0;
if (opts_ & MUT_REMOVE_OPS)
{
if ((uo->op() == unop::G
|| uo->op() == unop::F
|| uo->op() == unop::X
|| uo->op() == unop::Not)
&& mutation_counter_-- == 0)
result_ = uo->child()->clone();
}
if (!result_)
{
if (mutation_counter_ < 0)
result_ = uo->clone();
else
{
result_ = unop::instance(uo->op(), recurse(uo->child()));
}
}
}
void visit(const binop* bo)
{
const formula* first = bo->first();
const formula* second = bo->second();
result_ = 0;
if (opts_ & MUT_REMOVE_OPS && mutation_counter_-- == 0)
result_ = first->clone();
if (opts_ & MUT_REMOVE_OPS && mutation_counter_-- == 0)
result_ = second->clone();
if (opts_ & MUT_REWRITE_OPS)
{
switch (bo->op())
{
case binop::U:
if (mutation_counter_-- == 0)
result_ = binop::instance(binop::W, first->clone(),
second->clone());
break;
case binop::M:
if (mutation_counter_-- == 0)
result_ = binop::instance(binop::R, first->clone(),
second->clone());
if (mutation_counter_-- == 0)
result_ = binop::instance(binop::U, second->clone(),
first->clone());
break;
case binop::R:
if (mutation_counter_-- == 0)
result_ = binop::instance(binop::W, second->clone(),
first->clone());
break;
default:
break;
}
}
if (opts_ & MUT_SPLIT_OPS)
{
switch (bo->op())
{
case binop::Equiv:
if (mutation_counter_-- == 0)
result_ = Implies_(first->clone(), second->clone());
if (mutation_counter_-- == 0)
result_ = Implies_(second->clone(), first->clone());
if (mutation_counter_-- == 0)
result_ = And_(first->clone(), second->clone());
if (mutation_counter_-- == 0)
result_ = And_(Not_(first->clone()),
Not_(second->clone()));
break;
case binop::Xor:
if (mutation_counter_-- == 0)
result_ = And_(first->clone(), Not_(second->clone()));
if (mutation_counter_-- == 0)
result_ = And_(Not_(first->clone()), second->clone());
break;
default:
break;
}
}
if (!result_)
{
if (mutation_counter_ < 0)
result_ = bo->clone();
else
result_ =
binop::instance(bo->op(), recurse(first), recurse(second));
}
}
void visit(const bunop* bu)
{
const formula* c = bu->child()->clone();
result_ = 0;
if (opts_ & MUT_REMOVE_OPS && mutation_counter_-- == 0)
result_ = c->clone();
if (opts_ & MUT_SIMPLIFY_BOUNDS)
{
if (bu->min() > 0 && mutation_counter_-- == 0)
result_ =
bunop::instance(bu->op(), c, bu->min() - 1, bu->max());
if (bu->min() > 0 && mutation_counter_-- == 0)
result_ = bunop::instance(bu->op(), c, 0, bu->max());
if (bu->max() != bunop::unbounded && bu->max() > bu->min()
&& mutation_counter_-- == 0)
result_ =
bunop::instance(bu->op(), c, bu->min(), bu->max() - 1);
if (bu->max() != bunop::unbounded && mutation_counter_-- == 0)
result_ = bunop::instance(bu->op(), c, bu->min(),
bunop::unbounded);
}
if (!result_)
{
c->destroy();
if (mutation_counter_ < 0)
result_ = bu->clone();
else
result_ = bunop::instance(bu->op(), recurse(c), bu->min(),
bu->max());
}
}
void visit(const multop* mo)
{
int mos = mo->size();
int i;
result_ = 0;
if (opts_ & MUT_REMOVE_MULTOP_OPERANDS)
{
for (i = 0; i < mos; ++i)
if (mutation_counter_-- == 0)
result_ = mo->all_but(i);
}
if (opts_ & MUT_SPLIT_OPS && mo->op() == multop::AndNLM)
{
if (mutation_counter_ >= 0 && mutation_counter_ < 2 * (mos - 1))
{
vec* v1 = new vec();
vec* v2 = new vec();
v1->push_back(mo->nth(0)->clone());
bool reverse = false;
i = 1;
while (i < mos)
{
if (mutation_counter_-- == 0)
break;
if (mutation_counter_-- == 0)
{
reverse = true;
break;
}
v1->push_back(mo->nth(i++)->clone());
}
for (; i < mos; ++i)
v2->push_back(mo->nth(i)->clone());
const formula* tstar =
bunop::instance(bunop::Star, constant::true_instance(),
0,
bunop::unbounded);
const formula* first = AndNLM_(v1);
const formula* second = AndNLM_(v2);
if (!reverse)
result_ = AndRat_(Concat_(first, tstar), second);
else
result_ = AndRat_(Concat_(second, tstar), first);
}
else
mutation_counter_ -= 2 * (mos - 1);
}
if (!result_)
{
if (mutation_counter_ < 0)
result_ = mo->clone();
else
{
vec* v = new vec();
for (i = 0; i < mos; ++i)
v->push_back(recurse(mo->nth(i)));
result_ = multop::instance(mo->op(), v);
}
}
}
const formula*
recurse(const formula* f)
{
f->accept(*this);
return result_;
}
const formula*
get_mutation(int n)
{
mutation_counter_ = n;
const formula* mut = recurse(f_);
if (mut == f_)
{
mut->destroy();
return 0;
}
return mut;
}
private:
const formula* f_;
int mutation_counter_ = 0;
unsigned opts_;
};
bool
formula_length_less_than(const formula* left, const formula* right)
{
assert(left);
assert(right);
if (left == right)
return false;
return length(left) < length(right);
}
typedef std::set<const formula*, formula_ptr_less_than> fset_t;
void
single_mutation_rec(const formula* f, fset_t& mutations, unsigned opts,
int& n, unsigned m)
{
if (m == 0)
{
if (mutations.insert(f).second)
{
f->clone();
--n;
}
}
else
{
const formula* mut(nullptr);
int i = 0;
mutation_visitor mv(f, opts);
while (n > 0 && (mut = mv.get_mutation(i++)))
{
single_mutation_rec(mut, mutations, opts, n, m - 1);
mut->destroy();
}
}
}
void
replace_ap_rec(const formula* f, fset_t& mutations, unsigned opts,
int& n, unsigned m)
{
if (m == 0)
{
if (mutations.insert(f).second)
{
f->clone();
--n;
}
}
else
{
const formula* mut;
replace_visitor rv;
std::unique_ptr<atomic_prop_set> aps =
std::unique_ptr<atomic_prop_set>(atomic_prop_collect(f));
atomic_prop_set::iterator ap1;
atomic_prop_set::iterator ap2;
for (ap1 = aps->begin(); ap1 != aps->end() && n > 0; ++ap1)
for (ap2 = aps->begin(); ap2 != aps->end() && n > 0; ++ap2)
{
if (ap1 == ap2)
continue;
mut = rv.replace(f, ap1, ap2);
replace_ap_rec(mut, mutations, opts, n, m - 1);
mut->destroy();
}
}
}
}
vec get_mutations(const formula* f,
unsigned opts,
bool sort,
int n,
unsigned m)
{
fset_t mutations;
single_mutation_rec(f, mutations, opts, n, m);
if (opts & MUT_REMOVE_ONE_AP)
replace_ap_rec(f, mutations, opts, n, m);
vec res(mutations.begin(), mutations.end());
if (sort)
std::sort(res.begin(), res.end(), formula_length_less_than);
return res;
}
}
}

52
src/ltlvisit/mutation.hh Normal file
View file

@ -0,0 +1,52 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2003, 2004 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/>.
#ifndef SPOT_LTLVISIT_MUTATION_HH
# define SPOT_LTLVISIT_MUTATION_HH
#include "ltlast/formula.hh"
#include <limits>
#include <set>
#include <vector>
#define MUT_AP2CONST 0x1
#define MUT_SIMPLIFY_BOUNDS 0x2
#define MUT_REMOVE_MULTOP_OPERANDS 0x4
#define MUT_REMOVE_OPS 0x8
#define MUT_SPLIT_OPS 0x10
#define MUT_REWRITE_OPS 0x20
#define MUT_REMOVE_ONE_AP 0x40
namespace spot
{
namespace ltl
{
typedef std::vector<const formula*> vec;
SPOT_API
vec get_mutations(const formula*,
unsigned opts = 0xfff,
bool sort = true,
int n = std::numeric_limits<int>::max(),
unsigned m = 1);
}
}
#endif