3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-18 06:39:02 +00:00
z3/src/util/top_sort.h
Nikolaj Bjorner 80604c7bc5 na
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2022-06-08 07:00:59 -07:00

141 lines
3.8 KiB
C++

/*++
Copyright (c) 2018 Microsoft Corporation
Module Name:
top_sort.h
Abstract:
Topological sort over objects
Author:
Nikolaj Bjorner (nbjorner) 2018-02-14
Revision History:
--*/
#pragma once
#include<algorithm>
#include<type_traits>
#include<memory.h>
#include "util/obj_hashtable.h"
#include "util/vector.h"
#include "util/memory_manager.h"
#include "util/tptr.h"
template<typename T>
class top_sort {
typedef obj_hashtable<T> T_set;
unsigned_vector m_partition_id;
unsigned_vector m_dfs_num;
ptr_vector<T> m_top_sorted;
ptr_vector<T> m_stack_S;
ptr_vector<T> m_stack_P;
unsigned m_next_preorder;
ptr_vector<T_set> m_deps;
ptr_vector<T> m_dep_keys;
static T_set* add_tag(T_set* t) { return TAG(T_set*, t, 1); }
static T_set* del_tag(T_set* t) { return UNTAG(T_set*, t); }
bool contains_partition(T* f) const {
return m_partition_id.get(f->get_small_id()) != UINT_MAX;
}
void traverse(T* f) {
unsigned p_id = m_dfs_num.get(f->get_small_id(), UINT_MAX);
if (p_id != UINT_MAX) {
if (!contains_partition(f)) {
while (!m_stack_P.empty() && contains_partition(m_stack_P.back()) && partition_id(m_stack_P.back()) > p_id) {
m_stack_P.pop_back();
}
}
}
else if (!contains_dep(f))
return;
else {
m_dfs_num.setx(f->get_small_id(), m_next_preorder, UINT_MAX);
++m_next_preorder;
m_stack_S.push_back(f);
m_stack_P.push_back(f);
T_set* ts = get_dep(f);
if (ts) {
for (T* g : *ts)
traverse(g);
}
if (f == m_stack_P.back()) {
p_id = m_top_sorted.size();
T* s_f;
do {
s_f = m_stack_S.back();
m_stack_S.pop_back();
m_top_sorted.push_back(s_f);
m_partition_id.setx(s_f->get_small_id(), p_id, UINT_MAX);
}
while (s_f != f);
m_stack_P.pop_back();
}
}
}
public:
virtual ~top_sort() {
for (auto * t : m_dep_keys)
dealloc(get_dep(t));
}
void topological_sort() {
m_next_preorder = 0;
m_partition_id.reset();
m_top_sorted.reset();
for (auto * t : m_dep_keys)
traverse(t);
SASSERT(m_stack_S.empty());
SASSERT(m_stack_P.empty());
m_dfs_num.reset();
}
void insert(T* t, T_set* s) {
m_deps.setx(t->get_small_id(), add_tag(s), nullptr);
m_dep_keys.push_back(t);
}
ptr_vector<T> const& deps() { return m_dep_keys; }
void add(T* t, T* s) {
T_set* tb = get_dep(t);
if (!tb) {
tb = alloc(T_set);
insert(t, tb);
}
tb->insert(s);
}
ptr_vector<T> const& top_sorted() const { return m_top_sorted; }
unsigned partition_id(T* t) const { return m_partition_id[t->get_small_id()]; }
bool find(T* t, unsigned& p) const { p = m_partition_id.get(t->get_small_id(), UINT_MAX); return p != UINT_MAX; }
bool contains_dep(T* t) const { return m_deps.get(t->get_small_id(), nullptr) != nullptr; }
T_set* get_dep(T* t) const { return del_tag(m_deps.get(t->get_small_id(), nullptr)); }
bool is_singleton_partition(T* f) const {
unsigned pid = m_partition_id(f);
return f == m_top_sorted[pid] &&
(pid == 0 || partition_id(m_top_sorted[pid-1]) != pid) &&
(pid + 1 == m_top_sorted.size() || partition_id(m_top_sorted[pid+1]) != pid);
}
};