54 static constexpr std::string_view
familyName =
"tree-topology";
57 static constexpr AttributeComputerFamily
family = AttributeComputerFamily::TreeTopology;
60 static constexpr AttributeComputerDomain
domain = AttributeComputerDomain::Topology;
73 NUM_LEAF_DESCENDANTS_NODE,
76 AVG_CHILD_HEIGHT_NODE};
88 template <std::
floating_po
int Real>
98 template <std::
floating_po
int Real>
137 std::vector<Real> depthStorage(computeDepth ? 0 : numNodeSlots, Real{0});
138 Real* bufferDepth = computeDepth ? buffer.data() : depthStorage.data();
139 auto indexOfDepth = [&](NodeId idx) {
140 return computeDepth ? attrNames.
linearIndex(idx, DEPTH_NODE) : idx;
143 std::vector<Real> minChildHeightStorage(computeBalance ? numNodeSlots : 0, Real{0});
145 ::mmcfilters::detail::traversePostOrder(tree,
148 const NodeId node = detail::topologySlotOf(tree, nodeId);
149 const bool isRoot = tree.isRoot(nodeId);
150 const NodeId parentNodeId = tree.getNodeParent(nodeId);
151 const NodeId parent = isRoot ? InvalidNode : detail::topologySlotOf(tree, parentNodeId);
152 const int numChildren = tree.getNumChildren(nodeId);
153 const bool isLeaf = tree.isLeaf(nodeId);
155 Real parentDepth = (parent != InvalidNode) ? bufferDepth[indexOfDepth(parent)] : Real{0};
156 bufferDepth[indexOfDepth(node)] = parent !=
InvalidNode ? parentDepth + Real{1} : Real{0};
158 bufferHeight[indexOfHeight(node)] = Real{0};
159 bufferNumDesc[indexOfNumDescendants(node)] = Real{0};
160 bufferNumLeafDesc[indexOfNumLeafDescendants(node)] = isLeaf ? Real{1} : Real{0};
163 buffer[attrNames.
linearIndex(node, HEIGHT_NODE)] = Real{0};
165 buffer[attrNames.
linearIndex(node, IS_LEAF_NODE)] = isLeaf ? Real{1} : Real{0};
167 buffer[attrNames.
linearIndex(node, IS_ROOT_NODE)] = isRoot ? Real{1} : Real{0};
168 if (computeNumChildren)
169 buffer[attrNames.
linearIndex(node, NUM_CHILDREN_NODE)] =
static_cast<Real
>(numChildren);
170 if (computeNumSiblings)
171 buffer[attrNames.
linearIndex(node, NUM_SIBLINGS_NODE)] = isRoot ? Real{0} :
static_cast<Real
>(tree.
getNumChildren(parentNodeId) - 1);
172 if (computeLeafRatio)
173 buffer[attrNames.
linearIndex(node, LEAF_RATIO_NODE)] = Real{0};
174 if (computeBalance) {
175 minChildHeightStorage[
static_cast<std::size_t
>(node)] = std::numeric_limits<Real>::infinity();
176 buffer[attrNames.
linearIndex(node, BALANCE_NODE)] = Real{0};
178 if (computeAvgChildHeight)
179 buffer[attrNames.
linearIndex(node, AVG_CHILD_HEIGHT_NODE)] = Real{0};
182 const NodeId parent = detail::topologySlotOf(tree, parentNodeId);
183 const NodeId child = detail::topologySlotOf(tree, childNodeId);
185 bufferNumDesc[indexOfNumDescendants(parent)] += bufferNumDesc[indexOfNumDescendants(child)] + Real{1};
186 bufferNumLeafDesc[indexOfNumLeafDescendants(parent)] += bufferNumLeafDesc[indexOfNumLeafDescendants(child)];
188 Real childHeight = bufferHeight[indexOfHeight(child)];
189 Real& parentHeight = bufferHeight[indexOfHeight(parent)];
190 parentHeight = std::max(parentHeight, childHeight + Real{1});
193 if (computeBalance) {
194 Real& minChildHeight = minChildHeightStorage[
static_cast<std::size_t
>(parent)];
195 minChildHeight = std::min(minChildHeight, childHeight);
198 if (computeAvgChildHeight) {
199 Real& sumH = buffer[attrNames.
linearIndex(parent, AVG_CHILD_HEIGHT_NODE)];
200 if (numChildren == 1)
207 const NodeId idx = detail::topologySlotOf(tree, idxGlobalId);
209 if (computeLeafRatio) {
210 Real desc = bufferNumDesc[indexOfNumDescendants(idx)];
211 Real leafCount = bufferNumLeafDesc[indexOfNumLeafDescendants(idx)];
212 buffer[attrNames.
linearIndex(idx, LEAF_RATIO_NODE)] =
214 ? ::mmcfilters::attributes::numeric::safeDivide(leafCount, desc + Real{1})
218 if (!tree.
isLeaf(idxGlobalId)) {
219 if (computeBalance) {
220 const Real maxChildHeight = bufferHeight[indexOfHeight(idx)] - Real{1};
221 const Real minChildHeight = minChildHeightStorage[
static_cast<std::size_t
>(idx)];
222 buffer[attrNames.
linearIndex(idx, BALANCE_NODE)] = maxChildHeight - minChildHeight;
225 if (computeAvgChildHeight) {
226 buffer[attrNames.
linearIndex(idx, AVG_CHILD_HEIGHT_NODE)] =
227 ::mmcfilters::attributes::numeric::safeDivide(
228 buffer[attrNames.
linearIndex(idx, AVG_CHILD_HEIGHT_NODE)],
244 template <std::
floating_po
int Real>