remfin: Make removing of fins more modular.
* spot/twaalgos/remfin.cc: Refactore remove_fin implementation. Enable filtering of strategies used for fin removing. * spot/priv/enumflags.hh: Add support for enum flags from brick-types. * spot/priv/Makefile.am: Add enumflags.hh to make. * debian/copyright: Update copyright with bricks library license.
This commit is contained in:
parent
4f8a8f7305
commit
784681d833
4 changed files with 458 additions and 268 deletions
16
debian/copyright
vendored
16
debian/copyright
vendored
|
|
@ -183,3 +183,19 @@ License: MIT style
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
IN THE SOFTWARE.
|
IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Files: spot/priv/enumflags.hh
|
||||||
|
Copyright: 2006, 2014 Petr Ročkai <me@mornfall.net>
|
||||||
|
2013-2015 Vladimír Štill <xstill@fi.muni.cz>
|
||||||
|
License: ICS License
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ libpriv_la_SOURCES = \
|
||||||
accmap.hh \
|
accmap.hh \
|
||||||
bddalloc.cc \
|
bddalloc.cc \
|
||||||
bddalloc.hh \
|
bddalloc.hh \
|
||||||
|
enumflags.hh \
|
||||||
freelist.cc \
|
freelist.cc \
|
||||||
freelist.hh \
|
freelist.hh \
|
||||||
satcommon.hh\
|
satcommon.hh\
|
||||||
|
|
|
||||||
117
spot/priv/enumflags.hh
Normal file
117
spot/priv/enumflags.hh
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
// -*- coding: utf-8 -*-
|
||||||
|
// Copyright (C) 2006, 2014 Petr Ročkai <me@mornfall.net>
|
||||||
|
// Copyright (C) 2013-2015 Vladimír Štill <xstill@fi.muni.cz>
|
||||||
|
// Copyright (C) 2017 Henrich Lauko <xlauko@mail.muni.cz>
|
||||||
|
//
|
||||||
|
// This file is a modification of brick-types file from brick library.
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace spot
|
||||||
|
{
|
||||||
|
template<typename E>
|
||||||
|
using is_enum_class = std::integral_constant<bool,
|
||||||
|
std::is_enum<E>::value && !std::is_convertible<E, int>::value>;
|
||||||
|
|
||||||
|
template<typename self>
|
||||||
|
struct strong_enum_flags {
|
||||||
|
static_assert(is_enum_class<self>::value, "Not an enum class.");
|
||||||
|
using type = strong_enum_flags<self>;
|
||||||
|
using underlying_type = typename std::underlying_type<self>::type;
|
||||||
|
|
||||||
|
constexpr strong_enum_flags() noexcept : store(0) {}
|
||||||
|
constexpr strong_enum_flags(self flag) noexcept :
|
||||||
|
store(static_cast<underlying_type>(flag))
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit constexpr strong_enum_flags(underlying_type st) noexcept
|
||||||
|
: store(st) {}
|
||||||
|
|
||||||
|
constexpr explicit operator underlying_type() const noexcept
|
||||||
|
{
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
type &operator|=(type o) noexcept
|
||||||
|
{
|
||||||
|
store |= o.store;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
type &operator&=(type o) noexcept
|
||||||
|
{
|
||||||
|
store &= o.store;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
type &operator^=(type o) noexcept
|
||||||
|
{
|
||||||
|
store ^= o.store;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr type operator~(type a)
|
||||||
|
{
|
||||||
|
return type(~a.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr type operator|(type a, type b) noexcept
|
||||||
|
{
|
||||||
|
return type(a.store | b.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr type operator&(type a, type b) noexcept
|
||||||
|
{
|
||||||
|
return type(a.store & b.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr type operator^(type a, type b) noexcept
|
||||||
|
{
|
||||||
|
return type(a.store ^ b.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator==(type a, type b) noexcept
|
||||||
|
{
|
||||||
|
return a.store == b.store;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator!=(type a, type b) noexcept
|
||||||
|
{
|
||||||
|
return a.store != b.store;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
constexpr bool has(self x) const noexcept
|
||||||
|
{
|
||||||
|
return ((*this) &x);
|
||||||
|
}
|
||||||
|
|
||||||
|
type clear(self x) noexcept
|
||||||
|
{
|
||||||
|
store &= ~underlying_type(x);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit constexpr operator bool() const noexcept
|
||||||
|
{
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
underlying_type store;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include <spot/twaalgos/isdet.hh>
|
#include <spot/twaalgos/isdet.hh>
|
||||||
#include <spot/twaalgos/mask.hh>
|
#include <spot/twaalgos/mask.hh>
|
||||||
#include <spot/twaalgos/alternation.hh>
|
#include <spot/twaalgos/alternation.hh>
|
||||||
|
#include "spot/priv/enumflags.hh"
|
||||||
|
|
||||||
//#define TRACE
|
//#define TRACE
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
|
|
@ -418,98 +419,41 @@ namespace spot
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
twa_graph_ptr trivial_strategy(const const_twa_graph_ptr& aut)
|
||||||
|
{
|
||||||
|
return (!aut->acc().uses_fin_acceptance())
|
||||||
|
? std::const_pointer_cast<twa_graph>(aut)
|
||||||
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
twa_graph_ptr
|
twa_graph_ptr weak_strategy(const const_twa_graph_ptr& aut)
|
||||||
rabin_to_buchi_maybe(const const_twa_graph_ptr& aut)
|
|
||||||
{
|
{
|
||||||
if (!aut->prop_state_acc().is_true())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
auto code = aut->get_acceptance();
|
|
||||||
|
|
||||||
if (code.is_t())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
acc_cond::mark_t inf_pairs = 0U;
|
|
||||||
acc_cond::mark_t inf_alone = 0U;
|
|
||||||
acc_cond::mark_t fin_alone = 0U;
|
|
||||||
|
|
||||||
auto s = code.back().sub.size;
|
|
||||||
|
|
||||||
// Rabin 1
|
|
||||||
if (code.back().sub.op == acc_cond::acc_op::And && s == 4)
|
|
||||||
goto start_and;
|
|
||||||
// Co-Büchi
|
|
||||||
else if (code.back().sub.op == acc_cond::acc_op::Fin && s == 1)
|
|
||||||
goto start_fin;
|
|
||||||
// Rabin >1
|
|
||||||
else if (code.back().sub.op != acc_cond::acc_op::Or)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
while (s)
|
|
||||||
{
|
|
||||||
--s;
|
|
||||||
if (code[s].sub.op == acc_cond::acc_op::And)
|
|
||||||
{
|
|
||||||
start_and:
|
|
||||||
auto o1 = code[--s].sub.op;
|
|
||||||
auto m1 = code[--s].mark;
|
|
||||||
auto o2 = code[--s].sub.op;
|
|
||||||
auto m2 = code[--s].mark;
|
|
||||||
// We expect
|
|
||||||
// Fin({n}) & Inf({n+1})
|
|
||||||
if (o1 != acc_cond::acc_op::Fin ||
|
|
||||||
o2 != acc_cond::acc_op::Inf ||
|
|
||||||
m1.count() != 1 ||
|
|
||||||
m2.count() != 1 ||
|
|
||||||
m2 != (m1 << 1U))
|
|
||||||
return nullptr;
|
|
||||||
inf_pairs |= m2;
|
|
||||||
}
|
|
||||||
else if (code[s].sub.op == acc_cond::acc_op::Fin)
|
|
||||||
{
|
|
||||||
start_fin:
|
|
||||||
fin_alone |= code[--s].mark;
|
|
||||||
}
|
|
||||||
else if (code[s].sub.op == acc_cond::acc_op::Inf)
|
|
||||||
{
|
|
||||||
auto m1 = code[--s].mark;
|
|
||||||
if (m1.count() != 1)
|
|
||||||
return nullptr;
|
|
||||||
inf_alone |= m1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trace << "inf_pairs: " << inf_pairs << '\n';
|
|
||||||
trace << "inf_alone: " << inf_alone << '\n';
|
|
||||||
trace << "fin_alone: " << fin_alone << '\n';
|
|
||||||
return ra_to_ba(aut, inf_pairs, inf_alone, fin_alone);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
twa_graph_ptr remove_fin(const const_twa_graph_ptr& aut)
|
|
||||||
{
|
|
||||||
if (!aut->acc().uses_fin_acceptance())
|
|
||||||
return std::const_pointer_cast<twa_graph>(aut);
|
|
||||||
|
|
||||||
// FIXME: we should check whether the automaton is inherently weak.
|
// FIXME: we should check whether the automaton is inherently weak.
|
||||||
if (aut->prop_weak().is_true())
|
return (aut->prop_weak().is_true())
|
||||||
return remove_fin_weak(aut);
|
? remove_fin_weak(aut)
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!aut->is_existential())
|
twa_graph_ptr alternation_strategy(const const_twa_graph_ptr& aut)
|
||||||
return remove_fin(remove_alternation(aut));
|
{
|
||||||
|
return (!aut->is_existential())
|
||||||
|
? remove_fin(remove_alternation(aut))
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto maybe = streett_to_generalized_buchi_maybe(aut))
|
twa_graph_ptr street_strategy(const const_twa_graph_ptr& aut)
|
||||||
return maybe;
|
{
|
||||||
|
return streett_to_generalized_buchi_maybe(aut);
|
||||||
|
}
|
||||||
|
|
||||||
if (auto maybe = rabin_to_buchi_maybe(aut))
|
twa_graph_ptr rabin_strategy(const const_twa_graph_ptr& aut)
|
||||||
return maybe;
|
{
|
||||||
|
return rabin_to_buchi_maybe(aut);
|
||||||
|
}
|
||||||
|
|
||||||
|
twa_graph_ptr default_strategy(const const_twa_graph_ptr& aut)
|
||||||
|
{
|
||||||
{
|
{
|
||||||
// We want a clean acceptance condition, i.e., one where all
|
// We want a clean acceptance condition, i.e., one where all
|
||||||
// sets are useful. If that is not the case, clean it first.
|
// sets are useful. If that is not the case, clean it first.
|
||||||
|
|
@ -699,7 +643,8 @@ namespace spot
|
||||||
{
|
{
|
||||||
intersects_fin = true;
|
intersects_fin = true;
|
||||||
}
|
}
|
||||||
trace << "main_sets " << main_sets << "\nmain_add " << main_add << '\n';
|
trace << "main_sets " << main_sets << "\nmain_add "
|
||||||
|
<< main_add << '\n';
|
||||||
|
|
||||||
// Create the main copy
|
// Create the main copy
|
||||||
for (auto s: states)
|
for (auto s: states)
|
||||||
|
|
@ -762,4 +707,115 @@ namespace spot
|
||||||
res->merge_edges();
|
res->merge_edges();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class strategy_t : unsigned
|
||||||
|
{
|
||||||
|
trivial = 0x01,
|
||||||
|
weak = 0x02,
|
||||||
|
alternation = 0x04,
|
||||||
|
street = 0x08,
|
||||||
|
rabin = 0x016
|
||||||
|
};
|
||||||
|
|
||||||
|
using strategy_flags = strong_enum_flags<strategy_t>;
|
||||||
|
using strategy =
|
||||||
|
std::function<twa_graph_ptr(const const_twa_graph_ptr& aut)>;
|
||||||
|
|
||||||
|
twa_graph_ptr remove_fin_impl(const const_twa_graph_ptr& aut,
|
||||||
|
const strategy_flags skip = {})
|
||||||
|
{
|
||||||
|
auto handle = [&](strategy stra, strategy_t type)
|
||||||
|
{
|
||||||
|
return (type & ~skip) ? stra(aut) : nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto maybe = handle(trivial_strategy, strategy_t::trivial))
|
||||||
|
return maybe;
|
||||||
|
if (auto maybe = handle(weak_strategy, strategy_t::weak))
|
||||||
|
return maybe;
|
||||||
|
if (auto maybe = handle(alternation_strategy, strategy_t::alternation))
|
||||||
|
return maybe;
|
||||||
|
if (auto maybe = handle(street_strategy, strategy_t::street))
|
||||||
|
return maybe;
|
||||||
|
if (auto maybe = handle(rabin_strategy, strategy_t::rabin))
|
||||||
|
return maybe;
|
||||||
|
return default_strategy(aut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
twa_graph_ptr
|
||||||
|
rabin_to_buchi_maybe(const const_twa_graph_ptr& aut)
|
||||||
|
{
|
||||||
|
if (!aut->prop_state_acc().is_true())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto code = aut->get_acceptance();
|
||||||
|
|
||||||
|
if (code.is_t())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
acc_cond::mark_t inf_pairs = 0U;
|
||||||
|
acc_cond::mark_t inf_alone = 0U;
|
||||||
|
acc_cond::mark_t fin_alone = 0U;
|
||||||
|
|
||||||
|
auto s = code.back().sub.size;
|
||||||
|
|
||||||
|
// Rabin 1
|
||||||
|
if (code.back().sub.op == acc_cond::acc_op::And && s == 4)
|
||||||
|
goto start_and;
|
||||||
|
// Co-Büchi
|
||||||
|
else if (code.back().sub.op == acc_cond::acc_op::Fin && s == 1)
|
||||||
|
goto start_fin;
|
||||||
|
// Rabin >1
|
||||||
|
else if (code.back().sub.op != acc_cond::acc_op::Or)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
while (s)
|
||||||
|
{
|
||||||
|
--s;
|
||||||
|
if (code[s].sub.op == acc_cond::acc_op::And)
|
||||||
|
{
|
||||||
|
start_and:
|
||||||
|
auto o1 = code[--s].sub.op;
|
||||||
|
auto m1 = code[--s].mark;
|
||||||
|
auto o2 = code[--s].sub.op;
|
||||||
|
auto m2 = code[--s].mark;
|
||||||
|
// We expect
|
||||||
|
// Fin({n}) & Inf({n+1})
|
||||||
|
if (o1 != acc_cond::acc_op::Fin ||
|
||||||
|
o2 != acc_cond::acc_op::Inf ||
|
||||||
|
m1.count() != 1 ||
|
||||||
|
m2.count() != 1 ||
|
||||||
|
m2 != (m1 << 1U))
|
||||||
|
return nullptr;
|
||||||
|
inf_pairs |= m2;
|
||||||
|
}
|
||||||
|
else if (code[s].sub.op == acc_cond::acc_op::Fin)
|
||||||
|
{
|
||||||
|
start_fin:
|
||||||
|
fin_alone |= code[--s].mark;
|
||||||
|
}
|
||||||
|
else if (code[s].sub.op == acc_cond::acc_op::Inf)
|
||||||
|
{
|
||||||
|
auto m1 = code[--s].mark;
|
||||||
|
if (m1.count() != 1)
|
||||||
|
return nullptr;
|
||||||
|
inf_alone |= m1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace << "inf_pairs: " << inf_pairs << '\n';
|
||||||
|
trace << "inf_alone: " << inf_alone << '\n';
|
||||||
|
trace << "fin_alone: " << fin_alone << '\n';
|
||||||
|
return ra_to_ba(aut, inf_pairs, inf_alone, fin_alone);
|
||||||
|
}
|
||||||
|
|
||||||
|
twa_graph_ptr remove_fin(const const_twa_graph_ptr& aut)
|
||||||
|
{
|
||||||
|
return remove_fin_impl(aut);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue