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:
Henrich Lauko 2017-05-31 00:58:41 +00:00 committed by Henrich Lauko
parent 4f8a8f7305
commit 784681d833
4 changed files with 458 additions and 268 deletions

16
debian/copyright vendored
View file

@ -183,3 +183,19 @@ License: MIT style
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
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.

View file

@ -25,6 +25,7 @@ libpriv_la_SOURCES = \
accmap.hh \
bddalloc.cc \
bddalloc.hh \
enumflags.hh \
freelist.cc \
freelist.hh \
satcommon.hh\

117
spot/priv/enumflags.hh Normal file
View 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;
};
}

View file

@ -25,6 +25,7 @@
#include <spot/twaalgos/isdet.hh>
#include <spot/twaalgos/mask.hh>
#include <spot/twaalgos/alternation.hh>
#include "spot/priv/enumflags.hh"
//#define TRACE
#ifdef TRACE
@ -418,98 +419,41 @@ namespace spot
}
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
rabin_to_buchi_maybe(const const_twa_graph_ptr& aut)
twa_graph_ptr weak_strategy(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.
if (aut->prop_weak().is_true())
return remove_fin_weak(aut);
return (aut->prop_weak().is_true())
? remove_fin_weak(aut)
: nullptr;
}
if (!aut->is_existential())
return remove_fin(remove_alternation(aut));
twa_graph_ptr alternation_strategy(const const_twa_graph_ptr& aut)
{
return (!aut->is_existential())
? remove_fin(remove_alternation(aut))
: nullptr;
}
if (auto maybe = streett_to_generalized_buchi_maybe(aut))
return maybe;
twa_graph_ptr street_strategy(const const_twa_graph_ptr& aut)
{
return streett_to_generalized_buchi_maybe(aut);
}
if (auto maybe = rabin_to_buchi_maybe(aut))
return maybe;
twa_graph_ptr rabin_strategy(const const_twa_graph_ptr& aut)
{
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
// sets are useful. If that is not the case, clean it first.
@ -699,7 +643,8 @@ namespace spot
{
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
for (auto s: states)
@ -762,4 +707,115 @@ namespace spot
res->merge_edges();
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);
}
}