diff --git a/Makefile b/Makefile index cd8ce569c491030038d63946d3d890869a0546f0..11e6bc41bdd1d732445ec8e2773fed35e520dc5a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,17 @@ CXXFLAGS = -O0 -g -std=c++2a -Wall -Wextra -Wpedantic +dynamic_test: dynamic_test.o tree_representative.o dynamic_node.o + $(CXX) $(CXXFLAGS) -o $@ $^ + +dynamic_test.o: dynamic_test.cpp dynamic_node.o + $(CXX) $(CXXFLAGS) -c $< + +tree_representative.o: tree_representative.cpp dynamic_node.h + $(CXX) $(CXXFLAGS) -c $< + +dynamic_node.o: dynamic_node.cpp dynamic_node.h biased_binary_node.o + $(CXX) $(CXXFLAGS) -c $< + biased_test: tree_test.o $(CXX) $(CXXFLAGS) -o $@ $^ @@ -13,6 +25,6 @@ biased_binary_node.o: biased_binary_node.cpp biased_binary_node.h $(CXX) $(CXXFLAGS) -c $< clean: - rm -f *.o biased_test + rm -f *.o *.gch biased_test dynamic_test .PHONY: clean diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f4203f54b6456fc835b98ab252f9fa043873dd8a --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +Purpose +=== +This was supposed to be a implementation of the _"Dynamic Tree"_ data structure described in **[1]**. Specifically using the recommended _"Biased (Binary) Tree"_ data structure described in **[2]**. Sadly this could not be accomplished in time for submission. + +Supported Operations +=== +At time of submission the _BiasedBinaryTree<T>_ supports splitting and joining, which are the key operations needed for an efficient implementation of the Algorithm described in **[3]**. A test of these can be compiled using **make biased_test**. + +_TreeRepresentative_:_BiasedBinaryTree<DynamicAddon>_ is the type maintaining the binary tree structure described in **[1]** and is supposed to maintain _DynamicAddon_'s invariants. It is currently mostly a skeleton. + +_DynamicAddon_ is the Type providing most of the functionality. Its implementation, too, is incomplete. + +Plans +=== +If changes will be made they will go to a different branch, meaning the current state will be archived for evaluation. It seems unlikely that any pushes will be made during the exam period. + +--- +* **[1]** Daniel D. Sleator, Robert Endre Tarjan _A Data Structure for Dynamic Trees_ Journal of Computer and System Science (1983) +* **[2]** Samuel W. Bent, Daniel D. Sleator, Robert E. Tarjan _Biased Search Trees_ Society for Industrial and Applied Mathematics (1985) +* **[3]** Ravindra K. Ahuja, Dorit S. Hochbaum, James B. Orlin _Solving the Convex Cost Integer Dual Network Flow Problem_ Management Science (2003) diff --git a/biased_binary_node.cpp b/biased_binary_node.cpp index 93e1c1dcde4c31486e27a64b02245fc28ad2f165..3bb5a1bbb45c0efbccfe64f3ce92a0146316ae9d 100644 --- a/biased_binary_node.cpp +++ b/biased_binary_node.cpp @@ -177,7 +177,7 @@ std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::local_join(std::shared } template <typename T> -void BiasedBinaryNode<T>::split_at(std::shared_ptr<BiasedBinaryNode<T>> split_pos, std::shared_ptr<BiasedBinaryNode<T>>& before, std::shared_ptr<BiasedBinaryNode<T>>& after){ +void BiasedBinaryNode<T>::split_at(std::shared_ptr<BiasedBinaryNode<T>> split_pos,std::shared_ptr<BiasedBinaryNode<T>>& before, std::shared_ptr<BiasedBinaryNode<T>>& after, std::shared_ptr<BiasedBinaryNode<T>>& removed_interior_parent, std::shared_ptr<BiasedBinaryNode<T>>& removed_interior_root){ #ifdef PROTOCOL std::cout << "\033[36mSplitting\033[0m" << std::endl; std::cout << *this; @@ -201,26 +201,28 @@ void BiasedBinaryNode<T>::split_at(std::shared_ptr<BiasedBinaryNode<T>> split_po #endif std::shared_ptr<BiasedBinaryNode<T>> parent_lock = split_pos->parent().lock(); if(parent_lock == nullptr){ + removed_interior_root = this->me(); return; }else if(split_pos->is_left_child()){ if(parent_lock->right_child() != nullptr){ - after = parent_lock->right_child()->global_join(after); + after = parent_lock->right_child()->global_join(after, parent_lock); after->parent().reset(); } }else{ if(parent_lock->left_child() != nullptr){ - before = parent_lock->left_child()->global_join(before); + before = parent_lock->left_child()->global_join(before, parent_lock); before->parent().reset(); } } parent_lock->right_child().reset(); //orphan one side and disconnect the joined tree from the remaining nodes parent_lock->left_child().reset(); split_pos.reset(); - this->split_at(parent_lock, before, after); + this->split_at(parent_lock, before, after, removed_interior_parent, removed_interior_root); + removed_interior_parent = parent_lock; } template <typename T> -std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::global_join(std::shared_ptr<BiasedBinaryNode<T>> other){ +std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::global_join(std::shared_ptr<BiasedBinaryNode<T>> other, std::shared_ptr<BiasedBinaryNode> connector_node){ #ifdef PROTOCOL std::cout << "\033[36mJoin\033[0m" << std::endl; std::cout << *this; @@ -239,7 +241,13 @@ std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::global_join(std::share std::cout << "Case 1" << std::endl; #endif std::weak_ptr<BiasedBinaryNode<T>> old_parent = this->parent(); - std::shared_ptr<BiasedBinaryNode<T>> new_common_parent = std::make_shared<BiasedBinaryNode<T>>(std::max(this->rank(), other->rank())+1); + std::shared_ptr<BiasedBinaryNode<T>> new_common_parent; + if(connector_node != nullptr){ + connector_node->rank() = std::max(this->rank(), other->rank())+1; + new_common_parent = connector_node; + }else{ + new_common_parent = std::make_shared<BiasedBinaryNode<T>>(std::max(this->rank(), other->rank())+1); + } new_common_parent->rewire_left_child_with(this->me()); new_common_parent->rewire_right_child_with(other); new_common_parent->parent() = old_parent; diff --git a/biased_binary_node.h b/biased_binary_node.h index 9b81b2d2c8cd2e6aa729506532b1dcbd5dac2d58..3f070f0c88c9bd53142f520071eeeb91cee8de79 100644 --- a/biased_binary_node.h +++ b/biased_binary_node.h @@ -24,10 +24,10 @@ private: std::weak_ptr<BiasedBinaryNode<T>> _parent; std::shared_ptr<BiasedBinaryNode<T>> _left_child; std::shared_ptr<BiasedBinaryNode<T>> _right_child; - - std::shared_ptr<BiasedBinaryNode<T>> tilt_right(); - std::shared_ptr<BiasedBinaryNode<T>> tilt_left(); - std::shared_ptr<BiasedBinaryNode<T>> local_join(std::shared_ptr<BiasedBinaryNode<T>>); +protected: + virtual std::shared_ptr<BiasedBinaryNode<T>> tilt_right(); + virtual std::shared_ptr<BiasedBinaryNode<T>> tilt_left(); + virtual std::shared_ptr<BiasedBinaryNode<T>> local_join(std::shared_ptr<BiasedBinaryNode<T>>); public: BiasedBinaryNode(unsigned long); ~BiasedBinaryNode(); @@ -43,15 +43,14 @@ public: std::shared_ptr<BiasedBinaryNode<T>>& left_child(); std::shared_ptr<BiasedBinaryNode<T>>& right_child(); - void rewire_right_child_with(std::shared_ptr<BiasedBinaryNode<T>>); - void rewire_left_child_with(std::shared_ptr<BiasedBinaryNode<T>>); - void replace_with(std::shared_ptr<BiasedBinaryNode<T>>); + virtual void rewire_right_child_with(std::shared_ptr<BiasedBinaryNode<T>>); + virtual void rewire_left_child_with(std::shared_ptr<BiasedBinaryNode<T>>); + virtual void replace_with(std::shared_ptr<BiasedBinaryNode<T>>); - void split_at(std::shared_ptr<BiasedBinaryNode<T>> split_pos,std::shared_ptr<BiasedBinaryNode<T>>& before, std::shared_ptr<BiasedBinaryNode<T>>& after); - std::shared_ptr<BiasedBinaryNode<T>> global_join(std::shared_ptr<BiasedBinaryNode<T>>); + virtual void split_at(std::shared_ptr<BiasedBinaryNode<T>> split_pos,std::shared_ptr<BiasedBinaryNode<T>>& before, std::shared_ptr<BiasedBinaryNode<T>>& after, std::shared_ptr<BiasedBinaryNode<T>>& removed_interior_parent, std::shared_ptr<BiasedBinaryNode<T>>& removed_interior_root); + virtual std::shared_ptr<BiasedBinaryNode<T>> global_join(std::shared_ptr<BiasedBinaryNode<T>>, std::shared_ptr<BiasedBinaryNode<T>> = nullptr); }; - #include "biased_binary_node.cpp" #endif diff --git a/biased_binary_tree.cpp b/biased_binary_tree.cpp index 1101c8325ca8806e1bff2c8421ba0024cd1c4e17..840c32b8efcbfac11f95c052ed7f55d2d3919cb6 100644 --- a/biased_binary_tree.cpp +++ b/biased_binary_tree.cpp @@ -22,10 +22,10 @@ void BiasedBinaryTree<T>::join(BiasedBinaryTree<T> other){ } template <typename T> -void BiasedBinaryTree<T>::split_at(std::shared_ptr<BiasedBinaryNode<T>> split_pos,BiasedBinaryTree<T>& before, BiasedBinaryTree<T>& after){ +void BiasedBinaryTree<T>::split_at(std::shared_ptr<BiasedBinaryNode<T>> split_pos,BiasedBinaryTree<T>& before, BiasedBinaryTree<T>& after, std::shared_ptr<BiasedBinaryNode<T>> removed_interior_parent, std::shared_ptr<BiasedBinaryNode<T>> removed_interior_root){ std::shared_ptr<BiasedBinaryNode<T>> root_before; std::shared_ptr<BiasedBinaryNode<T>> root_after; - this->root()->split_at(split_pos, root_before, root_after); + this->root()->split_at(split_pos, root_before, root_after, removed_interior_parent, removed_interior_root); before = BiasedBinaryTree<T>(root_before); after = BiasedBinaryTree<T>(root_after); } diff --git a/biased_binary_tree.h b/biased_binary_tree.h index 23a527fd0a2fd2d4eca85f20349c778568349529..41f2d6c3b2bd9f097af7ba72251d274134af7dff 100644 --- a/biased_binary_tree.h +++ b/biased_binary_tree.h @@ -19,7 +19,7 @@ public: std::shared_ptr<BiasedBinaryNode<T>>& root(); void join(BiasedBinaryTree<T>); - void split_at(std::shared_ptr<BiasedBinaryNode<T>>, BiasedBinaryTree<T>&, BiasedBinaryTree<T>&); + void split_at(std::shared_ptr<BiasedBinaryNode<T>>, BiasedBinaryTree<T>&, BiasedBinaryTree<T>&, std::shared_ptr<BiasedBinaryNode<T>>, std::shared_ptr<BiasedBinaryNode<T>>); }; #include "biased_binary_tree.cpp" diff --git a/dynamic_node.cpp b/dynamic_node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19e4bc176cc2730a35f3c853e04428738fb594be --- /dev/null +++ b/dynamic_node.cpp @@ -0,0 +1,88 @@ +#include "dynamic_node.h" +#include <cfloat> + +void DynamicNode::decode_rel_struct_w(){ + this->_relative_structure_weight = this->min_path_weight(); + this->_rel_struct_encoded = false; +} + +void DynamicNode::decode_rel_path_and_struct_w(){ + this->decode_rel_struct_w(); + this->_relative_path_weight += this->_relative_structure_weight; + this->_rel_path_encoded = false; +} + +void DynamicNode::encode_rel_path_and_struct_w(){ + double min = DBL_MAX; + if(this->node()->left_child() != nullptr){ + min = std::min(min, this->node()->left_child()->value()->_relative_structure_weight); + } + if(this->node()->right_child() != nullptr){ + min = std::min(min, this->node()->right_child()->value()->_relative_structure_weight); + } + if(min == DBL_MAX){ // the node appears to be a leave, meaning that no edge cost can possibly be represented + this->_relative_path_weight = 0; + this->_relative_structure_weight = 0; + this->_rel_path_encoded = true; + this->_rel_struct_encoded = true; + return; + } + this->_relative_structure_weight = min-this->node()->parent().lock()->value()->min_path_weight(); + this->_rel_struct_encoded = true; + if(this->node()->left_child() != nullptr){ + this->node()->left_child()->value()->_relative_structure_weight -= min; + this->node()->left_child()->value()->_rel_struct_encoded = true; + } + if(this->node()->right_child() != nullptr){ + this->node()->right_child()->value()->_relative_structure_weight -= min; + this->node()->right_child()->value()->_rel_struct_encoded = true; + } + this->_relative_path_weight -= min; + this->_rel_path_encoded = true; +} + +std::shared_ptr<TreeRepresentative> DynamicNode::node(){ + return this->_node; +} + +bool& DynamicNode::reversed(){ + return this->_reversed; +} + +DynamicNode::DynamicNode(unsigned long rank) : _node(std::make_shared<TreeRepresentative>(rank)) { + this->_reversed = false; + this->_relative_path_weight = 0; + this->_relative_structure_weight = 0; +} + +bool DynamicNode::global_reversed(){ + if(this->node()->parent().lock() == nullptr) return this->reversed(); + int rec_val = this->node()->parent().lock()->value()->global_reversed(); + return (rec_val+this->reversed()) % 2; +} + +void DynamicNode::reverse(){ + this->reversed() = (this->reversed() + 1) % 2; +} + +double DynamicNode::weight(){ + if(!this->_rel_path_encoded) return this->_relative_path_weight; + return this->_relative_path_weight+this->min_path_weight(); +} + +double DynamicNode::min_path_weight(){ + if(!this->_rel_struct_encoded) return this->_relative_structure_weight; + auto parent_lock = this->node()->parent().lock(); + if(parent_lock == nullptr) return this->_relative_structure_weight; + return this->_relative_structure_weight + parent_lock->value()->min_path_weight(); +} + +double DynamicNode::send(double amount){ + auto parent_lock = this->node()->parent().lock(); + if(parent_lock == nullptr){ + double send_amount = std::min(this->_relative_structure_weight, amount); + this->_relative_structure_weight -= send_amount; + return send_amount; + } + return parent_lock->value()->send(amount); +} diff --git a/dynamic_node.h b/dynamic_node.h new file mode 100644 index 0000000000000000000000000000000000000000..2ef5892698932a53a33950b93ac8fc81b008e16d --- /dev/null +++ b/dynamic_node.h @@ -0,0 +1,71 @@ +#ifndef DYNAMIC_NODE_H +#define DYNAMIC_NODE_H + +#include "biased_binary_node.h" +#include <algorithm> + +class DynamicNode; + +/* + class overrides operator so that DynamicNode(see below) can support its invariants +*/ +class TreeRepresentative : public BiasedBinaryNode<DynamicNode*>{ +protected: + std::shared_ptr<BiasedBinaryNode<DynamicNode*>> tilt_right(); + std::shared_ptr<BiasedBinaryNode<DynamicNode*>> tilt_left(); + std::shared_ptr<BiasedBinaryNode<DynamicNode*>> local_join(std::shared_ptr<BiasedBinaryNode<DynamicNode*>>); +public: + TreeRepresentative(unsigned long); + + void rewire_right_child_with(std::shared_ptr<BiasedBinaryNode<DynamicNode*>>); + void rewire_left_child_with(std::shared_ptr<BiasedBinaryNode<DynamicNode*>>); + void replace_with(std::shared_ptr<BiasedBinaryNode<DynamicNode*>>); + + void split_at(std::shared_ptr<BiasedBinaryNode<DynamicNode*>> split_pos,std::shared_ptr<BiasedBinaryNode<DynamicNode*>>& before, std::shared_ptr<BiasedBinaryNode<DynamicNode*>>& after, std::shared_ptr<BiasedBinaryNode<DynamicNode*>>& removed_interior_parent, std::shared_ptr<BiasedBinaryNode<DynamicNode*>>& removed_interior_root); + std::shared_ptr<BiasedBinaryNode<DynamicNode*>> global_join(std::shared_ptr<BiasedBinaryNode<DynamicNode*>>, std::shared_ptr<BiasedBinaryNode<DynamicNode*>> = nullptr); +}; + +/* + Realizes Sleator and Tarjans Dynamic Tree Datastruct (using Biased Trees) +*/ +class DynamicNode{ + friend TreeRepresentative; + std::shared_ptr<TreeRepresentative> const _node; + + bool _reversed; + + double _relative_path_weight; // netcost in paper + bool _rel_path_encoded; + double _relative_structure_weight; // netmin in paper + bool _rel_struct_encoded; + + void decode_rel_path_and_struct_w(); + void encode_rel_path_and_struct_w(); + void decode_rel_struct_w(); +protected: + std::shared_ptr<TreeRepresentative> node(); + bool& reversed(); +public: + DynamicNode(unsigned long); + + bool global_reversed(); + void reverse(); + + double weight(); // for interior nodes + double min_path_weight(); // " + double send(double); // Pushes along the entire path to which the current node belongs + + + std::shared_ptr<TreeRepresentative>& head(); // implementation differes from paper + std::shared_ptr<TreeRepresentative>& tail(); // " + + std::shared_ptr<TreeRepresentative>& before(); // for leaves + std::shared_ptr<TreeRepresentative>& after(); // " + +private: + // other data to reflect Graph + bool is_leaf(); + std::vector<DynamicNode> reachable; +}; + +#endif diff --git a/dynamic_test.cpp b/dynamic_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10da60743a6201235a24920de53825555519d69b --- /dev/null +++ b/dynamic_test.cpp @@ -0,0 +1,10 @@ +#include "dynamic_node.h" +#include <iostream> + +int main(){ + DynamicNode node (5); + std::cout << node.global_reversed() << std::endl; + node.reverse(); + std::cout << node.global_reversed() << std::endl; + return 0; +} diff --git a/tree_representative.cpp b/tree_representative.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2981dd6add13a2a94cb279c6933288560e06339e --- /dev/null +++ b/tree_representative.cpp @@ -0,0 +1,52 @@ +#include "dynamic_node.h" + + +TreeRepresentative::TreeRepresentative(unsigned long rank) : BiasedBinaryNode<DynamicNode*>(rank) {} + +std::shared_ptr<BiasedBinaryNode<DynamicNode*>> TreeRepresentative::tilt_right(){ + auto other = this->left_child(); + if(other == nullptr) return this->me(); + this->value()->decode_rel_path_and_struct_w(); + other->value()->decode_rel_path_and_struct_w(); + + if(other->left_child() != nullptr) other->left_child()->value()->decode_rel_struct_w(); + if(other->right_child() != nullptr) other->right_child()->value()->decode_rel_struct_w(); + if(this->right_child() != nullptr) this->right_child()->value()->decode_rel_struct_w(); + + auto new_root = BiasedBinaryNode<DynamicNode*>::tilt_right(); + + if(this->left_child() == other){ + other->value()->encode_rel_path_and_struct_w(); + this->value()->encode_rel_path_and_struct_w(); + }else{ + this->value()->encode_rel_path_and_struct_w(); + other->value()->encode_rel_path_and_struct_w(); + } + return new_root; +} + +std::shared_ptr<BiasedBinaryNode<DynamicNode*>> TreeRepresentative::tilt_left(){ + auto other = this->right_child(); + if(other == nullptr) return this->me(); + this->value()->decode_rel_path_and_struct_w(); + other->value()->decode_rel_path_and_struct_w(); + + if(other->left_child() != nullptr) other->left_child()->value()->decode_rel_struct_w(); + if(other->right_child() != nullptr) other->right_child()->value()->decode_rel_struct_w(); + if(this->left_child() != nullptr) this->left_child()->value()->decode_rel_struct_w(); + + auto new_root = BiasedBinaryNode<DynamicNode*>::tilt_right(); + + if(this->right_child() == other){ + other->value()->encode_rel_path_and_struct_w(); + this->value()->encode_rel_path_and_struct_w(); + }else{ + this->value()->encode_rel_path_and_struct_w(); + other->value()->encode_rel_path_and_struct_w(); + } + return new_root; +} + +void TreeRepresentative::rewire_right_child_with(std::shared_ptr<BiasedBinaryNode<DynamicNode*>> new_child){ + +} diff --git a/tree_test.cpp b/tree_test.cpp index 420b02ff3970c9f1346610468924b0d5fad63d0a..53105250c1db58f169b45c5e0b0c92d50a5f04af 100644 --- a/tree_test.cpp +++ b/tree_test.cpp @@ -21,7 +21,8 @@ int main(){ BiasedBinaryTree<int> after; std::cout << "-.-.-.-" << std::endl; std::cout << "use_count : " << split_pos.use_count() << std::endl; - start.split_at(split_pos, before, after); + std::shared_ptr<BiasedBinaryNode<int>> removed_parent, removed_root; + start.split_at(split_pos, before, after, removed_parent, removed_root); std::cout << "----------------" << std::endl; std::cout << before; std::cout << "----------------" << std::endl;