Proofs: Loose octree
These are the human proofs of Loose octree, at full length.
The loose octree places each box in a loose cell and reports exactly the boxes that meet a query full
This proof shows: correctness, termination.
We use the names of the pseudocode. The root cube is , and boxes are closed with integer corners in it. A node at depth has side and index ; on each axis its cell is and its loose cell is . The placement of a box is the pair computed by lines L1 to L3. The invariant (P) asks: (1) each box is stored once, at the node of its placement; (2) the children of a node are its octants; (3) each node other than the root stores a box or has a child.
Lemma 1 (placement is valid). The placement of has , its cell holds the center of , and lies in its loose cell. Proof. All corners are in , so and the least power of two has , which gives . On one axis, with and , we have , and gives , so the cell is a cell of depth . The box reaches from to , and , so it lies in . The code computes as , which is the same number.
Lemma 2 (paths). The walk of line L4 reaches the node of index at depth , and each node on the way is the octant of its parent that holds the cell of . Proof. The cell of index at depth lies in the cell at depth whose index is shifted right by bits on each axis. The child of that cell that holds it has index with the next bit, bit of . So taking these bits as the octant at each depth goes down the chain of cells that hold the cell of .
Lemma 3 (nested loose cells). The loose cell of a child lies in the loose cell of its parent, so every box stored at a node or below it lies in the loose cell of that node. Proof. On one axis, let the parent have side and index , and the child side and index with . The child's loose cell is , which lies in . The second claim follows from Lemma 1 and part 2, by induction up from the node of the box.
INSERT. By Lemmas 1 and 2, lines L1 to L4 reach the node of the placement, making missing nodes as octants of their parents, so part 2 holds and the walk stops after steps. The code checks that is not in the list, and by part 1 this is the only node where could be stored, so line L5 keeps part 1. The nodes made now have below them, so part 3 holds.
DELETE. The placement depends only on . If is stored, by part 1 it is at the node of its placement, whose path exists, so line L11 finds that node and line L12 removes . If a node of the path is missing or the list does not hold , then is not stored and nothing changes. After the removal, part 3 can fail only on the path, and lines L13 and L14 remove the empty nodes from the bottom up; when the loop stops at a node that stores a box or has a child, every node above it has that node below it. Each pass goes up one level, so the loop stops after at most passes. MOVE is a DELETE followed by an INSERT.
QUERY. Each node is pushed once, by its parent, so the loop stops, and by part 1 no box is reported twice. Each reported box is stored and meets , by line L9. Let a stored box meet , at the node . For each node on the path from the root to , lies in the loose cell of by Lemma 3, so that loose cell meets and line L7 does not skip . Line L10 pushes all children, so is visited, and line L9 reports .
Uniqueness. By part 1 the node of each box is its placement, which depends only on the box, and by part 3 a node exists if and only if it is on the path of a stored box. So the tree depends only on the set of boxes.