diff --git a/spot/twaalgos/Makefile.am b/spot/twaalgos/Makefile.am index 02734f892..9ce9c2750 100644 --- a/spot/twaalgos/Makefile.am +++ b/spot/twaalgos/Makefile.am @@ -66,6 +66,7 @@ twaalgos_HEADERS = \ remfin.hh \ remprop.hh \ strength.hh \ + safra.hh \ sbacc.hh \ sccfilter.hh \ sccinfo.hh \ @@ -121,6 +122,7 @@ libtwaalgos_la_SOURCES = \ remprop.cc \ relabel.cc \ strength.cc \ + safra.cc \ sbacc.cc \ sccinfo.cc \ sccfilter.cc \ diff --git a/src/twaalgos/safra.cc b/src/twaalgos/safra.cc new file mode 100644 index 000000000..7a3d63a18 --- /dev/null +++ b/src/twaalgos/safra.cc @@ -0,0 +1,210 @@ +// -*- 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 . + +#include + +#include "safra.hh" + +namespace spot +{ + auto + safra_state::compute_succs(const const_twa_graph_ptr& aut) const -> succs_t + { + succs_t res; + // Given a bdd returns index of associated safra_state in res + std::map bdd2num; + for (auto& node: nodes_) + { + for (auto& t: aut->out(node.id_)) + { + auto i = bdd2num.insert(std::make_pair(t.cond, res.size())); + unsigned idx; + if (!i.second) + idx = i.first->second; + else + { + // Each new node starts out with same number of nodes as src + safra_state empty_state = safra_state(nb_braces_.size()); + idx = res.size(); + res.push_back(std::make_pair(empty_state, t.cond)); + std::cerr << "Created inner node: " << idx << std::endl; + } + safra_state& ss = res[idx].first; + ss.update_succ(node, t.dst, t.acc); + } + } + for (auto& s: res) + { + safra_state& tmp = s.first; + tmp.finalize_construction(); + } + return res; + } + + void safra_state::finalize_construction() + { + // TODO this is a dirty hack to have two comparision functions depending on + // wether or not we are still construction the safra_stata + // Ideally I'd like to have this done statically but not sure how to do it + for (unsigned i = 0; i < nb_braces_.size(); ++i) + { + if (nb_braces_[i] == 0) + { + // TODO We also emit Red = min(red, i) + is_green_[i] = false; + } + } + for (auto& n: nodes_) + { + node& nn = const_cast(n); + nn.disable_construction(); + } + } + + void safra_state::update_succ(const node& src, unsigned dst, + const acc_cond::mark_t acc) + { + (void) acc; // TODO + auto i = nodes_.find(node(dst)); + if (i != nodes_.end()) + { + // Todo need to handle acc and create new braces + if (src.braces_ > i->braces_) + { + std::cerr << "Replacing braces of: " << dst << std::endl; + node& dst = const_cast(*i); + for (auto b: dst.braces_) + nb_braces_[b]--; + dst.braces_ = src.braces_; + } + // Node already exists and has bigger values + else + return; + } + else + { + // Todo need to handle acc and create new braces + nodes_.emplace(dst, src.braces_); + } + for (auto b: src.braces_) + nb_braces_[b]++; + // If brace has no right-hand-side brace than it cannot emit any green color + is_green_[src.braces_[src.braces_.size() - 1]] = false; + } + + // Comparison is needed when for a set of safra_state + bool + safra_state::operator<(const safra_state& other) const + { + return nodes_ < other.nodes_; + } + + // Called only to initialize first state + safra_state::safra_state(unsigned val, bool init_state) + { + if (init_state) + { + unsigned state_num = val; + // One brace set + is_green_.push_back(true); + // First brace has init_state hence one state inside the first braces. + nb_braces_.push_back(1); + nodes_.emplace(state_num, 0); + } + else + { + unsigned nb_braces = val; + // One brace set + is_green_.assign(true, nb_braces); + // First brace has init_state hence one state inside the first braces. + nb_braces_.assign(nb_braces, 0); + } + } + + + bool + safra_state::node::operator<(const node& other) const + { + if (id_ == other.id_) + return in_construction_ ? false : braces_ < other.braces_; + else + return id_ < other.id_; + } + + bool + safra_state::node::operator==(const node& other) const + { + if (id_ == other.id_) + return in_construction_ ? true : braces_ == other.braces_; + else + return false; + } + + twa_graph_ptr + tgba_determinisation(const const_twa_graph_ptr& aut) + { + auto res = make_twa_graph(aut->get_dict()); + res->copy_ap_of(aut); + res->prop_copy(aut, + { true, // state based + true, // inherently_weak + true, // deterministic + false // stutter inv + }); + + // Given a safra_state get its associated state in output automata. + // Required to create new transitions from 2 safra-state + typedef std::map power_set; + power_set seen; + safra_state init(aut->get_init_state_number(), true); + unsigned num = res->new_state(); + res->set_init_state(num); + seen.insert(std::make_pair(init, num)); + std::deque todo; + todo.push_back(init); + while (!todo.empty()) + { + using succs_t = safra_state::succs_t; + safra_state curr = todo.front(); + unsigned src_num = seen.find(curr)->second; + todo.pop_front(); + succs_t succs = curr.compute_succs(aut); + for (auto s: succs) + { + auto i = seen.find(s.first); + unsigned dst_num; + if (i != seen.end()) + { + dst_num = i->second; + } + else + { + dst_num = res->new_state(); + std::cerr << "New state " << dst_num << std::endl; + todo.push_back(s.first); + seen.insert(std::make_pair(s.first, dst_num)); + } + std::cerr << "Tr: " << src_num << " -> " << dst_num << "[" + << s.second << "]" << std::endl; + res->new_transition(src_num, dst_num, s.second); + } + } + return res; + } +} diff --git a/src/twaalgos/safra.hh b/src/twaalgos/safra.hh new file mode 100644 index 000000000..5de34bed8 --- /dev/null +++ b/src/twaalgos/safra.hh @@ -0,0 +1,80 @@ +// -*- 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 . + +#pragma once + +#include + +#include "misc/bddlt.hh" +#include "twa/twagraph.hh" + +namespace spot +{ + class safra_state + { + class node + { + public: + using brace_t = size_t; + + bool operator==(const node& other) const; + bool operator<(const node& other) const; + void disable_construction() { in_construction_ = false; } + node(unsigned id) + : id_(id), in_construction_(true) {} + node(unsigned id, brace_t b_id, bool in_construction = true) + : id_(id), braces_(1, b_id), in_construction_(in_construction) {} + node(unsigned id, std::vector b, bool in_construction = true) + : id_(id), braces_(b), in_construction_(in_construction) {} + // The name used to identify a state + unsigned id_; + // The list of braces the state is nested in. + std::vector braces_; + // Hack to have two comparision functions during construction and after + // construction + // During construction only the nodes id matterns as the braces are under + // construction. After construction (id, braces) is what distinguishes a + // node. + bool in_construction_; + }; + + public: + typedef std::vector> succs_t; + bool operator<(const safra_state& other) const; + safra_state(unsigned state_number, bool init_state = false); + // Given a certain transition_label, compute all the successors of that + // label, and return that new node. + succs_t compute_succs(const const_twa_graph_ptr& aut) const; + // Used when creating the list of successors + void update_succ(const node& src, unsigned dst, const acc_cond::mark_t); + void finalize_construction(); + // A list of nodes similar to the ones of a + // safra tree. These are constructed in the same way as the powerset + // algorithm. + std::set nodes_; + // A counter that indicates the nomber of states within a brace. + // This enables us to compute the red value + std::vector nb_braces_; + // A bitfield to know if a brace can emit green. + std::vector is_green_; + }; + + SPOT_API twa_graph_ptr + tgba_determinisation(const const_twa_graph_ptr& aut); +}