diff --git a/arbor/tree.hpp b/arbor/tree.hpp index af0fb4bbee783cde19114480247d6006cb9700eb..5adb6f6d92995ec8064ac975daf03120954713d1 100644 --- a/arbor/tree.hpp +++ b/arbor/tree.hpp @@ -18,15 +18,12 @@ public: using int_type = cell_lid_type; using size_type = cell_local_size_type; - using iarray = memory::host_vector<int_type>; - using view_type = typename iarray::view_type; - using const_view_type = typename iarray::const_view_type; + using iarray = std::vector<int_type>; static constexpr int_type no_parent = (int_type)-1; tree() = default; tree& operator=(tree&& other) { - std::swap(data_, other.data_); std::swap(child_index_, other.child_index_); std::swap(children_, other.children_); std::swap(parents_, other.parents_); @@ -34,8 +31,9 @@ public: } tree& operator=(tree const& other) { - data_ = other.data_; - set_ranges(other.num_segments()); + children_ = other.children_; + child_index_ = other.child_index_; + parents_ = other.child_index_; return *this; } @@ -92,22 +90,24 @@ public: } /// return the child index - const_view_type child_index() { + const iarray& child_index() { return child_index_; } /// return the list of all children - const_view_type children() const { + const iarray& children() const { return children_; } - /// return the list of all children of branch b - const_view_type children(size_type b) const { - return children_(child_index_[b], child_index_[b+1]); + /// return the list of all children of branch i + auto children(size_type i) const { + const auto b = child_index_[i]; + const auto e = child_index_[i+1]; + return util::subrange_view(children_, b, e); } /// return the list of parents - const_view_type parents() const { + const iarray& parents() const { return parents_; } @@ -121,166 +121,29 @@ public: /// memory used to store tree (in bytes) std::size_t memory() const { - return sizeof(int_type)*data_.size() + sizeof(tree); - } - - iarray change_root(size_t b) { - assert(b<num_segments()); - - // no need to rebalance if the root node has been requested - if(b==0) { - return iarray(); - } - - // create new tree with memory allocated - tree new_tree; - new_tree.init(num_segments()); - - // add the root node - new_tree.parents_[0] = no_parent; - new_tree.child_index_[0] = 0; - - // allocate space for the permutation vector that - // will represent the permutation performed on the branches - // during the rebalancing - iarray p(num_segments(), -1); - - // recersively rebalance the tree - new_tree.add_children(0, b, 0, p, *this); - - // renumber the child indexes - std::transform( - new_tree.children_.begin(), new_tree.children_.end(), - new_tree.children_.begin(), [&p] (int i) {return p[i];} - ); - - // copy in new data with a move because the information in - // new_tree is not kept - std::swap(data_, new_tree.data_); - set_ranges(new_tree.num_segments()); - - return p; + return sizeof(int_type)*(children_.size()+child_index_.size()+parents_.size()) + + sizeof(tree); } private: void init(size_type nnode) { - auto nchild = nnode - 1; - - data_ = iarray(nchild + (nnode + 1) + nnode); - set_ranges(nnode); - } - - void set_ranges(size_type nnode) { if (nnode) { auto nchild = nnode - 1; - // data_ is partitioned as follows: - // data_ = [children_[nchild], child_index_[nnode+1], parents_[nnode]] - assert(data_.size() == unsigned(nchild + (nnode+1) + nnode)); - children_ = data_(0, nchild); - child_index_ = data_(nchild, nchild+nnode+1); - parents_ = data_(nchild+nnode+1, memory::end); - - // check that arrays have appropriate size - // this should be moved into a unit test - assert(children_.size() == unsigned(nchild)); - assert(child_index_.size() == unsigned(nnode+1)); - assert(parents_.size() == unsigned(nnode)); + children_.resize(nchild); + child_index_.resize(nnode+1); + parents_.resize(nnode); } else { - children_ = data_(0, 0); - child_index_ = data_(0, 0); - parents_ = data_(0, 0); - } - } - - /// Renumber the sub-tree with old_node as its root with new_node as - /// the new index of old_node. This is a helper function for the - /// renumbering required when a new root node is chosen to improve - /// the balance of the tree. - /// Optionally add the parent of old_node as a child of new_node, which - /// will be applied recursively until the old root has been processed, - /// which indicates that the renumbering is finished. - /// - /// precondition - the node new_node has already been placed in the tree - /// precondition - all of new_node's children have been added to the tree - /// new_node : the new index of the node whose children are to be added - /// to the tree - /// old_node : the index of new_node in the original tree - /// parent_node : equals index of old_node's parent in the original tree - /// should be a child of new_node - /// : equals -1 if the old_node's parent is not a child of - /// new_node - /// p : permutation vector, p[i] is the new index of node i in the old - /// tree - int_type add_children( - int_type new_node, - int_type old_node, - int_type parent_node, - view_type p, - tree const& old_tree - ) - { - // check for the sentinel that indicates that the old root has - // been processed - if (old_node==no_parent) { - return new_node; + children_.resize(0); + child_index_.resize(0); + parents_.resize(0); } - - p[old_node] = new_node; - - // the list of the children of the original node - auto old_children = old_tree.children(old_node); - - auto this_node = new_node; - auto pos = child_index_[this_node]; - - auto add_parent_as_child = parent_node!=no_parent && old_node>0; - // - // STEP 1 : add the child indexes for this_node - // - // first add the children of the node - for(auto b : old_children) { - if(b != parent_node) { - children_[pos++] = b; - parents_[pos] = new_node; - } - } - // then add the node's parent as a child if applicable - if(add_parent_as_child) { - children_[pos++] = old_tree.parent(old_node); - parents_[pos] = new_node; - } - child_index_[this_node+1] = pos; - - // - // STEP 2 : recursively add each child's children - // - new_node++; - for (auto b : old_children) { - if (b != parent_node) { - new_node = add_children(new_node, b, no_parent, p, old_tree); - } - } - if (add_parent_as_child) { - new_node = - add_children( - new_node, old_tree.parent(old_node), old_node, p, old_tree - ); - } - - return new_node; } - ////////////////////////////////////////////////// // state - ////////////////////////////////////////////////// - iarray data_; - - // provide default parameters so that tree type can - // be default constructed - view_type children_ = data_(0, 0); - view_type child_index_= data_(0, 0); - view_type parents_ = data_(0, 0); + iarray children_; + iarray child_index_; + iarray parents_; }; template <typename C> diff --git a/test/unit/test_tree.cpp b/test/unit/test_tree.cpp index 9fea9278f3a6d265560d7c24671a78379483ad85..e23cc8ed7d9e2b1c5240b3a685001414b93da0a1 100644 --- a/test/unit/test_tree.cpp +++ b/test/unit/test_tree.cpp @@ -164,6 +164,13 @@ TEST(tree, from_segment_index) { EXPECT_EQ(tree.num_children(4), 2u); EXPECT_EQ(tree.num_children(5), 0u); EXPECT_EQ(tree.num_children(6), 0u); + + EXPECT_EQ(tree.children(0)[0], 1u); + EXPECT_EQ(tree.children(0)[1], 2u); + EXPECT_EQ(tree.children(1)[0], 3u); + EXPECT_EQ(tree.children(1)[1], 4u); + EXPECT_EQ(tree.children(4)[0], 5u); + EXPECT_EQ(tree.children(4)[1], 6u); } }