Commit 51a3cfce authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

product: add a product_or variant

* src/twaalgos/product.cc, src/twaalgos/product.hh: Implement
the variance.
* src/bin/autfilt.cc: Expose it.
* src/tests/prodor.test: New file.
* src/tests/Makefile.am: Add it.
* NEWS: Mention it.
parent b77f7e24
...@@ -5,6 +5,16 @@ New in spot 1.99.3a (not yet released) ...@@ -5,6 +5,16 @@ New in spot 1.99.3a (not yet released)
exactly one acceptance sets. This is useful when targeting parity exactly one acceptance sets. This is useful when targeting parity
acceptance. acceptance.
* autfilt has a new --product-or option. This builds a synchronized
product of two (completed of needed) automata in order to
recognize the *sum* of their languages. This works by just using
the disjunction of their acceptance conditions (with appropriate
renumbering of the acceptance sets).
For consistency, the --product option (that builds a synchronized
product that recognizes the *intersection* of the languages) now
also has a --product-and alias.
* the parser for ltl2dstar's format has been merged with the parser * the parser for ltl2dstar's format has been merged with the parser
for the other automata formats. This implies two things: for the other automata formats. This implies two things:
- autfilt and dstar2tgba (despite its name) can now both read - autfilt and dstar2tgba (despite its name) can now both read
...@@ -18,20 +28,18 @@ New in spot 1.99.3a (not yet released) ...@@ -18,20 +28,18 @@ New in spot 1.99.3a (not yet released)
* The class hierarchy for temporal formulas has been entirely * The class hierarchy for temporal formulas has been entirely
rewritten. This change is actually quite massive (~13200 lines rewritten. This change is actually quite massive (~13200 lines
removed, ~8200 lines added), and brings some nice benefits: removed, ~8200 lines added), and brings some nice benefits:
- LTL/PSL formulas are now represented by lightweight - LTL/PSL formulas are now represented by lightweight ltl::formula
ltl::formula objects (instead of ltl::formula* pointers) objects (instead of ltl::formula* pointers) that perform
that perform reference counting automatically. reference counting automatically.
- There is no hierachy anymore: all operators are represented - There is no hierachy anymore: all operators are represented by a
by a single type of node in the syntax tree, and an single type of node in the syntax tree, and an enumerator is
enumerator is used to distinguish between operators. used to distinguish between operators.
- Visitors have been replaced by member functions such - Visitors have been replaced by member functions such as map() or
as map() or traverse(), that take a function (usually traverse(), that take a function (usually written as a lambda
written as a lambda function) and apply it to the function) and apply it to the nodes of the tree.
nodes of the tree. - As a consequence, writing algorithms that manipulate formula is
- As a consequence, writing algorithms that manipulate more friendly, and several algorithms that spanned a few pages
formula is more friendly, and several functions have been reduced to a few lines.
algorithms that spanned a few pages have been
reduced to a few lines.
New in spot 1.99.3 (2015-08-26) New in spot 1.99.3 (2015-08-26)
......
...@@ -85,7 +85,8 @@ enum { ...@@ -85,7 +85,8 @@ enum {
OPT_KEEP_STATES, OPT_KEEP_STATES,
OPT_MASK_ACC, OPT_MASK_ACC,
OPT_MERGE, OPT_MERGE,
OPT_PRODUCT, OPT_PRODUCT_AND,
OPT_PRODUCT_OR,
OPT_RANDOMIZE, OPT_RANDOMIZE,
OPT_REM_AP, OPT_REM_AP,
OPT_REM_DEAD, OPT_REM_DEAD,
...@@ -122,8 +123,13 @@ static const argp_option options[] = ...@@ -122,8 +123,13 @@ static const argp_option options[] =
{ 0, 0, 0, 0, "Transformations:", 5 }, { 0, 0, 0, 0, "Transformations:", 5 },
{ "merge-transitions", OPT_MERGE, 0, 0, { "merge-transitions", OPT_MERGE, 0, 0,
"merge transitions with same destination and acceptance", 0 }, "merge transitions with same destination and acceptance", 0 },
{ "product", OPT_PRODUCT, "FILENAME", 0, { "product", OPT_PRODUCT_AND, "FILENAME", 0,
"build the product with the automaton in FILENAME", 0 }, "build the product with the automaton in FILENAME "
"to intersect languages", 0 },
{ "product-and", 0, 0, OPTION_ALIAS, 0, 0 },
{ "product-or", OPT_PRODUCT_OR, "FILENAME", 0,
"build the product with the automaton in FILENAME "
"to sum languages", 0 },
{ "randomize", OPT_RANDOMIZE, "s|t", OPTION_ARG_OPTIONAL, { "randomize", OPT_RANDOMIZE, "s|t", OPTION_ARG_OPTIONAL,
"randomize states and transitions (specify 's' or 't' to " "randomize states and transitions (specify 's' or 't' to "
"randomize only states or transitions)", 0 }, "randomize only states or transitions)", 0 },
...@@ -231,7 +237,8 @@ static int opt_seed = 0; ...@@ -231,7 +237,8 @@ static int opt_seed = 0;
static struct opt_t static struct opt_t
{ {
spot::bdd_dict_ptr dict = spot::make_bdd_dict(); spot::bdd_dict_ptr dict = spot::make_bdd_dict();
spot::twa_graph_ptr product = nullptr; spot::twa_graph_ptr product_and = nullptr;
spot::twa_graph_ptr product_or = nullptr;
spot::twa_graph_ptr intersect = nullptr; spot::twa_graph_ptr intersect = nullptr;
spot::twa_graph_ptr are_isomorphic = nullptr; spot::twa_graph_ptr are_isomorphic = nullptr;
std::unique_ptr<spot::isomorphism_checker> std::unique_ptr<spot::isomorphism_checker>
...@@ -393,14 +400,24 @@ parse_opt(int key, char* arg, struct argp_state*) ...@@ -393,14 +400,24 @@ parse_opt(int key, char* arg, struct argp_state*)
opt_rem_unreach = true; opt_rem_unreach = true;
break; break;
} }
case OPT_PRODUCT: case OPT_PRODUCT_AND:
{ {
auto a = read_automaton(arg, opt->dict); auto a = read_automaton(arg, opt->dict);
if (!opt->product) if (!opt->product_and)
opt->product = std::move(a); opt->product_and = std::move(a);
else else
opt->product = spot::product(std::move(opt->product), opt->product_and = spot::product(std::move(opt->product_and),
std::move(a)); std::move(a));
}
break;
case OPT_PRODUCT_OR:
{
auto a = read_automaton(arg, opt->dict);
if (!opt->product_or)
opt->product_or = std::move(a);
else
opt->product_or = spot::product_or(std::move(opt->product_or),
std::move(a));
} }
break; break;
case OPT_RANDOMIZE: case OPT_RANDOMIZE:
...@@ -579,8 +596,10 @@ namespace ...@@ -579,8 +596,10 @@ namespace
else if (opt_rem_unreach) else if (opt_rem_unreach)
aut->purge_unreachable_states(); aut->purge_unreachable_states();
if (opt->product) if (opt->product_and)
aut = spot::product(std::move(aut), opt->product); aut = spot::product(std::move(aut), opt->product_and);
if (opt->product_or)
aut = spot::product_or(std::move(aut), opt->product_or);
if (opt_sat_minimize) if (opt_sat_minimize)
{ {
......
...@@ -181,6 +181,7 @@ TESTS_twa = \ ...@@ -181,6 +181,7 @@ TESTS_twa = \
ltldo2.test \ ltldo2.test \
maskacc.test \ maskacc.test \
maskkeep.test \ maskkeep.test \
prodor.test \
simdet.test \ simdet.test \
sim2.test \ sim2.test \
sim3.test \ sim3.test \
......
#!/bin/sh
# -*- coding: utf-8 -*-
# Copyright (C) 2015 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
ltl2tgba=../../bin/ltl2tgba
autfilt=../../bin/autfilt
$ltl2tgba -DH 'GFa' > gfa.hoa
$ltl2tgba -DH 'FGb' > fgb.hoa
$autfilt --product-or gfa.hoa fgb.hoa -H > por.hoa
cat por.hoa
cat >exp <<EOF
HOA: v1
States: 3
Start: 0
AP: 2 "a" "b"
Acceptance: 2 Inf(0) | Inf(1)
properties: trans-labels explicit-labels trans-acc complete
--BODY--
State: 0
[0&1] 1 {1}
[!0&1] 1
[0] 0 {1}
[!0] 0
State: 1
[0&1] 1 {0 1}
[!0&1] 1 {0}
[0&!1] 2 {0 1}
[!0&!1] 2 {0}
State: 2
[0] 2 {1}
[!0] 2
--END--
EOF
diff por.hoa exp
test 2 = `$autfilt -c --intersect por.hoa gfa.hoa fgb.hoa`
$autfilt --product-and gfa.hoa fgb.hoa -H > pand.hoa
cat pand.hoa
cat >exp <<EOF
HOA: v1
States: 2
Start: 0
AP: 2 "a" "b"
acc-name: generalized-Buchi 2
Acceptance: 2 Inf(0)&Inf(1)
properties: trans-labels explicit-labels trans-acc
--BODY--
State: 0
[0&1] 1 {1}
[!0&1] 1
[0] 0 {1}
[!0] 0
State: 1
[0&1] 1 {0 1}
[!0&1] 1 {0}
--END--
EOF
diff pand.hoa exp
test 2 = `$autfilt -c --intersect pand.hoa gfa.hoa fgb.hoa`
$ltl2tgba -BDH 'GFa' > gfa.hoa
$ltl2tgba -BDH 'Xb' > xb.hoa
$autfilt --product-or gfa.hoa xb.hoa -H > por.hoa
cat por.hoa
cat >exp <<EOF
HOA: v1
States: 7
Start: 0
AP: 2 "a" "b"
Acceptance: 2 Inf(0) | Inf(1)
properties: trans-labels explicit-labels state-acc complete
properties: deterministic
--BODY--
State: 0 {0 1}
[0] 1
[!0] 2
State: 1 {0 1}
[0&1] 3
[!0&1] 4
[0&!1] 5
[!0&!1] 6
State: 2 {0}
[0&1] 3
[!0&1] 4
[0&!1] 5
[!0&!1] 6
State: 3 {0 1}
[0] 3
[!0] 4
State: 4 {0}
[0] 3
[!0] 4
State: 5 {1}
[0] 5
[!0] 6
State: 6
[0] 5
[!0] 6
--END--
EOF
diff por.hoa exp
$ltl2tgba -BDH 'GFa' > gfa.hoa
$ltl2tgba -x '!wdba-minimize' -DH 'Xb' > xb.hoa
$autfilt --product-or gfa.hoa xb.hoa -H > por.hoa
cat por.hoa
cat >exp <<EOF
HOA: v1
States: 7
Start: 0
AP: 2 "a" "b"
Acceptance: 2 Inf(0) | Inf(1)
properties: trans-labels explicit-labels state-acc complete
properties: deterministic
--BODY--
State: 0 {0 1}
[0] 1
[!0] 2
State: 1 {0 1}
[0&1] 3
[!0&1] 4
[0&!1] 5
[!0&!1] 6
State: 2 {0}
[0&1] 3
[!0&1] 4
[0&!1] 5
[!0&!1] 6
State: 3 {0 1}
[0] 3
[!0] 4
State: 4 {0}
[0] 3
[!0] 4
State: 5 {1}
[0] 5
[!0] 6
State: 6
[0] 5
[!0] 6
--END--
EOF
diff por.hoa exp
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "product.hh" #include "product.hh"
#include "twa/twagraph.hh" #include "twa/twagraph.hh"
#include "twaalgos/complete.hh"
#include <deque> #include <deque>
#include <unordered_map> #include <unordered_map>
#include "misc/hash.hh" #include "misc/hash.hh"
...@@ -37,77 +38,115 @@ namespace spot ...@@ -37,77 +38,115 @@ namespace spot
return wang32_hash(s.first ^ wang32_hash(s.second)); return wang32_hash(s.first ^ wang32_hash(s.second));
} }
}; };
}
static
twa_graph_ptr product_aux(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state,
bool and_acc)
{
std::unordered_map<product_state, unsigned, product_state_hash> s2n;
std::deque<std::pair<product_state, unsigned>> todo;
twa_graph_ptr product(const const_twa_graph_ptr& left, assert(left->get_dict() == right->get_dict());
const const_twa_graph_ptr& right, auto res = make_twa_graph(left->get_dict());
unsigned left_state, res->copy_ap_of(left);
unsigned right_state) res->copy_ap_of(right);
{ auto left_num = left->num_sets();
std::unordered_map<product_state, unsigned, product_state_hash> s2n; auto right_acc = right->get_acceptance();
std::deque<std::pair<product_state, unsigned>> todo; right_acc.shift_left(left_num);
if (and_acc)
right_acc.append_and(left->get_acceptance());
else
right_acc.append_or(acc_cond::acc_code(left->get_acceptance()));
res->set_acceptance(left_num + right->num_sets(), right_acc);
assert(left->get_dict() == right->get_dict()); auto v = new product_states;
auto res = make_twa_graph(left->get_dict()); res->set_named_prop("product-states", v);
res->copy_ap_of(left);
res->copy_ap_of(right);
auto left_num = left->num_sets();
auto right_acc = right->get_acceptance();
right_acc.shift_left(left_num);
right_acc.append_and(left->get_acceptance());
res->set_acceptance(left_num + right->num_sets(), right_acc);
auto v = new product_states; auto new_state =
res->set_named_prop("product-states", v); [&](unsigned left_state, unsigned right_state) -> unsigned
{
product_state x(left_state, right_state);
auto p = s2n.emplace(x, 0);
if (p.second) // This is a new state
{
p.first->second = res->new_state();
todo.emplace_back(x, p.first->second);
assert(p.first->second == v->size());
v->push_back(x);
}
return p.first->second;
};
auto new_state = res->set_init_state(new_state(left_state, right_state));
[&](unsigned left_state, unsigned right_state) -> unsigned if (right_acc.is_false())
{ // Do not bother doing any work if the resulting acceptance is
product_state x(left_state, right_state); // false.
auto p = s2n.emplace(x, 0); return res;
if (p.second) // This is a new state while (!todo.empty())
{ {
p.first->second = res->new_state(); auto top = todo.front();
todo.emplace_back(x, p.first->second); todo.pop_front();
assert(p.first->second == v->size()); for (auto& l: left->out(top.first.first))
v->push_back(x); for (auto& r: right->out(top.first.second))
} {
return p.first->second; auto cond = l.cond & r.cond;
}; if (cond == bddfalse)
continue;
auto dst = new_state(l.dst, r.dst);
res->new_edge(top.second, dst, cond,
res->acc().join(left->acc(), l.acc,
right->acc(), r.acc));
// If right is deterministic, we can abort immediately!
}
}
res->set_init_state(new_state(left_state, right_state)); res->prop_deterministic(left->is_deterministic()
if (right_acc.is_false()) && right->is_deterministic());
// Do not bother doing any work if the resulting acceptance is res->prop_stutter_invariant(left->is_stutter_invariant()
// false. && right->is_stutter_invariant());
res->prop_stutter_sensitive(left->is_stutter_sensitive()
&& right->is_stutter_sensitive());
res->prop_state_based_acc(left->has_state_based_acc()
&& right->has_state_based_acc());
return res; return res;
while (!todo.empty()) }
{ }
auto top = todo.front();
todo.pop_front();
for (auto& l: left->out(top.first.first))
for (auto& r: right->out(top.first.second))
{
auto cond = l.cond & r.cond;
if (cond == bddfalse)
continue;
auto dst = new_state(l.dst, r.dst);
res->new_edge(top.second, dst, cond,
res->acc().join(left->acc(), l.acc,
right->acc(), r.acc));
// If right is deterministic, we can abort immediately!
}
}
return res; twa_graph_ptr product(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state)
{
return product_aux(left, right, left_state, right_state, true);
} }
twa_graph_ptr product(const const_twa_graph_ptr& left, twa_graph_ptr product(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right) const const_twa_graph_ptr& right)
{ {
return product(left, right, return product(left, right,
left->get_init_state_number(), left->get_init_state_number(),
right->get_init_state_number()); right->get_init_state_number());
} }
twa_graph_ptr product_or(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state)
{
return product_aux(tgba_complete(left),
tgba_complete(right),
left_state, right_state, false);
}
twa_graph_ptr product_or(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right)
{
return product_or(left, right,
left->get_init_state_number(),
right->get_init_state_number());
}
} }
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2014 Laboratoire de Recherche et // Copyright (C) 2014, 2015 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.
...@@ -32,11 +32,22 @@ namespace spot ...@@ -32,11 +32,22 @@ namespace spot
SPOT_API SPOT_API
twa_graph_ptr product(const const_twa_graph_ptr& left, twa_graph_ptr product(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right); const const_twa_graph_ptr& right);
SPOT_API SPOT_API
twa_graph_ptr product(const const_twa_graph_ptr& left, twa_graph_ptr product(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right,
unsigned left_state,
unsigned right_state);
SPOT_API
twa_graph_ptr product_or(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right);
SPOT_API
twa_graph_ptr product_or(const const_twa_graph_ptr& left,
const const_twa_graph_ptr& right, const const_twa_graph_ptr& right,
unsigned left_state, unsigned left_state,
unsigned right_state); unsigned right_state);
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment