Commit d4c9bf2b authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

* src/ltlvisit/contain.hh, src/ltlvisit/contain.cc (reduce_tau03):

New function, performing LTL reduction a la tauriainen.03.a83.
* src/ltltest/equals.cc, src/ltltest/reduc.cc: Add support for
the new reduction.
* src/ltltest/reduc.test: Cut the test in half, and additionally
test the new reduction.
* src/ltltest/reduccmp.test: Run on the new reduction.
* src/ltltest/Makefile.am: Adjust.
* src/tgbatest/ltl2tgba.cc: Add new options to apply the reduction.
* src/tgbatest/spotlbtt.test: Use them.
parent 8cbec952
2006-07-19 Alexandre Duret-Lutz <adl@src.lip6.fr> 2006-07-19 Alexandre Duret-Lutz <adl@src.lip6.fr>
* src/ltlvisit/contain.hh, src/ltlvisit/contain.cc (reduce_tau03):
New function, performing LTL reduction a la tauriainen.03.a83.
* src/ltltest/equals.cc, src/ltltest/reduc.cc: Add support for
the new reduction.
* src/ltltest/reduc.test: Cut the test in half, and additionally
test the new reduction.
* src/ltltest/reduccmp.test: Run on the new reduction.
* src/ltltest/Makefile.am: Adjust.
* src/tgbatest/ltl2tgba.cc: Add new options to apply the reduction.
* src/tgbatest/spotlbtt.test: Use them.
* src/tgba/tgbaproduct.cc: Fix computation of common acceptance * src/tgba/tgbaproduct.cc: Fix computation of common acceptance
conditions. conditions.
......
## Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6), ## Copyright (C) 2003, 2004, 2005, 2006 Laboratoire d'Informatique de
## dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre ## Paris 6 (LIP6), dpartement Systmes Rpartis Coopratifs (SRC),
## et Marie Curie. ## Universit Pierre et Marie Curie.
## ##
## This file is part of Spot, a model checking library. ## This file is part of Spot, a model checking library.
## ##
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
## 02111-1307, USA. ## 02111-1307, USA.
AM_CPPFLAGS = -I$(srcdir)/.. AM_CPPFLAGS = -I$(srcdir)/.. $(BUDDY_CPPFLAGS)
AM_CXXFLAGS = $(WARNING_CXXFLAGS) AM_CXXFLAGS = $(WARNING_CXXFLAGS)
LDADD = ../libspot.la LDADD = ../libspot.la
...@@ -33,6 +33,8 @@ check_PROGRAMS = \ ...@@ -33,6 +33,8 @@ check_PROGRAMS = \
nenoform \ nenoform \
reduc \ reduc \
reduccmp \ reduccmp \
reductau \
reductaustr \
syntimpl \ syntimpl \
tostring \ tostring \
tunabbrev \ tunabbrev \
...@@ -53,6 +55,10 @@ randltl_SOURCES = randltl.cc ...@@ -53,6 +55,10 @@ randltl_SOURCES = randltl.cc
reduc_SOURCES = reduc.cc reduc_SOURCES = reduc.cc
reduccmp_SOURCES = equals.cc reduccmp_SOURCES = equals.cc
reduccmp_CPPFLAGS = $(AM_CPPFLAGS) -DREDUC reduccmp_CPPFLAGS = $(AM_CPPFLAGS) -DREDUC
reductau_SOURCES = equals.cc
reductau_CPPFLAGS = $(AM_CPPFLAGS) -DREDUC_TAU
reductaustr_SOURCES = equals.cc
reductaustr_CPPFLAGS = $(AM_CPPFLAGS) -DREDUC_TAUSTR
syntimpl_SOURCES = syntimpl.cc syntimpl_SOURCES = syntimpl.cc
tostring_SOURCES = tostring.cc tostring_SOURCES = tostring.cc
tunabbrev_SOURCES = equals.cc tunabbrev_SOURCES = equals.cc
......
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6), // Copyright (C) 2003, 2004, 2006 Laboratoire d'Informatique de Paris 6 (LIP6),
// dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre // dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre
// et Marie Curie. // et Marie Curie.
// //
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "ltlvisit/dump.hh" #include "ltlvisit/dump.hh"
#include "ltlvisit/nenoform.hh" #include "ltlvisit/nenoform.hh"
#include "ltlvisit/destroy.hh" #include "ltlvisit/destroy.hh"
#include "ltlvisit/contain.hh"
#include "ltlast/allnodes.hh" #include "ltlast/allnodes.hh"
#include "ltlvisit/reduce.hh" #include "ltlvisit/reduce.hh"
#include "ltlvisit/tostring.hh" #include "ltlvisit/tostring.hh"
...@@ -96,6 +97,20 @@ main(int argc, char** argv) ...@@ -96,6 +97,20 @@ main(int argc, char** argv)
spot::ltl::destroy(tmp); spot::ltl::destroy(tmp);
spot::ltl::dump(std::cout, f1); spot::ltl::dump(std::cout, f1);
#endif #endif
#ifdef REDUC_TAU
spot::ltl::formula* tmp;
tmp = f1;
f1 = spot::ltl::reduce_tau03(f1, false);
spot::ltl::destroy(tmp);
spot::ltl::dump(std::cout, f1);
#endif
#ifdef REDUC_TAUSTR
spot::ltl::formula* tmp;
tmp = f1;
f1 = spot::ltl::reduce_tau03(f1, true);
spot::ltl::destroy(tmp);
spot::ltl::dump(std::cout, f1);
#endif
int exit_code = f1 != f2; int exit_code = f1 != f2;
......
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6), // Copyright (C) 2004, 2006 Laboratoire d'Informatique de Paris 6 (LIP6),
// dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre // dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre
// et Marie Curie. // et Marie Curie.
// //
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "ltlvisit/tostring.hh" #include "ltlvisit/tostring.hh"
#include "ltlvisit/reduce.hh" #include "ltlvisit/reduce.hh"
#include "ltlvisit/length.hh" #include "ltlvisit/length.hh"
#include "ltlvisit/contain.hh"
#include "ltlast/allnodes.hh" #include "ltlast/allnodes.hh"
void void
...@@ -42,6 +43,9 @@ syntax(char* prog) ...@@ -42,6 +43,9 @@ syntax(char* prog)
int int
main(int argc, char** argv) main(int argc, char** argv)
{ {
bool tau03 = false;
bool stronger = false;
if (argc < 3) if (argc < 3)
syntax(argv[0]); syntax(argv[0]);
...@@ -57,6 +61,9 @@ main(int argc, char** argv) ...@@ -57,6 +61,9 @@ main(int argc, char** argv)
case 2: case 2:
o = spot::ltl::Reduce_Eventuality_And_Universality; o = spot::ltl::Reduce_Eventuality_And_Universality;
break; break;
case 9:
tau03 = stronger = true;
/* fall through */
case 3: case 3:
o = spot::ltl::Reduce_All; o = spot::ltl::Reduce_All;
break; break;
...@@ -71,6 +78,12 @@ main(int argc, char** argv) ...@@ -71,6 +78,12 @@ main(int argc, char** argv)
o = (spot::ltl::Reduce_Syntactic_Implications o = (spot::ltl::Reduce_Syntactic_Implications
| spot::ltl::Reduce_Eventuality_And_Universality); | spot::ltl::Reduce_Eventuality_And_Universality);
break; break;
case 8:
stronger = true;
/* fall through */
case 7:
tau03 = true;
break;
default: default:
return 2; return 2;
} }
...@@ -114,6 +127,13 @@ main(int argc, char** argv) ...@@ -114,6 +127,13 @@ main(int argc, char** argv)
spot::ltl::destroy(ftmp1); spot::ltl::destroy(ftmp1);
spot::ltl::destroy(ftmp2); spot::ltl::destroy(ftmp2);
if (tau03)
{
ftmp1 = f1;
f1 = spot::ltl::reduce_tau03(f1, stronger);
spot::ltl::destroy(ftmp1);
}
int length_f1_after = spot::ltl::length(f1); int length_f1_after = spot::ltl::length(f1);
std::string f1s_after = spot::ltl::to_string(f1); std::string f1s_after = spot::ltl::to_string(f1);
......
#! /bin/sh #! /bin/sh
# Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6), # Copyright (C) 2004, 2005, 2006 Laboratoire d'Informatique de Paris 6 (LIP6),
# dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre # dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre
# et Marie Curie. # et Marie Curie.
# #
...@@ -28,12 +28,13 @@ set -e ...@@ -28,12 +28,13 @@ set -e
FILE=formulae FILE=formulae
: > $FILE : > $FILE
for i in 10 11 12 13 14 15 16 17 18 19 20; do # for i in 10 11 12 13 14 15 16 17 18 19 20; do
for i in 10 12 14 16 18 20; do
run 0 ./randltl -u -s 0 -f $i a b c -F 100 >> $FILE run 0 ./randltl -u -s 0 -f $i a b c -F 100 >> $FILE
run 0 ./randltl -u -s 100 -f $i a b c d e f -F 100 >> $FILE run 0 ./randltl -u -s 100 -f $i a b c d e f -F 100 >> $FILE
done done
for opt in 0 1 2 3; do for opt in 0 1 2 3 7 8 9; do
rm -f result.data rm -f result.data
cat $FILE | cat $FILE |
......
#! /bin/sh #! /bin/sh
# Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6), # Copyright (C) 2004, 2006 Laboratoire d'Informatique de Paris 6 (LIP6),
# dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre # dpartement Systmes Rpartis Coopratifs (SRC), Universit Pierre
# et Marie Curie. # et Marie Curie.
# #
...@@ -21,81 +21,87 @@ ...@@ -21,81 +21,87 @@
# 02111-1307, USA. # 02111-1307, USA.
# Check for the equals visitor # Check LTL reductions
. ./defs || exit 1 . ./defs || exit 1
# No reduction for x in ./reduccmp ./reductaustr; do
run 0 ./reduccmp 'a U b' 'a U b'
run 0 ./reduccmp 'a R b' 'a R b' # No reduction
run 0 ./reduccmp 'a & b' 'a & b' run 0 $x 'a U b' 'a U b'
run 0 ./reduccmp 'a | b' 'a | b' run 0 $x 'a R b' 'a R b'
run 0 ./reduccmp 'a & (a U b)' 'a & (a U b)' run 0 $x 'a & b' 'a & b'
run 0 ./reduccmp 'a | (a U b)' 'a | (a U b)' run 0 $x 'a | b' 'a | b'
run 0 $x 'a & (a U b)' 'a & (a U b)'
# Syntactic reduction run 0 $x 'a | (a U b)' 'a | (a U b)'
run 0 ./reduccmp 'a & (!b R !a)' 'false'
run 0 ./reduccmp '(!b R !a) & a' 'false' # Syntactic reduction
#run 0 ./reduccmp '(!b R !a) | a' 'true' run 0 $x 'a & (!b R !a)' 'false'
#run 0 ./reduccmp 'a | (!b R !a)' 'true' run 0 $x '(!b R !a) & a' 'false'
run 0 ./reduccmp 'a & (!b R !a) & c' 'false' run 0 $x 'a & (!b R !a) & c' 'false'
run 0 ./reduccmp 'c & (!b R !a) & a' 'false' run 0 $x 'c & (!b R !a) & a' 'false'
#run 0 ./reduccmp 'a | (!b R !a) | c' 'true'
#run 0 ./reduccmp 'c | (!b R !a) | a' 'true' run 0 $x 'a & (b U a)' 'a'
run 0 $x '(b U a) & a' 'a'
run 0 ./reduccmp 'a & (b U a)' 'a' run 0 $x 'a | (b U a)' '(b U a)'
run 0 ./reduccmp '(b U a) & a' 'a' run 0 $x '(b U a) | a' '(b U a)'
run 0 ./reduccmp 'a | (b U a)' '(b U a)' run 0 $x 'a U (b U a)' '(b U a)'
run 0 ./reduccmp '(b U a) | a' '(b U a)'
run 0 ./reduccmp 'a U (b U a)' '(b U a)' run 0 $x 'a & (b U a) & a' 'a'
run 0 $x 'a & (b U a) & a' 'a'
run 0 ./reduccmp 'a & (b U a) & a' 'a' run 0 $x 'a | (b U a) | a' '(b U a)'
run 0 ./reduccmp 'a & (b U a) & a' 'a' run 0 $x 'a | (b U a) | a' '(b U a)'
run 0 ./reduccmp 'a | (b U a) | a' '(b U a)' run 0 $x 'a U (b U a)' '(b U a)'
run 0 ./reduccmp 'a | (b U a) | a' '(b U a)'
run 0 ./reduccmp 'a U (b U a)' '(b U a)'
# Basics reduction
run 0 $x 'X(true)' 'true'
# Basics reduction run 0 $x 'X(false)' 'false'
run 0 ./reduccmp 'X(true)' 'true' run 0 $x 'F(true)' 'true'
run 0 ./reduccmp 'X(false)' 'false' run 0 $x 'F(false)' 'false'
run 0 ./reduccmp 'F(true)' 'true' run 0 $x 'G(true)' 'true'
run 0 ./reduccmp 'F(false)' 'false' run 0 $x 'G(false)' 'false'
run 0 ./reduccmp 'G(true)' 'true'
run 0 ./reduccmp 'G(false)' 'false' run 0 $x 'XGF(f)' 'GF(f)'
case $x in
run 0 ./reduccmp 'XGF(f)' 'GF(f)' *tau*);;
run 0 ./reduccmp 'FX(a)' 'XF(a)' *)
run 0 ./reduccmp 'G(a R b)' 'G(b)' run 0 $x 'G(a R b)' 'G(b)'
run 0 ./reduccmp 'GX(a)' 'XG(a)'
run 0 $x 'FX(a)' 'XF(a)'
run 0 ./reduccmp 'X(a) U X(b)' 'X(a U b)' run 0 $x 'GX(a)' 'XG(a)'
run 0 ./reduccmp 'X(a) R X(b)' 'X(a R b)'
run 0 $x 'X(a) U X(b)' 'X(a U b)'
run 0 ./reduccmp 'Xa & Xb' 'X(a & b)' run 0 $x 'X(a) R X(b)' 'X(a R b)'
run 0 ./reduccmp '(a U b) & (c U b)' '(a & c) U b' run 0 $x 'Xa & Xb' 'X(a & b)'
run 0 ./reduccmp '(a R b) & (a R c)' 'a R (b & c)' run 0 $x 'Xa | Xb' 'X(a | b)'
run 0 ./reduccmp 'Xa | Xb' 'X(a | b)'
run 0 ./reduccmp '(a U b) | (a U c)' 'a U (b | c)' run 0 $x '(a U b) & (c U b)' '(a & c) U b'
run 0 ./reduccmp '(a R b) | (c R b)' '(a | c) R b' run 0 $x '(a R b) & (a R c)' 'a R (b & c)'
run 0 $x '(a U b) | (a U c)' 'a U (b | c)'
run 0 ./reduccmp 'X(a & GFb)' 'Xa & GFb' run 0 $x '(a R b) | (c R b)' '(a | c) R b'
run 0 ./reduccmp 'X(a | GFb)' 'Xa | GFb'
run 0 ./reduccmp 'F(a & GFb)' 'Fa & GFb' run 0 $x 'X(a & GFb)' 'Xa & GFb'
run 0 ./reduccmp 'G(a | GFb)' 'Ga | GFb' run 0 $x 'X(a | GFb)' 'Xa | GFb'
run 0 $x 'F(a & GFb)' 'Fa & GFb'
run 0 ./reduccmp 'X(a & GFb & c)' 'X(a & c) & GFb' run 0 $x 'G(a | GFb)' 'Ga | GFb'
run 0 ./reduccmp 'X(a | GFb | c)' 'X(a | c) | GFb'
run 0 ./reduccmp 'F(a & GFb & c)' 'F(a & c) & GFb' run 0 $x 'X(a & GFb & c)' 'X(a & c) & GFb'
run 0 ./reduccmp 'G(a | GFb | c)' 'G(a | c) | GFb' run 0 $x 'X(a | GFb | c)' 'X(a | c) | GFb'
run 0 $x 'F(a & GFb & c)' 'F(a & c) & GFb'
# Eventuality and universality class reduction run 0 $x 'G(a | GFb | c)' 'G(a | c) | GFb'
run 0 ./reduccmp 'FFa' 'Fa' ;;
run 0 ./reduccmp 'FGFa' 'GFa' esac
run 0 ./reduccmp 'b U Fa' 'Fa'
run 0 ./reduccmp 'b U GFa' 'GFa' # Eventuality and universality class reduction
run 0 ./reduccmp 'Ga' 'Ga' run 0 $x 'FFa' 'Fa'
run 0 ./reduccmp 'GFGa' 'FGa' run 0 $x 'FGFa' 'GFa'
run 0 ./reduccmp 'b R Ga' 'Ga' run 0 $x 'b U Fa' 'Fa'
run 0 ./reduccmp 'b R FGa' 'FGa' run 0 $x 'b U GFa' 'GFa'
run 0 $x 'Ga' 'Ga'
run 0 $x 'GFGa' 'FGa'
run 0 $x 'b R Ga' 'Ga'
run 0 $x 'b R FGa' 'FGa'
done
...@@ -22,10 +22,16 @@ ...@@ -22,10 +22,16 @@
#include "contain.hh" #include "contain.hh"
#include "destroy.hh" #include "destroy.hh"
#include "clone.hh" #include "clone.hh"
#include "tunabbrev.hh"
#include "ltlast/unop.hh" #include "ltlast/unop.hh"
#include "ltlast/binop.hh"
#include "ltlast/multop.hh"
#include "ltlast/constant.hh"
#include "tgba/tgbaproduct.hh" #include "tgba/tgbaproduct.hh"
#include "tgbaalgos/gtec/gtec.hh" #include "tgbaalgos/gtec/gtec.hh"
#include "tgbaalgos/save.hh"
#include "tostring.hh"
#include <iostream>
namespace spot namespace spot
{ {
namespace ltl namespace ltl
...@@ -64,6 +70,32 @@ namespace spot ...@@ -64,6 +70,32 @@ namespace spot
return res; return res;
} }
// Check whether L(!l) is a subset of L(g).
bool
language_containment_checker::neg_contained(const formula* l,
const formula* g)
{
const formula* nl = unop::instance(unop::Not, clone(l));
const record_* rnl = register_formula_(nl);
const formula* ng = unop::instance(unop::Not, clone(g));
const record_* rng = register_formula_(ng);
destroy(nl);
destroy(ng);
bool res = rnl->incompatible.find(rng) != rnl->incompatible.end();
return res;
}
// Check whether L(l) is a subset of L(!g).
bool
language_containment_checker::contained_neg(const formula* l,
const formula* g)
{
const record_* rl = register_formula_(l);
const record_* rg = register_formula_(g);
bool res = rl->incompatible.find(rg) != rl->incompatible.end();
return res;
}
// Check whether L(l) = L(g). // Check whether L(l) = L(g).
bool bool
language_containment_checker::equal(const formula* l, const formula* g) language_containment_checker::equal(const formula* l, const formula* g)
...@@ -105,5 +137,217 @@ namespace spot ...@@ -105,5 +137,217 @@ namespace spot
} }
return &r; return &r;
} }
namespace {
struct reduce_tau03_visitor : public clone_visitor {
bool stronger;
language_containment_checker* lcc;
reduce_tau03_visitor(bool stronger,
language_containment_checker* lcc)
: stronger(stronger), lcc(lcc)
{
}
void
visit(unop* uo)
{
formula* a = recurse(uo->child());
switch (uo->op())
{
case unop::X:
// if X(a) = a, then keep only a !
if (stronger && lcc->equal(a, uo))
{
result_ = a;
break;
}
default:
result_ = unop::instance(uo->op(), a);
}
}
void
visit(binop* bo)
{
formula* a = recurse(bo->first());
formula* b = recurse(bo->second());
switch (bo->op())
{
case binop::U:
// if (a U b) = b, then keep b !
if (stronger && lcc->equal(bo, b))
{
destroy(a);
result_ = b;
}
// if a => b, then a U b = b.
else if ((!stronger) && lcc->contained(a, b))
{
destroy(a);
result_ = b;
}
// if !a => b, then a U b = Fb
else if (lcc->neg_contained(a, b))
{
destroy(a);
result_ = unop::instance(unop::F, b);
}
else
{
result_ = binop::instance(binop::U, a, b);
}
break;
case binop::R:
// if (a R b) = b, then keep b !
if (stronger && lcc->equal(bo, b))
{
destroy(a);
result_ = b;
}
// if b => a, then a R b = b.
else if ((!stronger) && lcc->contained(b, a))
{
destroy(a);
result_ = b;
}
// if a => !b, then a R b = Gb
else if (lcc->contained_neg(a, b))
{
destroy(a);
result_ = unop::instance(unop::G, b);
}
else
{
result_ = binop::instance(binop::R, a, b);
}
break;
default:
result_ = binop::instance(bo->op(), a, b);
}
}
void
visit(multop* mo)
{
multop::vec* res = new multop::vec;
unsigned mos = mo->size();
for (unsigned i = 0; i < mos; ++i)
res->push_back(recurse(mo->nth(i)));
result_ = 0;
bool changed = false;
switch (mo->op())
{
case multop::Or:
for (unsigned i = 0; i < mos; ++i)
{
if (!(*res)[i])
continue;
for (unsigned j = i + 1; j < mos; ++j)
{
if (!(*res)[j])
continue;
// if !i => j, then i|j = true
if (lcc->neg_contained((*res)[i], (*res)[j]))
{
result_ = constant::true_instance();
goto constant_;
}
// if i => j, then i|j = j
else if (lcc->contained((*res)[i], (*res)[j]))
{
destroy((*res)[i]);
(*res)[i] = 0;
changed = true;
break;
}
// if j => i, then i|j = i
else if (lcc->contained((*res)[i], (*res)[j]))
{
destroy((*res)[j]);
(*res)[j] = 0;
changed = true;
}
}
}
break;
case multop::And:
for (unsigned i = 0; i < mos; ++i)
{
if (!(*res)[i])
continue;
for (unsigned j = i + 1; j < mos; ++j)
{
if (!(*res)[j])
continue;
// if i => !j, then i&j = false
if (lcc->contained_neg((*res)[i], (*res)[j]))
{
result_ = constant::false_instance();
goto constant_;
}
// if i => j, then i&j = i
else if (lcc->contained((*res)[i], (*res)[j]))
{
destroy((*res)[j]);