User:Azubit/sandbox

In computer science, an external memory priority queue is a priority queue stored completely or partially in external memory.

External memory priority queues are often used in combinations with large graph problems or simulations using large amounts of data when the use of internal priority queues would lead to paging. The random accesses of an internal priority queue would cause a slowdown of a factor from 10^5 to 10^6 Route planning algorithms usually use a weighted graph as the problem instance. Shortest path queries are then used to find the optimal route between point A and B. However, problem instances can be too large to fit into the internal memory and data needs to be transferred between the slow external memory and fast internal memory. Similarly, line sweep algorithms need to prioritize the line segments by their starting points and can use priority queues to do so (i.e. Bentley-Ottmann algorithm). An efficient handling of batched updates is necessary to minimize the I/Os needed per update and is often realized using dynamic data structures like Sequence Heaps or Buffer Trees. External memory priority queue implementations are found in libraries for large data sets. The STXXL for example implements the Sequence Heap as described by Sanders.

Sequence Heaps
The external memory priority queue proposed by Sanders uses multiple sorted sequences that are merged in a K-way merge algorithm. The result of the merge is a buffer of size $m$. To account for more elements in the priority queue, new k-way-merges and sorted sequences are introduced. For the Xth k-way-merge, the size of the sorted sequences is at most $mk^x$ but the resulting buffer is always of size $m$. These buffers represent a group of sorted sequences of the same size. They contain the smallest elements of the group. All these group buffers are merged in another R-way-merge, representing $R$ groups, resulting in a deletion buffer of size $m'$. Recently inserted elements are stored in an insert heap of size $m$.

DeleteMin
When deleting an element, the smallest elements of the deletion buffer and the in the insertion heap need to be compared. In case this empties the deletion buffer, all group buffers with less than $m'$ elements need to be refilled from the corresponding sorted sequences using a k-way-merge first. Then the deletion buffer needs to be refilled from the group buffers using the R-way-merge. Because the elements in the sorted sequences are not smaller than the elements in the corresponding group buffers and the group buffers only contain elements that are not smaller than the ones in the deletion buffer, the heap property is fulfilled and the smallest element of the data structure is always found in the deletion buffer or the insertion heap.

Insert
Inserted elements are first put into the insertion heap. When this heap is full, it is merged with the deletion buffer and the group buffer of the first group and sorted. The smallest elements of this merge are placed in the deletion buffer and in the first group buffer. The rest is added to the first group as another sequence of size $m$ such that there might be more than $k$  sequences in the first group. In this case, all old sequences in the group are merged into one large sequence of size $km$ and moved to the second group. To not violate the heap priority, the group buffer of the second group is merged with the buffer of the first group and inserted into the first group as a new sequence. The group buffers are then refilled with the k-way-merge. This is recursively also done to free up space in higher level groups as more and more elements are inserted. When there are multiple groups that have been emptied due to an insert, the group buffers of all the modified groups need to be merged and put into the first group as a new sequence.

Internal and external data
The elements that need to be accessed frequently are stored in internal memory while other elements are stored externally. This applies for a multitude of storage hierarchy models, be it the cache and random-access memory (RAM) or RAM and the disk storage. To optimize the performance of the external memory priority queue presented in this example, $m$ has to be chosen according to the block size of the external storage. When $m$ is smaller than the block size, unused data is fetched from the disk. Therefore $m=xB$, depending on the size of the internal storage. Generally only the deletion buffer and the insertion heap are stored in internal memory. The group buffers are swapped in and out when needed and the sorted sequences are stored exclusively in external memory.

Efficiency
All I/Os needed for inserting one element, propagating it through the groups and deleting it are done in batched operations which splits up the cost between all elements in a block. The element is first inserted into the insertion heap and then written to a sequence in the first group for a cost of $\frac{1}{B}$ writes. It is then transferred from one group to the next and needs to be read and wrote in every step. For $R$ groups this sums up to $\frac{2(R-1)}{B}$  I/Os. Lastly $\frac{1}{B}$ I/Os are needed to read the element into the group buffer. Each insertion leads to $\frac{2R}{B}$ I/Os in total.

Buffer Trees
The buffer tree data structure developed by Arge aims to transform an internal memory tree data structure into an external version. It is implemented as a (a,b)-tree with $a=\frac{m}{4}$ and $b=m$  (nodes have between $\frac{m}{4}$  and m children). Each parent node represents a varying number of elements that it stores in a buffer of size $mB$. The leaves represent one block each. Changes in the buffers are recorded with insert / delete flags. Before a buffer is processed all insert / delete pairs are removed.

Insert
Newly inserted elements are first placed into an internal buffer and marked as inserted. When the internal insertion buffer contains $B$ elements it is inserted into the buffer of the root element. In case this fills the buffer to at least $\frac{m}{2}$ blocks it is emptied and loaded into internal memory aside the parent node that is needed because of the partitioning elements. Insert / delete pairs are removed and all leftover elements are partitioned and pushed down to the appropriate child node buffers.

DeleteMin
The minimum element is contained in any of the leftmost nodes. Therefore all buffers on the path from the root to the leftmost leaf have to be emptied similar to the insert process. Afterwards at least the $\frac{m}{4B}$ smallest elements in the tree are in the leaves of the leftmost parent. These can now be cached to serve the next $\frac{m}{4B}$ deleteMin operations from internal memory.

Efficiency
For the deleteMin operation $m log_m(n)$ I/Os are needed. This leads to an amortized cost of $\frac{m log_m(n)}{1/4mB}$ I/Os per element.