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

Add a cleanup_acceptance() algorithm

* src/tgbaalgos/cleanacc.cc, src/tgbaalgos/cleanacc.hh: New file.
* src/tgbaalgos/Makefile.am: Add them.
* src/tgba/acc.hh, src/tgba/tgba.hh (get_acceptance): Return a
reference.
* src/bin/autfilt.cc: Add a --cleanup-acceptance option.
* src/tgbatest/hoaparse.test: Test it.
parent 85508a0e
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "tgbaalgos/sbacc.hh" #include "tgbaalgos/sbacc.hh"
#include "tgbaalgos/stripacc.hh" #include "tgbaalgos/stripacc.hh"
#include "tgbaalgos/remfin.hh" #include "tgbaalgos/remfin.hh"
#include "tgbaalgos/cleanacc.hh"
static const char argp_program_doc[] ="\ static const char argp_program_doc[] ="\
...@@ -82,6 +83,7 @@ Exit status:\n\ ...@@ -82,6 +83,7 @@ Exit status:\n\
#define OPT_KEEP_STATES 20 #define OPT_KEEP_STATES 20
#define OPT_DNF_ACC 21 #define OPT_DNF_ACC 21
#define OPT_REM_FIN 22 #define OPT_REM_FIN 22
#define OPT_CLEAN_ACC 23
static const argp_option options[] = static const argp_option options[] =
{ {
...@@ -125,6 +127,8 @@ static const argp_option options[] = ...@@ -125,6 +127,8 @@ static const argp_option options[] =
"put the acceptance condition in Disjunctive Normal Form", 0 }, "put the acceptance condition in Disjunctive Normal Form", 0 },
{ "remove-fin", OPT_REM_FIN, 0, 0, { "remove-fin", OPT_REM_FIN, 0, 0,
"rewrite the automaton without using Fin acceptance", 0 }, "rewrite the automaton without using Fin acceptance", 0 },
{ "cleanup-acceptance", OPT_CLEAN_ACC, 0, 0,
"remove unused acceptance sets from the automaton", 0 },
/**************************************************/ /**************************************************/
{ 0, 0, 0, 0, "Filtering options:", 6 }, { 0, 0, 0, 0, "Filtering options:", 6 },
{ "are-isomorphic", OPT_ARE_ISOMORPHIC, "FILENAME", 0, { "are-isomorphic", OPT_ARE_ISOMORPHIC, "FILENAME", 0,
...@@ -206,6 +210,7 @@ static bool opt_sbacc = false; ...@@ -206,6 +210,7 @@ static bool opt_sbacc = false;
static bool opt_stripacc = false; static bool opt_stripacc = false;
static bool opt_dnf_acc = false; static bool opt_dnf_acc = false;
static bool opt_rem_fin = false; static bool opt_rem_fin = false;
static bool opt_clean_acc = false;
static spot::acc_cond::mark_t opt_mask_acc = 0U; static spot::acc_cond::mark_t opt_mask_acc = 0U;
static std::vector<bool> opt_keep_states = {}; static std::vector<bool> opt_keep_states = {};
static unsigned int opt_keep_states_initial = 0; static unsigned int opt_keep_states_initial = 0;
...@@ -251,6 +256,9 @@ parse_opt(int key, char* arg, struct argp_state*) ...@@ -251,6 +256,9 @@ parse_opt(int key, char* arg, struct argp_state*)
case OPT_ARE_ISOMORPHIC: case OPT_ARE_ISOMORPHIC:
opt->are_isomorphic = read_automaton(arg, opt->dict); opt->are_isomorphic = read_automaton(arg, opt->dict);
break; break;
case OPT_CLEAN_ACC:
opt_clean_acc = true;
break;
case OPT_EDGES: case OPT_EDGES:
opt_edges = parse_range(arg, 0, std::numeric_limits<int>::max()); opt_edges = parse_range(arg, 0, std::numeric_limits<int>::max());
break; break;
...@@ -421,6 +429,8 @@ namespace ...@@ -421,6 +429,8 @@ namespace
if (opt_dnf_acc) if (opt_dnf_acc)
aut->set_acceptance(aut->acc().num_sets(), aut->set_acceptance(aut->acc().num_sets(),
aut->get_acceptance().to_dnf()); aut->get_acceptance().to_dnf());
if (opt_clean_acc && !opt_rem_fin)
cleanup_acceptance(aut);
if (opt_rem_fin) if (opt_rem_fin)
aut = remove_fin(aut); aut = remove_fin(aut);
......
...@@ -585,7 +585,7 @@ namespace spot ...@@ -585,7 +585,7 @@ namespace spot
uses_fin_acceptance_ = check_fin_acceptance(); uses_fin_acceptance_ = check_fin_acceptance();
} }
acc_code get_acceptance() const const acc_code& get_acceptance() const
{ {
return code_; return code_;
} }
......
...@@ -639,7 +639,7 @@ namespace spot ...@@ -639,7 +639,7 @@ namespace spot
acc_cond acc_; acc_cond acc_;
public: public:
acc_cond::acc_code get_acceptance() const const acc_cond::acc_code& get_acceptance() const
{ {
return acc_.get_acceptance(); return acc_.get_acceptance();
} }
......
...@@ -31,6 +31,7 @@ tgbaalgos_HEADERS = \ ...@@ -31,6 +31,7 @@ tgbaalgos_HEADERS = \
are_isomorphic.hh \ are_isomorphic.hh \
bfssteps.hh \ bfssteps.hh \
canonicalize.hh \ canonicalize.hh \
cleanacc.hh \
complete.hh \ complete.hh \
compsusp.hh \ compsusp.hh \
cycles.hh \ cycles.hh \
...@@ -84,6 +85,7 @@ libtgbaalgos_la_SOURCES = \ ...@@ -84,6 +85,7 @@ libtgbaalgos_la_SOURCES = \
are_isomorphic.cc \ are_isomorphic.cc \
bfssteps.cc \ bfssteps.cc \
canonicalize.cc \ canonicalize.cc \
cleanacc.cc \
complete.cc \ complete.cc \
compsusp.cc \ compsusp.cc \
cycles.cc \ cycles.cc \
......
// -*- coding: utf-8 -*-
// Copyright (C) 2015 Laboratoire de Recherche et Développement
// de l'Epita.
//
// 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 "tgbaalgos/cleanacc.hh"
namespace spot
{
namespace
{
acc_cond::acc_code strip(const acc_cond& acc,
const acc_cond::acc_word* pos,
acc_cond::mark_t useless)
{
auto start = pos - pos->size;
switch (pos->op)
{
case acc_cond::acc_op::And:
{
--pos;
acc_cond::acc_code res;
do
{
auto tmp = strip(acc, pos, useless);
tmp.append_and(std::move(res));
std::swap(tmp, res);
pos -= pos->size + 1;
}
while (pos > start);
return res;
}
case acc_cond::acc_op::Or:
{
--pos;
acc_cond::acc_code res = acc.fin(0); // f
do
{
auto tmp = strip(acc, pos, useless);
tmp.append_or(std::move(res));
std::swap(tmp, res);
pos -= pos->size + 1;
}
while (pos > start);
return res;
}
case acc_cond::acc_op::Fin:
if (pos[-1].mark & useless)
return acc.inf(0U); // t
return acc.fin(acc.strip(pos[-1].mark, useless));
case acc_cond::acc_op::Inf:
if (pos[-1].mark & useless)
return acc.fin(0U); // f
return acc.inf(acc.strip(pos[-1].mark, useless));
case acc_cond::acc_op::FinNeg:
case acc_cond::acc_op::InfNeg:
SPOT_UNREACHABLE();
return acc_cond::acc_code{};
}
SPOT_UNREACHABLE();
return acc_cond::acc_code{};
}
}
void cleanup_acceptance(tgba_digraph_ptr& aut)
{
auto& acc = aut->acc();
if (acc.num_sets() == 0)
return;
auto& c = aut->get_acceptance();
acc_cond::mark_t used_in_cond = 0U;
if (!c.is_true())
{
auto pos = &c.back();
auto end = &c.front();
while (pos > end)
{
switch (pos->op)
{
case acc_cond::acc_op::And:
case acc_cond::acc_op::Or:
--pos;
break;
case acc_cond::acc_op::Fin:
case acc_cond::acc_op::Inf:
case acc_cond::acc_op::FinNeg:
case acc_cond::acc_op::InfNeg:
used_in_cond |= pos[-1].mark;
pos -= 2;
break;
}
}
}
acc_cond::mark_t used_in_aut = 0U;
for (auto& t: aut->transitions())
used_in_aut |= t.acc;
auto useful = used_in_aut & used_in_cond;
auto useless = acc.comp(useful);
if (!useless)
return;
// Remove useless marks from the automaton
for (auto& t: aut->transitions())
t.acc = acc.strip(t.acc, useless);
// Remove useless marks from the acceptance condition
acc_cond::acc_code newc;
if (c.is_true() || c.is_false())
newc = c;
else
newc = strip(acc, &c.back(), useless);
aut->set_acceptance(useful.count(), newc);
}
}
// -*- coding: utf-8 -*-
// Copyright (C) 2015 Laboratoire de Recherche et Développement
// de l'Epita.
//
// 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_TGBAALGOS_CLEANACC_HH
# define SPOT_TGBAALGOS_CLEANACC_HH
#include "tgba/tgbagraph.hh"
namespace spot
{
/// \brief Remove useless acceptance sets
SPOT_API void
cleanup_acceptance(tgba_digraph_ptr& aut);
}
#endif // SPOT_TGBAALGOS_CLEANACC_HH
...@@ -1394,48 +1394,48 @@ State: 0 ...@@ -1394,48 +1394,48 @@ State: 0
EOF EOF
# FIXME: Test removal of useless acceptance sets # Test removal of useless acceptance sets
#
# # The mapping of acceptance sets for the second automaton is # The mapping of acceptance sets for the second automaton is
# # input -> output # input -> output
# # 0 -> 0 # 0 -> 0
# # 1 -> removed # 1 -> removed
# # 2 -> 1 # 2 -> 1
# # 3 -> removed # 3 -> removed
# # 4 -> 2 # 4 -> 2
# # !2 -> 3 # !2 -> 3
# expectok input <<EOF expectok input --cleanup-acc <<EOF
# HOA: v1 HOA: v1
# name: "TGBA for Fa" name: "TGBA for Fa"
# States: 2 States: 2
# Start: 0 Start: 0
# AP: 1 "a" AP: 1 "a"
# acc-name: all acc-name: all
# Acceptance: 0 t Acceptance: 0 t
# properties: trans-labels explicit-labels state-acc complete deterministic properties: trans-labels explicit-labels state-acc complete deterministic
# --BODY-- --BODY--
# State: 0 "F(a)" State: 0 "F(a)"
# [0] 1 [0] 1
# [!0] 0 [!0] 0
# State: 1 "t" State: 1 "t"
# [t] 1 [t] 1
# --END-- --END--
# HOA: v1 HOA: v1
# States: 1 States: 1
# Start: 0 Start: 0
# AP: 3 "a" "b" "c" AP: 3 "a" "b" "c"
# acc-name: generalized-Buchi 4 acc-name: generalized-Buchi 4
# Acceptance: 4 Inf(0)&Inf(1)&Inf(2)&Inf(3) Acceptance: 4 Inf(0)&Inf(1)&Inf(2)&Inf(3)
# properties: trans-labels explicit-labels trans-acc complete deterministic properties: trans-labels explicit-labels trans-acc complete deterministic
# --BODY-- --BODY--
# State: 0 State: 0
# [0&1&2] 0 {0 1 2} [0&1&2] 0 {0 1 2}
# [!0&1&2] 0 {1 2} [!0&1&2] 0 {1 2}
# [0&!1&2] 0 {0 1} [0&!1&2] 0 {0 1}
# [!0&!1&2] 0 {1} [!0&!1&2] 0 {1}
# [0&1&!2] 0 {0 2 3} [0&1&!2] 0 {0 2 3}
# [!0&1&!2] 0 {2 3} [!0&1&!2] 0 {2 3}
# [0&!1&!2] 0 {0 3} [0&!1&!2] 0 {0 3}
# [!0&!1&!2] 0 {3} [!0&!1&!2] 0 {3}
# --END-- --END--
# EOF EOF
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