Skip to content

Commit

Permalink
Merge 2741960 into b989f09
Browse files Browse the repository at this point in the history
  • Loading branch information
mogproject committed Feb 21, 2023
2 parents b989f09 + 2741960 commit e5a67c6
Show file tree
Hide file tree
Showing 24 changed files with 637 additions and 407 deletions.
139 changes: 87 additions & 52 deletions src/main/cpp/ds/tree/IntRootedForest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
//================================================================================
// Macros
//================================================================================

// validation: on
// #define VALIDATE(s) s

// validation: off
#define VALIDATE(s)

#define FOR_EACH_CHILD(c, p) for (auto c = nodes_[(p)].first_child; (c) != NOT_AVAILABLE; (c) = nodes_[(c)].right)

namespace ds {
Expand Down Expand Up @@ -109,19 +116,19 @@ class IntRootedForest {
//================================================================================
// array subscript operator for writing
Node& operator[](std::size_t index) {
if (!is_valid(index)) throw std::invalid_argument("invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("invalid index"));
return nodes_[index];
}

// array subscript operator for reading
Node const& operator[](std::size_t index) const {
if (!is_valid(index)) throw std::invalid_argument("invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("invalid index"));
return nodes_[index];
}

// get nodes in the one-level lower
std::vector<int> get_children(int index) const {
if (!is_valid(index)) throw std::invalid_argument("get_children: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("get_children: invalid index"));

std::vector<int> ret;
FOR_EACH_CHILD(c, index) ret.push_back(c);
Expand All @@ -141,7 +148,7 @@ class IntRootedForest {
* leaving: traverse from node to parent
*/
std::vector<std::pair<int, int>> dfs_preorder_edges(int index) const {
if (!is_valid(index)) throw std::invalid_argument("dfs_preorder_edges: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("dfs_preorder_edges: invalid index"));

std::vector<std::pair<int, int>> ret, stack;
stack.push_back({index, false});
Expand All @@ -162,7 +169,7 @@ class IntRootedForest {
}

std::vector<std::pair<int, int>> dfs_reverse_preorder_edges(int index) const {
if (!is_valid(index)) throw std::invalid_argument("dfs_preorder_edges: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("dfs_preorder_edges: invalid index"));

std::vector<std::pair<int, int>> ret, stack;
stack.push_back({index, false});
Expand All @@ -183,7 +190,7 @@ class IntRootedForest {
}

std::vector<int> bfs_nodes(int index) const {
if (!is_valid(index)) throw std::invalid_argument("bfs_nodes: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("bfs_nodes: invalid index"));

std::vector<int> ret;
std::queue<int> q;
Expand All @@ -199,7 +206,7 @@ class IntRootedForest {
}

std::vector<int> dfs_preorder_nodes(int index) const {
if (!is_valid(index)) throw std::invalid_argument("dfs_preorder_nodes: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("dfs_preorder_nodes: invalid index"));

std::vector<int> ret, stack;
stack.push_back(index);
Expand All @@ -216,7 +223,7 @@ class IntRootedForest {
}

std::vector<int> dfs_reverse_preorder_nodes(int index) const {
if (!is_valid(index)) throw std::invalid_argument("dfs_reverse_preorder_nodes: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("dfs_reverse_preorder_nodes: invalid index"));

std::vector<int> ret, stack;
stack.push_back(index);
Expand All @@ -238,7 +245,7 @@ class IntRootedForest {
* @return std::vector<int>
*/
std::vector<int> get_leaves(int index) const {
if (!is_valid(index)) throw std::invalid_argument("get_leaves: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("get_leaves: invalid index"));

std::vector<int> ret;
for (auto x : dfs_reverse_preorder_nodes(index)) {
Expand All @@ -248,15 +255,15 @@ class IntRootedForest {
}

std::vector<int> get_ancestors(int index) const {
if (!is_valid(index)) throw std::invalid_argument("get_ancestors: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("get_ancestors: invalid index"));

std::vector<int> ret;
for (auto p = nodes_[index].parent; p != NOT_AVAILABLE; p = nodes_[p].parent) ret.push_back(p);
return ret;
}

int get_root(int index) const {
if (!is_valid(index)) throw std::invalid_argument("get_root: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("get_root: invalid index"));

int ret = NOT_AVAILABLE;
for (auto p = index; p != NOT_AVAILABLE; p = nodes_[p].parent) ret = p;
Expand Down Expand Up @@ -311,9 +318,9 @@ class IntRootedForest {
}

void remove(int index) {
if (!is_valid(index)) throw std::invalid_argument("remove: invalid index");
VALIDATE(if (!is_valid(index)) throw std::invalid_argument("remove: invalid index"));
detach(index);
if (!nodes_[index].is_leaf()) throw std::invalid_argument("remove: must be a leaf");
VALIDATE(if (!nodes_[index].is_leaf()) throw std::invalid_argument("remove: must be a leaf"));

--num_live_nodes_;
nodes_[index].alive = false;
Expand All @@ -325,12 +332,16 @@ class IntRootedForest {
//================================================================================
private:
void add_child(int parent, int child) {
if (!is_valid(parent)) throw std::invalid_argument("add_child: parent invalid index");
if (!is_valid(child)) throw std::invalid_argument("add_child: child invalid index");
VALIDATE({
if (!is_valid(parent)) throw std::invalid_argument("add_child: parent invalid index");
if (!is_valid(child)) throw std::invalid_argument("add_child: child invalid index");
});
auto& p = nodes_[parent];
auto& c = nodes_[child];

if (!c.is_root()) throw std::invalid_argument("add_child: child must be a root");
VALIDATE({
if (!c.is_root()) throw std::invalid_argument("add_child: child must be a root");
});

if (p.has_child()) {
nodes_[p.first_child].left = child;
Expand All @@ -344,7 +355,9 @@ class IntRootedForest {

public:
void detach(int index) {
if (!is_valid(index)) throw std::invalid_argument("detach: invalid index");
VALIDATE({
if (!is_valid(index)) throw std::invalid_argument("detach: invalid index");
});

auto& node = nodes_[index];
if (node.parent != NOT_AVAILABLE) nodes_[node.parent].num_children--;
Expand All @@ -358,10 +371,11 @@ class IntRootedForest {
};

void swap(int a, int b) {
if (!is_valid(a)) throw std::invalid_argument("swap: a invalid index");
if (!is_valid(b)) throw std::invalid_argument("swap: b invalid index");
if (get_root(a) == get_root(b)) throw std::invalid_argument("swap: a and b must belong to different trees");

VALIDATE({
if (!is_valid(a)) throw std::invalid_argument("swap: a invalid index");
if (!is_valid(b)) throw std::invalid_argument("swap: b invalid index");
if (get_root(a) == get_root(b)) throw std::invalid_argument("swap: a and b must belong to different trees")
});
// if (a == b) return; // never happens

auto& na = nodes_[a];
Expand All @@ -386,20 +400,25 @@ class IntRootedForest {
* @param replace_by not to replace
*/
void replace(int index, int replace_by) {
if (!is_valid(index)) throw std::invalid_argument("replace: invalid index");
if (!is_valid(replace_by)) throw std::invalid_argument("replace: replace_by invalid index");
if (index == replace_by) throw std::invalid_argument("replace: replace_by must differ from index");
if (util::contains(get_ancestors(index), replace_by))
throw std::invalid_argument("replace: replace_by cannot be an ancestor of index");
VALIDATE({
if (!is_valid(index)) throw std::invalid_argument("replace: invalid index");
if (!is_valid(replace_by)) throw std::invalid_argument("replace: replace_by invalid index");
if (index == replace_by) throw std::invalid_argument("replace: replace_by must differ from index");
if (util::contains(get_ancestors(index), replace_by)) {
throw std::invalid_argument("replace: replace_by cannot be an ancestor of index");
}
});

detach(replace_by);
swap(index, replace_by);
}

void move_to(int index, int new_parent) {
if (!is_valid(index)) throw std::invalid_argument("move_to: invalid index");
if (!is_valid(new_parent)) throw std::invalid_argument("move_to: new_parent invalid index");
if (index == new_parent) throw std::invalid_argument("move_to: index and new_parent cannot be the same");
VALIDATE({
if (!is_valid(index)) throw std::invalid_argument("move_to: invalid index");
if (!is_valid(new_parent)) throw std::invalid_argument("move_to: new_parent invalid index");
if (index == new_parent) throw std::invalid_argument("move_to: index and new_parent cannot be the same");
});

detach(index);
add_child(new_parent, index);
Expand All @@ -410,12 +429,15 @@ class IntRootedForest {
* @param node node that is not a root
*/
void move_to_before(int index, int target) {
if (!is_valid(index)) throw std::invalid_argument("move_to_after: invalid index");
if (!is_valid(target)) throw std::invalid_argument("move_to_after: target invalid index");
if (nodes_[target].is_root()) throw std::invalid_argument("move_to_before: target must not be a root");
if (index == target) throw std::invalid_argument("move_to_after: index and target cannot be the same");
if (util::contains(get_ancestors(target), index))
throw std::invalid_argument("replace: index cannot be an ancestor of target");
VALIDATE({
if (!is_valid(index)) throw std::invalid_argument("move_to_after: invalid index");
if (!is_valid(target)) throw std::invalid_argument("move_to_after: target invalid index");
if (nodes_[target].is_root()) throw std::invalid_argument("move_to_before: target must not be a root");
if (index == target) throw std::invalid_argument("move_to_after: index and target cannot be the same");
if (util::contains(get_ancestors(target), index)) {
throw std::invalid_argument("replace: index cannot be an ancestor of target");
}
});

detach(index);

Expand All @@ -437,12 +459,15 @@ class IntRootedForest {
* @param node node that is not a root
*/
void move_to_after(int index, int target) {
if (!is_valid(index)) throw std::invalid_argument("move_to_after: invalid index");
if (!is_valid(target)) throw std::invalid_argument("move_to_after: target invalid index");
if (nodes_[target].is_root()) throw std::invalid_argument("move_to_after: target must not be a root");
if (index == target) throw std::invalid_argument("move_to_after: index and target cannot be the same");
if (util::contains(get_ancestors(target), index))
throw std::invalid_argument("move_to_after: index cannot be an ancestor of target");
VALIDATE({
if (!is_valid(index)) throw std::invalid_argument("move_to_after: invalid index");
if (!is_valid(target)) throw std::invalid_argument("move_to_after: target invalid index");
if (nodes_[target].is_root()) throw std::invalid_argument("move_to_after: target must not be a root");
if (index == target) throw std::invalid_argument("move_to_after: index and target cannot be the same");
if (util::contains(get_ancestors(target), index)) {
throw std::invalid_argument("move_to_after: index cannot be an ancestor of target");
}
});

detach(index);

Expand All @@ -462,7 +487,9 @@ class IntRootedForest {
* @brief Moves this node to the first among all its siblings.
*/
void make_first_child(int index) {
if (!is_valid(index)) throw std::invalid_argument("make_first_child: invalid index");
VALIDATE({
if (!is_valid(index)) throw std::invalid_argument("make_first_child: invalid index");
});

if (nodes_[index].is_root() || nodes_[index].is_first_child()) return; // do nothing

Expand All @@ -474,10 +501,13 @@ class IntRootedForest {
* @param node node whose children are to be added to this node's children
*/
void add_children_from(int index, int target) {
if (!is_valid(index)) throw std::invalid_argument("add_children_from: invalid index");
if (!is_valid(target)) throw std::invalid_argument("add_children_from: target invalid index");
if (util::contains(get_ancestors(index), target))
throw std::invalid_argument("add_children_from: target cannot be an ancestor of index");
VALIDATE({
if (!is_valid(index)) throw std::invalid_argument("add_children_from: invalid index");
if (!is_valid(target)) throw std::invalid_argument("add_children_from: target invalid index");
if (util::contains(get_ancestors(index), target)) {
throw std::invalid_argument("add_children_from: target cannot be an ancestor of index");
}
});

if (index == target) return; // do nothing

Expand All @@ -504,12 +534,17 @@ class IntRootedForest {
* This original node will be detached form its tree but not removed.
*/
void replace_by_children(int index) {
if (!is_valid(index)) throw std::invalid_argument("replace_by_children: invalid index");
auto& node = nodes_[index];
if (node.is_root()) throw std::invalid_argument("replace_by_children:this must not be a root");

auto ch = get_children(index);
for (auto c : ch) move_to_before(c, index);
VALIDATE({
if (!is_valid(index)) throw std::invalid_argument("replace_by_children: invalid index");
auto& node = nodes_[index];
if (node.is_root()) throw std::invalid_argument("replace_by_children:this must not be a root");
});

for (auto c = nodes_[index].first_child; c != NOT_AVAILABLE;) {
auto nxt = nodes_[c].right;
move_to_before(c, index);
c = nxt;
}
detach(index);
}

Expand Down
6 changes: 6 additions & 0 deletions src/main/cpp/modular-bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ int main(int argc, char* argv[]) {
auto graph = readwrite::read_edge_list(std::cin);

// run algorithm
#if PROFILE_ON
util::Profiler prof;
auto result = modular::modular_decomposition_time(graph, true, &prof);
prof.print();
#else
auto result = modular::modular_decomposition_time(graph, true);
#endif

// output result
printf("%d\n", result.first.modular_width());
Expand Down
4 changes: 2 additions & 2 deletions src/main/cpp/modular/MDTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ std::ostream &operator<<(std::ostream &os, MDNode const &node) { return os << no

MDTree modular_decomposition(ds::graph::Graph const &graph, bool sorted) { return MDTree(graph, sorted); }

std::pair<MDTree, double> modular_decomposition_time(ds::graph::Graph const &graph, bool sorted) {
std::pair<MDTree, double> modular_decomposition_time(ds::graph::Graph const &graph, bool sorted, util::Profiler *prof) {
auto time_start = std::chrono::system_clock::now();
auto ret = MDTree(graph, false);
auto ret = MDTree(graph, false, prof);
auto time_finish = std::chrono::system_clock::now();
auto elapsed = time_finish - time_start;
auto elapsed_sec = std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count() * 1e-9;
Expand Down
9 changes: 6 additions & 3 deletions src/main/cpp/modular/MDTree.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include "util/profiler.hpp"

#include "compute/MDSolver.hpp"

namespace modular {
Expand Down Expand Up @@ -47,8 +49,8 @@ class MDTree {

public:
MDTree() : root_(-1){};
MDTree(ds::graph::Graph const &graph, bool sorted = false) {
auto result = compute::MDSolver::compute(graph);
MDTree(ds::graph::Graph const &graph, bool sorted = false, util::Profiler *prof = nullptr) {
auto result = compute::MDSolver::compute(graph, prof);
if (result.second >= 0) {
*this = MDTree(result.first, result.second);
if (sorted) this->sort();
Expand Down Expand Up @@ -160,5 +162,6 @@ class MDTree {

MDTree modular_decomposition(ds::graph::Graph const &graph, bool sorted = false);

std::pair<MDTree, double> modular_decomposition_time(ds::graph::Graph const &graph, bool sorted = false);
std::pair<MDTree, double> modular_decomposition_time(ds::graph::Graph const &graph, bool sorted = false,
util::Profiler *prof = nullptr);
} // namespace modular
Loading

0 comments on commit e5a67c6

Please sign in to comment.