Algorithm Search⌘K

Proofs: Binary space partitioning tree

These are the human proofs of Binary space partitioning tree, at full length.

BUILD keeps the partition invariant and BACK-TO-FRONT gives a painter's order full

This proof shows: correctness, termination.

We use the names of the pseudocode. The input is a list SS of segments of positive length, no two of which cross or touch. For a node tt, the function σt\sigma_t is affine, so on a segment from pp to qq its value at the point p+λ(q−p)p + \lambda(q - p) is (1−λ)σt(p)+λσt(q)(1 - \lambda)\sigma_t(p) + \lambda \sigma_t(q).

Invariant (P). For each node tt: (1) each fragment of t.ont.on lies on t.linet.line; (2) each fragment of the subtree t.frontt.front has σt≥0\sigma_t \ge 0 at both ends, and not σt=0\sigma_t = 0 at both ends; (3) the same for t.backt.back with σt≤0\sigma_t \le 0; (4) the fragments of each input segment cover it and meet only at their ends.

Fact 1. Let a fragment ff have σt≥0\sigma_t \ge 0 at both ends and not 00 at both. Then σt>0\sigma_t > 0 at each point of the relative interior of ff. Proof. At such a point the value is a combination of the two end values with positive weights, both at least 0 and one positive. □\square The mirror statement holds for ≤0\le 0.

BUILD. By induction on ∣S∣|S|, BUILD(S)(S) returns a tree that satisfies (P) and whose fragments, for each segment of SS, cover it and meet only at their ends. Line L1 handles SS empty. Otherwise each segment r≠sr \ne s goes to exactly one case. If σt\sigma_t is 0 at both ends, rr lies on the line and joins t.ont.on (part 1). If the end values are both ≥0\ge 0 and not both 0, rr goes to FF; if both ≤0\le 0 and not both 0, to KK. Otherwise one value is positive and the other negative, so line L8 cuts rr at the point with λ=σt(p)/(σt(p)−σt(q))∈(0,1)\lambda = \sigma_t(p) / (\sigma_t(p) - \sigma_t(q)) \in (0, 1), where σt=0\sigma_t = 0. The front part has end values σt(p)>0\sigma_t(p) > 0 and 00, the back part 00 and a negative value, so parts 2 and 3 hold for them, and the two parts cover rr and meet only at the cut point, so part 4 holds. The lists FF and KK have at most ∣S∣−1|S| - 1 entries each, since ss goes to neither, so the induction applies to them and the recursion stops. The argument for BUILD does not use the condition that the segments do not cross; only the claim below does. Parts 2 and 3 for tt hold because every fragment in the subtree t.frontt.front is a part of a member of FF, which lies in the closed front half-plane, and a part of a segment with both end values ≥0\ge 0 has both end values ≥0\ge 0 and, by Fact 1, does not lie on the line. INSERT is the same filter for one segment, so it keeps (P) too.

Hiding. For a viewpoint vv, say that a fragment ff hides a point yy if vv is not on the line of ff and the open segment from vv to yy meets the relative interior of ff. When vv is on the line of ff, the fragment is seen edge on and covers nothing. A list of fragments is a painter's order for vv if no fragment hides a point of the relative interior of a fragment that comes later.

Claim. BACK-TO-FRONT(t,v)(t, v) outputs the fragments of the subtree tt in a painter's order for vv.

Proof. By induction on the height. The empty tree is clear. Let tt have children with outputs that are painter's orders by induction. A pair of fragments from one child keeps its order. For the list t.ont.on: its fragments all lie on t.linet.line. If vv is not on the line, the segment from vv to a point yy of the line meets the line only at yy, so it misses the other fragments of t.ont.on except at yy, which is not on the open segment. If vv is on the line, no fragment of t.ont.on hides anything by definition. It remains to treat pairs from different parts.

Case σt(v)>0\sigma_t(v) > 0, order back, on, front (line L11). Let ff come from the back subtree, and gg from t.ont.on or the front subtree, and let yy be in the relative interior of gg. By parts 1 and 2 and Fact 1, σt(y)≥0\sigma_t(y) \ge 0. Each point of the open segment from vv to yy has σt=(1−λ)σt(v)+λσt(y)>0\sigma_t = (1 - \lambda)\sigma_t(v) + \lambda\sigma_t(y) > 0 with λ∈(0,1)\lambda \in (0, 1). By part 3 and Fact 1, the relative interior of ff has σt<0\sigma_t < 0. So the open segment misses it, and ff does not hide yy. Let ff come from t.ont.on and gg from the front subtree: the interior of ff has σt=0\sigma_t = 0, and the same computation shows the open segment has σt>0\sigma_t > 0, so again ff does not hide yy.

Case σt(v)<0\sigma_t(v) < 0 (line L12) is the mirror image, with front and back swapped.

Case σt(v)=0\sigma_t(v) = 0, order front, on, back (line L13). Let ff come from the front subtree and gg from t.ont.on or the back subtree, with yy in the relative interior of gg. By parts 1 and 3 and Fact 1, σt(y)≤0\sigma_t(y) \le 0. If σt(y)<0\sigma_t(y) < 0, each point of the open segment has σt=λσt(y)<0\sigma_t = \lambda\sigma_t(y) < 0, while the interior of ff has σt>0\sigma_t > 0, so they do not meet. If σt(y)=0\sigma_t(y) = 0, then gg is in t.ont.on by Fact 1, and the whole segment from vv to yy lies on t.linet.line, where σt=0\sigma_t = 0; the interior of ff has σt>0\sigma_t > 0, so they do not meet. Let ff come from t.ont.on and gg from the back subtree: then vv is on the line of ff, so ff hides nothing.

In every case no earlier fragment hides a point of a later one, which proves the claim. Each node is expanded once, so the walk stops after O(m)O(m) steps. ■\blacksquare

Back to Binary space partitioning tree