mirror of
https://github.com/Z3Prover/z3
synced 2025-09-30 21:19:29 +00:00
remove theory_str and classes that are only used by it
This commit is contained in:
parent
2ac1b24121
commit
fcd3a70c92
34 changed files with 14 additions and 14974 deletions
|
@ -1,6 +0,0 @@
|
|||
z3_add_component(automata
|
||||
SOURCES
|
||||
automaton.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
util
|
||||
)
|
|
@ -1,23 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
automaton.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Symbolic Automaton, a la Margus Veanes Automata library.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-12-23.
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "math/automata/automaton.h"
|
||||
|
||||
template class automaton<unsigned>;
|
|
@ -1,751 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
automaton.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Symbolic Automaton, a la Margus Veanes Automata library.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-12-23.
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "util/util.h"
|
||||
#include "util/vector.h"
|
||||
#include "util/uint_set.h"
|
||||
#include "util/trace.h"
|
||||
|
||||
template<class T>
|
||||
class default_value_manager {
|
||||
public:
|
||||
void inc_ref(T* t) {}
|
||||
void dec_ref(T* t) {}
|
||||
};
|
||||
|
||||
template<class T, class M = default_value_manager<T> >
|
||||
class automaton {
|
||||
public:
|
||||
class move {
|
||||
M& m;
|
||||
T* m_t;
|
||||
unsigned m_src;
|
||||
unsigned m_dst;
|
||||
public:
|
||||
move(M& m, unsigned s, unsigned d, T* t = nullptr): m(m), m_t(t), m_src(s), m_dst(d) {
|
||||
if (t) m.inc_ref(t);
|
||||
}
|
||||
~move() {
|
||||
if (m_t) m.dec_ref(m_t);
|
||||
}
|
||||
|
||||
move(move const& other): m(other.m), m_t(other.m_t), m_src(other.m_src), m_dst(other.m_dst) {
|
||||
if (m_t) m.inc_ref(m_t);
|
||||
}
|
||||
|
||||
move(move &&other) noexcept : m(other.m), m_t(nullptr), m_src(other.m_src), m_dst(other.m_dst) {
|
||||
std::swap(m_t, other.m_t);
|
||||
}
|
||||
|
||||
move& operator=(move const& other) {
|
||||
SASSERT(&m == &other.m);
|
||||
T* t = other.m_t;
|
||||
if (t) m.inc_ref(t);
|
||||
if (m_t) m.dec_ref(m_t);
|
||||
m_t = t;
|
||||
m_src = other.m_src;
|
||||
m_dst = other.m_dst;
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned dst() const { return m_dst; }
|
||||
unsigned src() const { return m_src; }
|
||||
T* t() const { return m_t; }
|
||||
|
||||
bool is_epsilon() const { return m_t == nullptr; }
|
||||
};
|
||||
typedef vector<move> moves;
|
||||
private:
|
||||
M& m;
|
||||
vector<moves> m_delta;
|
||||
vector<moves> m_delta_inv;
|
||||
unsigned m_init;
|
||||
uint_set m_final_set;
|
||||
unsigned_vector m_final_states;
|
||||
|
||||
|
||||
// local data-structures
|
||||
mutable uint_set m_visited;
|
||||
mutable unsigned_vector m_todo;
|
||||
|
||||
struct default_display {
|
||||
std::ostream& display(std::ostream& out, T* t) {
|
||||
return out << t;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
// The empty automaton:
|
||||
automaton(M& m):
|
||||
m(m),
|
||||
m_init(0)
|
||||
{
|
||||
m_delta.push_back(moves());
|
||||
m_delta_inv.push_back(moves());
|
||||
}
|
||||
|
||||
|
||||
// create an automaton from initial state, final states, and moves
|
||||
automaton(M& m, unsigned init, unsigned_vector const& final, moves const& mvs): m(m) {
|
||||
m_init = init;
|
||||
m_delta.push_back(moves());
|
||||
m_delta_inv.push_back(moves());
|
||||
for (unsigned f : final) {
|
||||
add_to_final_states(f);
|
||||
}
|
||||
for (move const& mv : mvs) {
|
||||
unsigned n = std::max(mv.src(), mv.dst());
|
||||
if (n >= m_delta.size()) {
|
||||
m_delta.resize(n+1, moves());
|
||||
m_delta_inv.resize(n+1, moves());
|
||||
}
|
||||
add(mv);
|
||||
}
|
||||
}
|
||||
|
||||
// create an automaton that accepts a sequence.
|
||||
automaton(M& m, ptr_vector<T> const& seq):
|
||||
m(m),
|
||||
m_init(0) {
|
||||
m_delta.resize(seq.size()+1, moves());
|
||||
m_delta_inv.resize(seq.size()+1, moves());
|
||||
for (unsigned i = 0; i < seq.size(); ++i) {
|
||||
m_delta[i].push_back(move(m, i, i + 1, seq[i]));
|
||||
m_delta[i + 1].push_back(move(m, i, i + 1, seq[i]));
|
||||
}
|
||||
add_to_final_states(seq.size());
|
||||
}
|
||||
|
||||
// The automaton that accepts t
|
||||
automaton(M& m, T* t):
|
||||
m(m),
|
||||
m_init(0) {
|
||||
m_delta.resize(2, moves());
|
||||
m_delta_inv.resize(2, moves());
|
||||
add_to_final_states(1);
|
||||
add(move(m, 0, 1, t));
|
||||
}
|
||||
|
||||
automaton(automaton const& other):
|
||||
m(other.m),
|
||||
m_delta(other.m_delta),
|
||||
m_delta_inv(other.m_delta_inv),
|
||||
m_init(other.m_init),
|
||||
m_final_set(other.m_final_set),
|
||||
m_final_states(other.m_final_states)
|
||||
{}
|
||||
|
||||
// create the automaton that accepts the empty string/sequence only.
|
||||
static automaton* mk_epsilon(M& m) {
|
||||
moves mvs;
|
||||
unsigned_vector final;
|
||||
final.push_back(0);
|
||||
return alloc(automaton, m, 0, final, mvs);
|
||||
}
|
||||
|
||||
// create the automaton with a single state on condition t.
|
||||
static automaton* mk_loop(M& m, T* t) {
|
||||
moves mvs;
|
||||
unsigned_vector final;
|
||||
final.push_back(0);
|
||||
mvs.push_back(move(m, 0, 0, t));
|
||||
return alloc(automaton, m, 0, final, mvs);
|
||||
}
|
||||
|
||||
static automaton* clone(automaton const& a) {
|
||||
moves mvs;
|
||||
unsigned_vector final;
|
||||
append_moves(0, a, mvs);
|
||||
append_final(0, a, final);
|
||||
return alloc(automaton, a.m, a.init(), final, mvs);
|
||||
}
|
||||
|
||||
automaton* clone() const {
|
||||
return clone(*this);
|
||||
}
|
||||
|
||||
// create the sum of disjoint automata
|
||||
static automaton* mk_union(automaton const& a, automaton const& b) {
|
||||
SASSERT(&a.m == &b.m);
|
||||
M& m = a.m;
|
||||
if (a.is_empty()) {
|
||||
return b.clone();
|
||||
}
|
||||
if (b.is_empty()) {
|
||||
return a.clone();
|
||||
}
|
||||
moves mvs;
|
||||
unsigned_vector final;
|
||||
unsigned offset1 = 1;
|
||||
unsigned offset2 = a.num_states() + 1;
|
||||
mvs.push_back(move(m, 0, a.init() + offset1));
|
||||
mvs.push_back(move(m, 0, b.init() + offset2));
|
||||
append_moves(offset1, a, mvs);
|
||||
append_moves(offset2, b, mvs);
|
||||
append_final(offset1, a, final);
|
||||
append_final(offset2, b, final);
|
||||
return alloc(automaton, m, 0, final, mvs);
|
||||
}
|
||||
|
||||
static automaton* mk_opt(automaton const& a) {
|
||||
M& m = a.m;
|
||||
moves mvs;
|
||||
unsigned_vector final;
|
||||
unsigned offset = 0;
|
||||
unsigned init = a.init();
|
||||
if (!a.initial_state_is_source()) {
|
||||
offset = 1;
|
||||
init = 0;
|
||||
mvs.push_back(move(m, 0, a.init() + offset));
|
||||
}
|
||||
if (a.is_empty()) {
|
||||
return a.clone();
|
||||
}
|
||||
|
||||
mvs.push_back(move(m, init, a.final_state() + offset));
|
||||
append_moves(offset, a, mvs);
|
||||
append_final(offset, a, final);
|
||||
return alloc(automaton, m, init, final, mvs);
|
||||
}
|
||||
|
||||
// concatenate accepting languages
|
||||
static automaton* mk_concat(automaton const& a, automaton const& b) {
|
||||
SASSERT(&a.m == &b.m);
|
||||
M& m = a.m;
|
||||
if (a.is_empty()) {
|
||||
return a.clone();
|
||||
}
|
||||
if (b.is_empty()) {
|
||||
return b.clone();
|
||||
}
|
||||
if (a.is_epsilon()) {
|
||||
return b.clone();
|
||||
}
|
||||
if (b.is_epsilon()) {
|
||||
return a.clone();
|
||||
}
|
||||
|
||||
moves mvs;
|
||||
unsigned_vector final;
|
||||
unsigned init = 0;
|
||||
unsigned offset1 = 1;
|
||||
unsigned offset2 = a.num_states() + offset1;
|
||||
mvs.push_back(move(m, 0, a.init() + offset1));
|
||||
append_moves(offset1, a, mvs);
|
||||
for (unsigned i = 0; i < a.m_final_states.size(); ++i) {
|
||||
mvs.push_back(move(m, a.m_final_states[i] + offset1, b.init() + offset2));
|
||||
}
|
||||
append_moves(offset2, b, mvs);
|
||||
append_final(offset2, b, final);
|
||||
|
||||
return alloc(automaton, m, init, final, mvs);
|
||||
}
|
||||
|
||||
static automaton* mk_reverse(automaton const& a) {
|
||||
M& m = a.m;
|
||||
if (a.is_empty()) {
|
||||
return alloc(automaton, m);
|
||||
}
|
||||
moves mvs;
|
||||
for (unsigned i = 0; i < a.m_delta.size(); ++i) {
|
||||
moves const& mvs1 = a.m_delta[i];
|
||||
for (unsigned j = 0; j < mvs1.size(); ++j) {
|
||||
move const& mv = mvs1[j];
|
||||
mvs.push_back(move(m, mv.dst(), mv.src(), mv.t()));
|
||||
}
|
||||
}
|
||||
unsigned_vector final;
|
||||
unsigned init;
|
||||
final.push_back(a.init());
|
||||
if (a.m_final_states.size() == 1) {
|
||||
init = a.m_final_states[0];
|
||||
}
|
||||
else {
|
||||
init = a.num_states();
|
||||
for (unsigned st : a.m_final_states) {
|
||||
mvs.push_back(move(m, init, st));
|
||||
}
|
||||
}
|
||||
return alloc(automaton, m, init, final, mvs);
|
||||
}
|
||||
|
||||
void add_to_final_states(unsigned s) {
|
||||
if (!is_final_state(s)) {
|
||||
m_final_set.insert(s);
|
||||
m_final_states.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_from_final_states(unsigned s) {
|
||||
if (is_final_state(s)) {
|
||||
m_final_set.remove(s);
|
||||
m_final_states.erase(s);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_sink_state(unsigned s) const {
|
||||
if (is_final_state(s)) return false;
|
||||
moves mvs;
|
||||
get_moves_from(s, mvs);
|
||||
for (move const& m : mvs) {
|
||||
if (s != m.dst()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void add_init_to_final_states() {
|
||||
add_to_final_states(init());
|
||||
}
|
||||
|
||||
void add_final_to_init_moves() {
|
||||
for (unsigned i = 0; i < m_final_states.size(); ++i) {
|
||||
unsigned state = m_final_states[i];
|
||||
bool found = false;
|
||||
moves const& mvs = m_delta[state];
|
||||
for (unsigned j = 0; found && j < mvs.size(); ++j) {
|
||||
found = (mvs[j].dst() == m_init) && mvs[j].is_epsilon();
|
||||
}
|
||||
if (!found && state != m_init) {
|
||||
add(move(m, state, m_init));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove epsilon transitions
|
||||
// src - e -> dst
|
||||
// in_degree(src) = 1, final(src) => final(dst), src0 != src
|
||||
// src0 - t -> src - e -> dst => src0 - t -> dst
|
||||
// out_degree(dst) = 1, final(dst) => final(src), dst != dst1
|
||||
// src - e -> dst - t -> dst1 => src - t -> dst1
|
||||
|
||||
// Generalized:
|
||||
// Src - E -> dst - t -> dst1 => Src - t -> dst1 if dst is final => each Src is final
|
||||
//
|
||||
// src - e -> dst - ET -> Dst1 => src - ET -> Dst1 if in_degree(dst) = 1, src != dst
|
||||
// Src - E -> dst - et -> dst1 => Src - et -> dst1 if out_degree(dst) = 1, src != dst
|
||||
//
|
||||
// Some missing:
|
||||
// src - et -> dst - E -> Dst1 => src - et -> Dst1 if in_degree(dst) = 1
|
||||
// Src - ET -> dst - e -> dst1 => Src - ET -> dst1 if out_degree(dst) = 1,
|
||||
//
|
||||
void compress() {
|
||||
SASSERT(!m_delta.empty());
|
||||
TRACE(seq, display(tout););
|
||||
for (unsigned i = 0; i < m_delta.size(); ++i) {
|
||||
for (unsigned j = 0; j < m_delta[i].size(); ++j) {
|
||||
move const& mv = m_delta[i][j];
|
||||
unsigned src = mv.src();
|
||||
unsigned dst = mv.dst();
|
||||
SASSERT(src == i);
|
||||
if (mv.is_epsilon()) {
|
||||
if (src == dst) {
|
||||
// just remove this edge.
|
||||
}
|
||||
else if (1 == in_degree(src) && 1 == out_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) {
|
||||
move const& mv0 = m_delta_inv[src][0];
|
||||
unsigned src0 = mv0.src();
|
||||
T* t = mv0.t();
|
||||
SASSERT(mv0.dst() == src);
|
||||
if (src0 == src) {
|
||||
continue;
|
||||
}
|
||||
add(move(m, src0, dst, t));
|
||||
remove(src0, src, t);
|
||||
|
||||
}
|
||||
else if (1 == out_degree(dst) && 1 == in_degree(dst) && init() != dst && (!is_final_state(dst) || is_final_state(src))) {
|
||||
move const& mv1 = m_delta[dst][0];
|
||||
unsigned dst1 = mv1.dst();
|
||||
T* t = mv1.t();
|
||||
SASSERT(mv1.src() == dst);
|
||||
if (dst1 == dst) {
|
||||
continue;
|
||||
}
|
||||
add(move(m, src, dst1, t));
|
||||
remove(dst, dst1, t);
|
||||
}
|
||||
else if (1 == in_degree(dst) && (!is_final_state(dst) || is_final_state(src)) && init() != dst) {
|
||||
moves const& mvs = m_delta[dst];
|
||||
moves mvs1;
|
||||
for (move const& mv : mvs) {
|
||||
mvs1.push_back(move(m, src, mv.dst(), mv.t()));
|
||||
}
|
||||
for (move const& mv : mvs1) {
|
||||
remove(dst, mv.dst(), mv.t());
|
||||
add(mv);
|
||||
}
|
||||
}
|
||||
//
|
||||
// Src - E -> dst - et -> dst1 => Src - et -> dst1 if out_degree(dst) = 1, src != dst
|
||||
//
|
||||
else if (1 == out_degree(dst) && all_epsilon_in(dst) && init() != dst && !is_final_state(dst)) {
|
||||
move const& mv = m_delta[dst][0];
|
||||
unsigned dst1 = mv.dst();
|
||||
T* t = mv.t();
|
||||
unsigned_vector src0s;
|
||||
moves const& mvs = m_delta_inv[dst];
|
||||
moves mvs1;
|
||||
for (move const& mv1 : mvs) {
|
||||
SASSERT(mv1.is_epsilon());
|
||||
mvs1.push_back(move(m, mv1.src(), dst1, t));
|
||||
}
|
||||
for (move const& mv1 : mvs1) {
|
||||
remove(mv1.src(), dst, nullptr);
|
||||
add(mv1);
|
||||
}
|
||||
remove(dst, dst1, t);
|
||||
--j;
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Src1 - ET -> src - e -> dst => Src1 - ET -> dst if out_degree(src) = 1, src != init()
|
||||
//
|
||||
else if (1 == out_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) {
|
||||
moves const& mvs = m_delta_inv[src];
|
||||
moves mvs1;
|
||||
for (move const& mv : mvs) {
|
||||
mvs1.push_back(move(m, mv.src(), dst, mv.t()));
|
||||
}
|
||||
for (move const& mv : mvs1) {
|
||||
remove(mv.src(), src, mv.t());
|
||||
add(mv);
|
||||
}
|
||||
}
|
||||
else if (1 == out_degree(src) && (is_final_state(src) || !is_final_state(dst))) {
|
||||
moves const& mvs = m_delta[dst];
|
||||
moves mvs1;
|
||||
for (move const& mv : mvs) {
|
||||
mvs1.push_back(move(m, src, mv.dst(), mv.t()));
|
||||
}
|
||||
for (move const& mv : mvs1) {
|
||||
add(mv);
|
||||
}
|
||||
}
|
||||
else {
|
||||
TRACE(seq, tout << "epsilon not removed " << out_degree(src) << " " << is_final_state(src) << " " << is_final_state(dst) << "\n";);
|
||||
continue;
|
||||
}
|
||||
remove(src, dst, nullptr);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
}
|
||||
SASSERT(!m_delta.empty());
|
||||
while (true) {
|
||||
SASSERT(!m_delta.empty());
|
||||
unsigned src = m_delta.size() - 1;
|
||||
if (in_degree(src) == 0 && init() != src) {
|
||||
remove_from_final_states(src);
|
||||
m_delta.pop_back();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
sinkify_dead_states();
|
||||
TRACE(seq, display(tout););
|
||||
}
|
||||
|
||||
bool is_sequence(unsigned& length) const {
|
||||
if (is_final_state(m_init) && (out_degree(m_init) == 0 || (out_degree(m_init) == 1 && is_loop_state(m_init)))) {
|
||||
length = 0;
|
||||
return true;
|
||||
}
|
||||
if (is_empty() || in_degree(m_init) != 0 || out_degree(m_init) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
length = 1;
|
||||
unsigned s = get_move_from(m_init).dst();
|
||||
while (!is_final_state(s)) {
|
||||
if (out_degree(s) != 1 || in_degree(s) != 1) {
|
||||
return false;
|
||||
}
|
||||
s = get_move_from(s).dst();
|
||||
++length;
|
||||
}
|
||||
return out_degree(s) == 0 || (out_degree(s) == 1 && is_loop_state(s));
|
||||
}
|
||||
|
||||
unsigned init() const { return m_init; }
|
||||
unsigned_vector const& final_states() const { return m_final_states; }
|
||||
unsigned in_degree(unsigned state) const { return m_delta_inv[state].size(); }
|
||||
unsigned out_degree(unsigned state) const { return m_delta[state].size(); }
|
||||
move const& get_move_from(unsigned state) const { SASSERT(m_delta[state].size() == 1); return m_delta[state][0]; }
|
||||
move const& get_move_to(unsigned state) const { SASSERT(m_delta_inv[state].size() == 1); return m_delta_inv[state][0]; }
|
||||
moves const& get_moves_from(unsigned state) const { return m_delta[state]; }
|
||||
moves const& get_moves_to(unsigned state) const { return m_delta_inv[state]; }
|
||||
bool initial_state_is_source() const { return m_delta_inv[m_init].empty(); }
|
||||
bool is_final_state(unsigned s) const { return m_final_set.contains(s); }
|
||||
bool is_final_configuration(uint_set const& s) const {
|
||||
for (unsigned i : s) {
|
||||
if (is_final_state(i))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_epsilon_free() const {
|
||||
for (moves const& mvs : m_delta) {
|
||||
for (move const & m : mvs) {
|
||||
if (!m.t()) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool all_epsilon_in(unsigned s) {
|
||||
moves const& mvs = m_delta_inv[s];
|
||||
for (move const& m : mvs) {
|
||||
if (m.t()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_empty() const { return m_final_states.empty(); }
|
||||
bool is_epsilon() const { return m_final_states.size() == 1 && m_final_states.back() == init() && m_delta.empty(); }
|
||||
unsigned final_state() const { return m_final_states[0]; }
|
||||
bool has_single_final_sink() const { return m_final_states.size() == 1 && m_delta[final_state()].empty(); }
|
||||
unsigned num_states() const { return m_delta.size(); }
|
||||
bool is_loop_state(unsigned s) const {
|
||||
moves mvs;
|
||||
get_moves_from(s, mvs);
|
||||
for (move const& m : mvs) {
|
||||
if (s == m.dst()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned move_count() const {
|
||||
unsigned result = 0;
|
||||
for (moves const& mvs : m_delta) result += mvs.size();
|
||||
return result;
|
||||
}
|
||||
void get_epsilon_closure(unsigned state, unsigned_vector& states) {
|
||||
get_epsilon_closure(state, m_delta, states);
|
||||
}
|
||||
void get_inv_epsilon_closure(unsigned state, unsigned_vector& states) {
|
||||
get_epsilon_closure(state, m_delta_inv, states);
|
||||
}
|
||||
void get_moves_from(unsigned state, moves& mvs, bool epsilon_closure = true) const {
|
||||
get_moves(state, m_delta, mvs, epsilon_closure);
|
||||
}
|
||||
void get_moves_from_states(uint_set const& states, moves& mvs, bool epsilon_closure = true) const {
|
||||
for (unsigned i : states) {
|
||||
moves curr;
|
||||
get_moves(i, m_delta, curr, epsilon_closure);
|
||||
mvs.append(curr);
|
||||
}
|
||||
}
|
||||
void get_moves_to(unsigned state, moves& mvs, bool epsilon_closure = true) {
|
||||
get_moves(state, m_delta_inv, mvs, epsilon_closure);
|
||||
}
|
||||
|
||||
template<class D>
|
||||
std::ostream& display(std::ostream& out, D& displayer = D()) const {
|
||||
out << "init: " << init() << "\n";
|
||||
out << "final: " << m_final_states << "\n";
|
||||
|
||||
for (unsigned i = 0; i < m_delta.size(); ++i) {
|
||||
moves const& mvs = m_delta[i];
|
||||
for (move const& mv : mvs) {
|
||||
out << i << " -> " << mv.dst() << " ";
|
||||
if (mv.t()) {
|
||||
out << "if ";
|
||||
displayer.display(out, mv.t());
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
private:
|
||||
|
||||
std::ostream& display(std::ostream& out) const {
|
||||
out << "init: " << init() << "\n";
|
||||
out << "final: " << m_final_states << "\n";
|
||||
|
||||
for (unsigned i = 0; i < m_delta.size(); ++i) {
|
||||
moves const& mvs = m_delta[i];
|
||||
for (move const& mv : mvs) {
|
||||
out << i << " -> " << mv.dst() << " ";
|
||||
if (mv.t()) {
|
||||
out << "if *** ";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
void sinkify_dead_states() {
|
||||
uint_set dead_states;
|
||||
for (unsigned i = 0; i < m_delta.size(); ++i) {
|
||||
if (!m_final_states.contains(i)) {
|
||||
dead_states.insert(i);
|
||||
}
|
||||
}
|
||||
bool change = true;
|
||||
unsigned_vector to_remove;
|
||||
while (change) {
|
||||
change = false;
|
||||
to_remove.reset();
|
||||
for (unsigned s : dead_states) {
|
||||
moves const& mvs = m_delta[s];
|
||||
for (move const& mv : mvs) {
|
||||
if (!dead_states.contains(mv.dst())) {
|
||||
to_remove.push_back(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
change = !to_remove.empty();
|
||||
for (unsigned s : to_remove) {
|
||||
dead_states.remove(s);
|
||||
}
|
||||
to_remove.reset();
|
||||
}
|
||||
TRACE(seq, tout << "remove: " << dead_states << "\n";
|
||||
tout << "final: " << m_final_states << "\n";
|
||||
);
|
||||
for (unsigned s : dead_states) {
|
||||
CTRACE(seq, !m_delta[s].empty(), tout << "live state " << s << "\n";);
|
||||
m_delta[s].reset();
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void remove_dead_states() {
|
||||
unsigned_vector remap;
|
||||
for (unsigned i = 0; i < m_delta.size(); ++i) {
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void add(move const& mv) {
|
||||
if (!is_duplicate_cheap(mv)) {
|
||||
m_delta[mv.src()].push_back(mv);
|
||||
m_delta_inv[mv.dst()].push_back(mv);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_duplicate_cheap(move const& mv) const {
|
||||
if (m_delta[mv.src()].empty()) return false;
|
||||
move const& mv0 = m_delta[mv.src()].back();
|
||||
return mv0.src() == mv.src() && mv0.dst() == mv.dst() && mv0.t() == mv.t();
|
||||
}
|
||||
|
||||
|
||||
unsigned find_move(unsigned src, unsigned dst, T* t, moves const& mvs) {
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
move const& mv = mvs[i];
|
||||
if (mv.src() == src && mv.dst() == dst && t == mv.t()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
void remove(unsigned src, unsigned dst, T* t, moves& mvs) {
|
||||
remove(find_move(src, dst, t, mvs), mvs);
|
||||
}
|
||||
|
||||
void remove(unsigned src, unsigned dst, T* t) {
|
||||
remove(src, dst, t, m_delta[src]);
|
||||
remove(src, dst, t, m_delta_inv[dst]);
|
||||
}
|
||||
|
||||
void remove(unsigned index, moves& mvs) {
|
||||
mvs[index] = mvs.back();
|
||||
mvs.pop_back();
|
||||
}
|
||||
|
||||
mutable unsigned_vector m_states1, m_states2;
|
||||
|
||||
void get_moves(unsigned state, vector<moves> const& delta, moves& mvs, bool epsilon_closure) const {
|
||||
m_states1.reset();
|
||||
m_states2.reset();
|
||||
get_epsilon_closure(state, delta, m_states1);
|
||||
for (unsigned i = 0; i < m_states1.size(); ++i) {
|
||||
state = m_states1[i];
|
||||
moves const& mv1 = delta[state];
|
||||
for (unsigned j = 0; j < mv1.size(); ++j) {
|
||||
move const& mv = mv1[j];
|
||||
if (!mv.is_epsilon()) {
|
||||
if (epsilon_closure) {
|
||||
m_states2.reset();
|
||||
get_epsilon_closure(mv.dst(), delta, m_states2);
|
||||
for (unsigned k = 0; k < m_states2.size(); ++k) {
|
||||
mvs.push_back(move(m, state, m_states2[k], mv.t()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
mvs.push_back(move(m, state, mv.dst(), mv.t()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_epsilon_closure(unsigned state, vector<moves> const& delta, unsigned_vector& states) const {
|
||||
m_todo.push_back(state);
|
||||
m_visited.insert(state);
|
||||
while (!m_todo.empty()) {
|
||||
state = m_todo.back();
|
||||
states.push_back(state);
|
||||
m_todo.pop_back();
|
||||
moves const& mvs = delta[state];
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
unsigned tgt = mvs[i].dst();
|
||||
if (mvs[i].is_epsilon() && !m_visited.contains(tgt)) {
|
||||
m_visited.insert(tgt);
|
||||
m_todo.push_back(tgt);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_visited.reset();
|
||||
SASSERT(m_todo.empty());
|
||||
}
|
||||
|
||||
static void append_moves(unsigned offset, automaton const& a, moves& mvs) {
|
||||
for (unsigned i = 0; i < a.num_states(); ++i) {
|
||||
moves const& mvs1 = a.m_delta[i];
|
||||
for (unsigned j = 0; j < mvs1.size(); ++j) {
|
||||
move const& mv = mvs1[j];
|
||||
mvs.push_back(move(a.m, mv.src() + offset, mv.dst() + offset, mv.t()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void append_final(unsigned offset, automaton const& a, unsigned_vector& final) {
|
||||
for (unsigned s : a.m_final_states) {
|
||||
final.push_back(s+offset);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef automaton<unsigned> uautomaton;
|
||||
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
boolean_algebra.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Boolean Algebra, a la Margus Veanes Automata library.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2016-2-27
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
template<class T>
|
||||
class positive_boolean_algebra {
|
||||
public:
|
||||
virtual ~positive_boolean_algebra() = default;
|
||||
virtual T mk_false() = 0;
|
||||
virtual T mk_true() = 0;
|
||||
virtual T mk_and(T x, T y) = 0;
|
||||
virtual T mk_or(T x, T y) = 0;
|
||||
virtual T mk_and(unsigned sz, T const* ts) = 0;
|
||||
virtual T mk_or(unsigned sz, T const* ts) = 0;
|
||||
virtual lbool is_sat(T x) = 0;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class boolean_algebra : public positive_boolean_algebra<T> {
|
||||
public:
|
||||
virtual T mk_not(T x) = 0;
|
||||
};
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
symbolic_automata.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Symbolic Automata over Boolean Algebras, a la Margus Veanes Automata library.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2016-02-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "math/automata/automaton.h"
|
||||
#include "math/automata/boolean_algebra.h"
|
||||
|
||||
|
||||
template<class T, class M = default_value_manager<T> >
|
||||
class symbolic_automata {
|
||||
typedef automaton<T, M> automaton_t;
|
||||
typedef boolean_algebra<T*> ba_t;
|
||||
typedef typename automaton_t::move move_t;
|
||||
typedef vector<move_t> moves_t;
|
||||
typedef obj_ref<T, M> ref_t;
|
||||
typedef ref_vector<T, M> refs_t;
|
||||
typedef std::pair<unsigned, unsigned> unsigned_pair;
|
||||
template<class V> class u2_map : public map<unsigned_pair, V, pair_hash<unsigned_hash, unsigned_hash>, default_eq<unsigned_pair> > {};
|
||||
|
||||
|
||||
M& m;
|
||||
ba_t& m_ba;
|
||||
|
||||
|
||||
class block {
|
||||
uint_set m_set;
|
||||
unsigned m_rep;
|
||||
bool m_rep_chosen;
|
||||
public:
|
||||
|
||||
block(): m_rep(0), m_rep_chosen(false) {}
|
||||
|
||||
block(uint_set const& s):
|
||||
m_set(s),
|
||||
m_rep(0),
|
||||
m_rep_chosen(false) {
|
||||
}
|
||||
|
||||
block(unsigned_vector const& vs) {
|
||||
for (unsigned i = 0; i < vs.size(); ++i) {
|
||||
m_set.insert(vs[i]);
|
||||
}
|
||||
m_rep_chosen = false;
|
||||
m_rep = 0;
|
||||
}
|
||||
|
||||
block& operator=(block const& b) {
|
||||
m_set = b.m_set;
|
||||
m_rep = 0;
|
||||
m_rep_chosen = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned get_representative() {
|
||||
if (!m_rep_chosen) {
|
||||
uint_set::iterator it = m_set.begin();
|
||||
if (m_set.end() != it) {
|
||||
m_rep = *it;
|
||||
}
|
||||
m_rep_chosen = true;
|
||||
}
|
||||
return m_rep;
|
||||
}
|
||||
|
||||
void insert(unsigned i) { m_set.insert(i); }
|
||||
bool contains(unsigned i) const { return m_set.contains(i); }
|
||||
bool is_empty() const { return m_set.empty(); }
|
||||
unsigned size() const { return m_set.num_elems(); }
|
||||
void remove(unsigned i) { m_set.remove(i); m_rep_chosen = false; }
|
||||
void clear() { m_set.reset(); m_rep_chosen = false; }
|
||||
uint_set::iterator begin() const { return m_set.begin(); }
|
||||
uint_set::iterator end() const { return m_set.end(); }
|
||||
};
|
||||
|
||||
void add_block(block const& p1, unsigned p0_index, unsigned_vector& blocks, vector<block>& pblocks, unsigned_vector& W);
|
||||
|
||||
public:
|
||||
symbolic_automata(M& m, ba_t& ba): m(m), m_ba(ba) {}
|
||||
automaton_t* mk_determinstic(automaton_t& a);
|
||||
automaton_t* mk_complement(automaton_t& a);
|
||||
automaton_t* remove_epsilons(automaton_t& a);
|
||||
automaton_t* mk_total(automaton_t& a);
|
||||
automaton_t* mk_minimize(automaton_t& a);
|
||||
automaton_t* mk_minimize_total(automaton_t& a);
|
||||
automaton_t* mk_difference(automaton_t& a, automaton_t& b);
|
||||
automaton_t* mk_product(automaton_t& a, automaton_t& b);
|
||||
|
||||
private:
|
||||
automaton_t* mk_determinstic_param(automaton_t& a, bool flip_acceptance);
|
||||
|
||||
vector<std::pair<vector<bool>, ref_t> > generate_min_terms(vector<ref_t> &constraints) {
|
||||
vector<std::pair<vector<bool>, ref_t> > min_terms;
|
||||
|
||||
ref_t curr_pred(m_ba.mk_true(), m);
|
||||
vector<bool> curr_bv;
|
||||
|
||||
generate_min_terms_rec(constraints, min_terms, 0, curr_bv, curr_pred);
|
||||
|
||||
return min_terms;
|
||||
}
|
||||
void generate_min_terms_rec(vector<ref_t> &constraints, vector<std::pair<vector<bool>, ref_t> > &min_terms, unsigned i, vector<bool> &curr_bv, ref_t &curr_pred) {
|
||||
lbool is_sat = m_ba.is_sat(curr_pred);
|
||||
if (is_sat == l_undef)
|
||||
throw default_exception("incomplete theory: unable to generate min-terms");
|
||||
|
||||
if (is_sat != l_true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (i == constraints.size()) {
|
||||
min_terms.push_back(std::pair<vector<bool>, ref_t>(curr_bv, curr_pred));
|
||||
}
|
||||
else {
|
||||
//true case
|
||||
curr_bv.push_back(true);
|
||||
ref_t new_pred_pos(m_ba.mk_and(curr_pred, constraints[i]), m);
|
||||
generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_pos);
|
||||
curr_bv.pop_back();
|
||||
|
||||
//false case
|
||||
curr_bv.push_back(false);
|
||||
ref_t neg(m_ba.mk_not(constraints[i]), m);
|
||||
ref_t new_pred_neg(m_ba.mk_and(curr_pred, neg), m);
|
||||
generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_neg);
|
||||
curr_bv.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,490 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
symbolic_automata_def.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Symbolic Automata over Boolean Algebras, a la Margus Veanes Automata library.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2016-02-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "math/automata/symbolic_automata.h"
|
||||
#include "util/hashtable.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T, class M>
|
||||
typename symbolic_automata<T, M>::automaton_t* symbolic_automata<T, M>::mk_total(automaton_t& a) {
|
||||
unsigned dead_state = a.num_states();
|
||||
moves_t mvs, new_mvs;
|
||||
for (unsigned i = 0; i < dead_state; ++i) {
|
||||
mvs.reset();
|
||||
a.get_moves_from(i, mvs, true);
|
||||
refs_t vs(m);
|
||||
|
||||
for (unsigned j = 0; j < mvs.size(); ++j) {
|
||||
vs.push_back(mvs[j].t());
|
||||
}
|
||||
ref_t cond(m_ba.mk_not(m_ba.mk_or(vs.size(), vs.data())), m);
|
||||
lbool is_sat = m_ba.is_sat(cond);
|
||||
if (is_sat == l_undef) {
|
||||
return nullptr;
|
||||
}
|
||||
if (is_sat == l_true) {
|
||||
new_mvs.push_back(move_t(m, i, dead_state, cond));
|
||||
}
|
||||
}
|
||||
if (new_mvs.empty()) {
|
||||
return a.clone();
|
||||
}
|
||||
new_mvs.push_back(move_t(m, dead_state, dead_state, m_ba.mk_true()));
|
||||
|
||||
// TBD private: automaton_t::append_moves(0, a, new_mvs);
|
||||
|
||||
return alloc(automaton_t, m, a.init(), a.final_states(), new_mvs);
|
||||
}
|
||||
|
||||
template<class T, class M>
|
||||
typename symbolic_automata<T, M>::automaton_t* symbolic_automata<T, M>::mk_minimize(automaton_t& a) {
|
||||
if (a.is_empty()) {
|
||||
return a.clone();
|
||||
}
|
||||
|
||||
if (a.is_epsilon()) {
|
||||
return a.clone();
|
||||
}
|
||||
// SASSERT(a.is_deterministic());
|
||||
|
||||
scoped_ptr<automaton_t> fa = mk_total(a);
|
||||
if (!fa) {
|
||||
return 0;
|
||||
}
|
||||
return mk_minimize_total(*fa.get());
|
||||
}
|
||||
|
||||
|
||||
template<class T, class M>
|
||||
void symbolic_automata<T, M>::add_block(block const& p1, unsigned p0_index, unsigned_vector& blocks, vector<block>& pblocks, unsigned_vector& W) {
|
||||
block& p0 = pblocks[p0_index];
|
||||
if (p1.size() < p0.size()) {
|
||||
unsigned p1_index = pblocks.size();
|
||||
pblocks.push_back(p1);
|
||||
for (uint_set::iterator it = p1.begin(), end = p1.end(); it != end; ++it) {
|
||||
p0.remove(*it);
|
||||
blocks[*it] = p1_index;
|
||||
}
|
||||
if (W.contains(p0_index)) {
|
||||
W.push_back(p1_index);
|
||||
}
|
||||
else if (p0.size() <= p1.size()) {
|
||||
W.push_back(p0_index);
|
||||
}
|
||||
else {
|
||||
W.push_back(p1_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class M>
|
||||
typename symbolic_automata<T, M>::automaton_t* symbolic_automata<T, M>::mk_minimize_total(automaton_t& a) {
|
||||
vector<block> pblocks;
|
||||
unsigned_vector blocks;
|
||||
unsigned_vector non_final;
|
||||
for (unsigned i = 0; i < a.num_states(); ++i) {
|
||||
if (!a.is_final_state(i)) {
|
||||
non_final.push_back(i);
|
||||
blocks.push_back(1);
|
||||
}
|
||||
else {
|
||||
blocks.push_back(0);
|
||||
}
|
||||
}
|
||||
pblocks.push_back(block(a.final_states())); // 0 |-> final states
|
||||
pblocks.push_back(block(non_final)); // 1 |-> non-final states
|
||||
|
||||
unsigned_vector W;
|
||||
W.push_back(pblocks[0].size() > pblocks[1].size() ? 1 : 0);
|
||||
|
||||
refs_t trail(m);
|
||||
u_map<T*> gamma;
|
||||
moves_t mvs;
|
||||
while (!W.empty()) {
|
||||
block R(pblocks[W.back()]);
|
||||
W.pop_back();
|
||||
gamma.reset();
|
||||
uint_set::iterator it = R.begin(), end = R.end();
|
||||
for (; it != end; ++it) {
|
||||
unsigned dst = *it;
|
||||
mvs.reset();
|
||||
a.get_moves_to(dst, mvs);
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
unsigned src = mvs[i].src();
|
||||
if (pblocks[src].size() > 1) {
|
||||
T* t = mvs[i].t();
|
||||
T* t1;
|
||||
if (gamma.find(src, t1)) {
|
||||
t = m_ba.mk_or(t, t1);
|
||||
trail.push_back(t);
|
||||
}
|
||||
gamma.insert(src, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
uint_set relevant1;
|
||||
typedef typename u_map<T*>::iterator gamma_iterator;
|
||||
gamma_iterator gend = gamma.end();
|
||||
for (gamma_iterator git = gamma.begin(); git != gend; ++git) {
|
||||
unsigned p0A_index = blocks[git->m_key];
|
||||
if (relevant1.contains(p0A_index)) {
|
||||
continue;
|
||||
}
|
||||
relevant1.insert(p0A_index);
|
||||
block& p0A = pblocks[p0A_index];
|
||||
block p1;
|
||||
for (gamma_iterator it = gamma.begin(); it != gend; ++it) {
|
||||
if (p0A.contains(it->m_key)) p1.insert(it->m_key);
|
||||
}
|
||||
|
||||
add_block(p1, p0A_index, blocks, pblocks, W);
|
||||
|
||||
bool iterate = true;
|
||||
while (iterate) {
|
||||
iterate = false;
|
||||
uint_set relevant2;
|
||||
for (gamma_iterator it = gamma.begin(); it != gend; ++it) {
|
||||
unsigned p0B_index = blocks[it->m_key];
|
||||
if (pblocks[p0B_index].size() <= 1 || relevant2.contains(p0B_index)) {
|
||||
continue;
|
||||
}
|
||||
relevant2.insert(p0B_index);
|
||||
block const& p0B = pblocks[p0B_index];
|
||||
uint_set::iterator bi = p0B.begin(), be = p0B.end();
|
||||
|
||||
block p1;
|
||||
p1.insert(*bi);
|
||||
bool split_found = false;
|
||||
ref_t psi(gamma[*bi], m);
|
||||
++bi;
|
||||
for (; bi != be; ++bi) {
|
||||
unsigned q = *bi;
|
||||
ref_t phi(gamma[q], m);
|
||||
if (split_found) {
|
||||
ref_t phi_and_psi(m_ba.mk_and(phi, psi), m);
|
||||
switch (m_ba.is_sat(phi_and_psi)) {
|
||||
case l_true:
|
||||
p1.insert(q);
|
||||
break;
|
||||
case l_undef:
|
||||
return nullptr;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ref_t psi_min_phi(m_ba.mk_and(psi, m_ba.mk_not(phi)), m);
|
||||
lbool is_sat = m_ba.is_sat(psi_min_phi);
|
||||
if (is_sat == l_undef) {
|
||||
return nullptr;
|
||||
}
|
||||
if (is_sat == l_true) {
|
||||
psi = psi_min_phi;
|
||||
split_found = true;
|
||||
continue;
|
||||
}
|
||||
// psi is a subset of phi
|
||||
ref_t phi_min_psi(m_ba.mk_and(phi, m_ba.mk_not(psi)), m);
|
||||
is_sat = m_ba.is_sat(phi_min_psi);
|
||||
if (is_sat == l_undef) {
|
||||
return nullptr;
|
||||
}
|
||||
else if (is_sat == l_false) {
|
||||
p1.insert(q); // psi and phi are equivalent
|
||||
}
|
||||
else {
|
||||
p1.clear();
|
||||
p1.insert(q);
|
||||
psi = phi_min_psi;
|
||||
split_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p1.size() < p0B.size() && p0B.size() > 2) iterate = true;
|
||||
add_block(p1, p0B_index, blocks, pblocks, W);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned new_init = pblocks[blocks[a.init()]].get_representative();
|
||||
|
||||
// set moves
|
||||
u2_map<T*> conds;
|
||||
svector<unsigned_pair> keys;
|
||||
moves_t new_moves;
|
||||
|
||||
for (unsigned i = 0; i < a.num_states(); ++i) {
|
||||
unsigned src = pblocks[blocks[i]].get_representative();
|
||||
typename automaton_t::moves const& mvs = a.get_moves_from(i);
|
||||
for (unsigned j = 0; j < mvs.size(); ++j) {
|
||||
unsigned dst = pblocks[blocks[mvs[j].dst()]].get_representative();
|
||||
unsigned_pair st(src, dst);
|
||||
T* t = 0;
|
||||
if (conds.find(st, t)) {
|
||||
t = m_ba.mk_or(t, mvs[j].t());
|
||||
trail.push_back(t);
|
||||
conds.insert(st, t);
|
||||
}
|
||||
else {
|
||||
conds.insert(st, mvs[j].t());
|
||||
keys.push_back(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < keys.size(); ++i) {
|
||||
unsigned_pair st = keys[i];
|
||||
new_moves.push_back(move_t(m, st.first, st.second, conds[st]));
|
||||
}
|
||||
// set final states.
|
||||
unsigned_vector new_final;
|
||||
uint_set new_final_set;
|
||||
for (unsigned i = 0; i < a.final_states().size(); ++i) {
|
||||
unsigned f = pblocks[blocks[a.final_states()[i]]].get_representative();
|
||||
if (!new_final_set.contains(f)) {
|
||||
new_final_set.insert(f);
|
||||
new_final.push_back(f);
|
||||
}
|
||||
}
|
||||
|
||||
return alloc(automaton_t, m, new_init, new_final, new_moves);
|
||||
}
|
||||
|
||||
template<class T, class M>
|
||||
typename symbolic_automata<T, M>::automaton_t* symbolic_automata<T, M>::mk_determinstic(automaton_t& a) {
|
||||
return mk_determinstic_param(a);
|
||||
}
|
||||
|
||||
template<class T, class M>
|
||||
typename symbolic_automata<T, M>::automaton_t* symbolic_automata<T, M>::mk_complement(automaton_t& a) {
|
||||
return mk_determinstic_param(a, true);
|
||||
}
|
||||
|
||||
template<class T, class M>
|
||||
typename symbolic_automata<T, M>::automaton_t*
|
||||
symbolic_automata<T, M>::mk_determinstic_param(automaton_t& a, bool flip_acceptance) {
|
||||
vector<std::pair<vector<bool>, ref_t> > min_terms;
|
||||
vector<ref_t> predicates;
|
||||
|
||||
map<uint_set, unsigned, uint_set::hash, uint_set::eq> s2id; // set of states to unique id
|
||||
vector<uint_set> id2s; // unique id to set of b-states
|
||||
uint_set set;
|
||||
unsigned_vector vector;
|
||||
moves_t new_mvs; // moves in the resulting automaton
|
||||
unsigned_vector new_final_states; // new final states
|
||||
unsigned p_state_id = 0; // next state identifier
|
||||
|
||||
TRACE(seq, tout << "mk-deterministic " << flip_acceptance << " " << set << " " << a.is_final_configuration(set) << "\n";);
|
||||
// adds non-final states of a to final if flipping and final otherwise
|
||||
unsigned_vector init_states;
|
||||
a.get_epsilon_closure(a.init(), init_states);
|
||||
for (unsigned s : init_states) {
|
||||
set.insert(s);
|
||||
}
|
||||
if (a.is_final_configuration(set) != flip_acceptance) {
|
||||
new_final_states.push_back(p_state_id);
|
||||
}
|
||||
|
||||
s2id.insert(set, p_state_id++); // the index to the initial state is 0
|
||||
id2s.push_back(set);
|
||||
|
||||
::vector<uint_set> todo; //States to visit
|
||||
todo.push_back(set);
|
||||
|
||||
uint_set state;
|
||||
moves_t mvsA;
|
||||
|
||||
new_mvs.reset();
|
||||
|
||||
// or just make todo a vector whose indices coincide with state_id.
|
||||
while (!todo.empty()) {
|
||||
uint_set state = todo.back();
|
||||
|
||||
unsigned state_id = s2id[state];
|
||||
todo.pop_back();
|
||||
mvsA.reset();
|
||||
|
||||
min_terms.reset();
|
||||
predicates.reset();
|
||||
|
||||
a.get_moves_from_states(state, mvsA);
|
||||
|
||||
for (unsigned j = 0; j < mvsA.size(); ++j) {
|
||||
ref_t mv_guard(mvsA[j].t(),m);
|
||||
predicates.push_back(mv_guard);
|
||||
}
|
||||
|
||||
min_terms = generate_min_terms(predicates);
|
||||
for (unsigned j = 0; j < min_terms.size(); ++j) {
|
||||
set = uint_set();
|
||||
for (unsigned i = 0; i < mvsA.size(); ++i) {
|
||||
if (min_terms[j].first[i])
|
||||
set.insert(mvsA[i].dst());
|
||||
}
|
||||
|
||||
bool is_new = !s2id.contains(set);
|
||||
if (is_new) {
|
||||
TRACE(seq, tout << "mk-deterministic " << flip_acceptance << " " << set << " " << a.is_final_configuration(set) << "\n";);
|
||||
if (a.is_final_configuration(set) != flip_acceptance) {
|
||||
new_final_states.push_back(p_state_id);
|
||||
}
|
||||
|
||||
s2id.insert(set, p_state_id++);
|
||||
id2s.push_back(set);
|
||||
todo.push_back(set);
|
||||
}
|
||||
new_mvs.push_back(move_t(m, state_id, s2id[set], min_terms[j].second));
|
||||
}
|
||||
}
|
||||
|
||||
if (new_final_states.empty()) {
|
||||
return alloc(automaton_t, m);
|
||||
}
|
||||
|
||||
return alloc(automaton_t, m, 0, new_final_states, new_mvs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class M>
|
||||
typename symbolic_automata<T, M>::automaton_t* symbolic_automata<T, M>::mk_product(automaton_t& a, automaton_t& b) {
|
||||
u2_map<unsigned> pair2id;
|
||||
unsigned_pair init_pair(a.init(), b.init());
|
||||
svector<unsigned_pair> todo;
|
||||
todo.push_back(init_pair);
|
||||
pair2id.insert(init_pair, 0);
|
||||
moves_t mvs;
|
||||
unsigned_vector final;
|
||||
unsigned_vector a_init, b_init;
|
||||
a.get_epsilon_closure(a.init(), a_init);
|
||||
bool a_init_is_final = false, b_init_is_final = false;
|
||||
for (unsigned ia : a_init) {
|
||||
if (a.is_final_state(ia)) {
|
||||
a_init_is_final = true;
|
||||
b.get_epsilon_closure(b.init(), b_init);
|
||||
for (unsigned ib : b_init) {
|
||||
if (b.is_final_state(ib)) {
|
||||
b_init_is_final = true;
|
||||
final.push_back(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned n = 1;
|
||||
moves_t mvsA, mvsB;
|
||||
while (!todo.empty()) {
|
||||
unsigned_pair curr_pair = todo.back();
|
||||
todo.pop_back();
|
||||
unsigned src = pair2id[curr_pair];
|
||||
mvsA.reset(); mvsB.reset();
|
||||
a.get_moves_from(curr_pair.first, mvsA, true);
|
||||
b.get_moves_from(curr_pair.second, mvsB, true);
|
||||
for (unsigned i = 0; i < mvsA.size(); ++i) {
|
||||
for (unsigned j = 0; j < mvsB.size(); ++j) {
|
||||
ref_t ab(m_ba.mk_and(mvsA[i].t(), mvsB[j].t()), m);
|
||||
lbool is_sat = m_ba.is_sat(ab);
|
||||
if (is_sat == l_false) {
|
||||
continue;
|
||||
}
|
||||
else if (is_sat == l_undef) {
|
||||
return nullptr;
|
||||
}
|
||||
unsigned_pair tgt_pair(mvsA[i].dst(), mvsB[j].dst());
|
||||
unsigned tgt;
|
||||
if (!pair2id.find(tgt_pair, tgt)) {
|
||||
tgt = n++;
|
||||
pair2id.insert(tgt_pair, tgt);
|
||||
todo.push_back(tgt_pair);
|
||||
if (a.is_final_state(tgt_pair.first) && b.is_final_state(tgt_pair.second)) {
|
||||
final.push_back(tgt);
|
||||
}
|
||||
}
|
||||
mvs.push_back(move_t(m, src, tgt, ab));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (final.empty()) {
|
||||
return alloc(automaton_t, m);
|
||||
}
|
||||
vector<moves_t> inv(n, moves_t());
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
move_t const& mv = mvs[i];
|
||||
inv[mv.dst()].push_back(move_t(m, mv.dst(), mv.src(), mv.t()));
|
||||
}
|
||||
|
||||
bool_vector back_reachable(n, false);
|
||||
for (unsigned f : final) {
|
||||
back_reachable[f] = true;
|
||||
}
|
||||
|
||||
unsigned_vector stack(final);
|
||||
while (!stack.empty()) {
|
||||
unsigned state = stack.back();
|
||||
stack.pop_back();
|
||||
moves_t const& mv = inv[state];
|
||||
for (unsigned i = 0; i < mv.size(); ++i) {
|
||||
state = mv[i].dst();
|
||||
if (!back_reachable[state]) {
|
||||
back_reachable[state] = true;
|
||||
stack.push_back(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moves_t mvs1;
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
move_t const& mv = mvs[i];
|
||||
if (back_reachable[mv.dst()]) {
|
||||
mvs1.push_back(mv);
|
||||
}
|
||||
}
|
||||
if (mvs1.empty()) {
|
||||
if (a_init_is_final && b_init_is_final) {
|
||||
// special case: automaton has no moves, but the initial state is final on both sides
|
||||
// this results in the automaton which accepts the empty sequence and nothing else
|
||||
final.clear();
|
||||
final.push_back(0);
|
||||
return alloc(automaton_t, m, 0, final, mvs1);
|
||||
} else {
|
||||
return alloc(automaton_t, m);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return alloc(automaton_t, m, 0, final, mvs1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class M>
|
||||
typename symbolic_automata<T, M>::automaton_t* symbolic_automata<T, M>::mk_difference(automaton_t& a, automaton_t& b) {
|
||||
return mk_product(a,mk_complement(b));
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue