void Pop(out SubtreeHeapEntry entry) { entry = Entries[0]; --Count; var cost = Entries[Count].Cost; //Pull the elements up to fill in the gap. int index = 0; while (true) { var childIndexA = (index << 1) + 1; var childIndexB = (index << 1) + 2; if (childIndexB < Count) { //Both children are available. //Try swapping with the largest one. var childA = Entries + childIndexA; var childB = Entries + childIndexB; if (childA->Cost > childB->Cost) { if (cost > childA->Cost) { break; } Entries[index] = Entries[childIndexA]; index = childIndexA; } else { if (cost > childB->Cost) { break; } Entries[index] = Entries[childIndexB]; index = childIndexB; } } else if (childIndexA < Count) { //Only one child was available. var childA = Entries + childIndexA; if (cost > childA->Cost) { break; } Entries[index] = Entries[childIndexA]; index = childIndexA; } else { //The children were beyond the heap. break; } } //Move the last entry into position. Entries[index] = Entries[Count]; }
public unsafe void CollectSubtrees(int nodeIndex, int maximumSubtrees, SubtreeHeapEntry* entries, ref QuickList<int> subtrees, ref QuickList<int> internalNodes, out float treeletCost) { //Collect subtrees iteratively by choosing the highest surface area subtree repeatedly. //This collects every child of a given node at once- the set of subtrees must not include only SOME of the children of a node. //(You could lift this restriction and only take some nodes, but it would complicate things. You could not simply remove //the parent and add its children to go deeper; it would require doing some post-fixup on the results of the construction //or perhaps constraining the generation process to leave room for the unaffected nodes.) var node = nodes + nodeIndex; Debug.Assert(maximumSubtrees >= node->ChildCount, "Can't only consider some of a node's children, but specified maximumSubtrees precludes the treelet root's children."); //All of treelet root's children are included immediately. (Follows from above requirement.) var priorityQueue = new SubtreeBinaryHeap(entries); priorityQueue.Insert(node, nodes, ref subtrees); //Note that the treelet root is NOT added to the internal nodes list. //Note that the treelet root's cost is excluded from the treeletCost. //That's because the treelet root cannot change. treeletCost = 0; int highestIndex; float highestCost; int remainingSubtreeSpace = maximumSubtrees - priorityQueue.Count - subtrees.Count; while (priorityQueue.TryPop(nodes, ref remainingSubtreeSpace, ref subtrees, out highestIndex, out highestCost)) { treeletCost += highestCost; internalNodes.Add(highestIndex); //Add all the children to the set of subtrees. //This is safe because we pre-validated the number of children in the node. var expandedNode = nodes + highestIndex; priorityQueue.Insert(expandedNode, nodes, ref subtrees); } for (int i = 0; i < priorityQueue.Count; ++i) { subtrees.Add(priorityQueue.Entries[i].Index); } //Sort the internal nodes so that the depth first builder will tend to produce less cache-scrambled results. Array.Sort(internalNodes.Elements, 0, internalNodes.Count); }
public SubtreeBinaryHeap(SubtreeHeapEntry* entries) { Entries = entries; Count = 0; }