k-d tree
k-d tree
InductiveKd-trees#✓fully proved
A kd-tree over points of \(\mathbb{Z}^d\) is either empty, a leaf holding one point of \(\mathbb{Z}^d\), or a split node holding a split axis \(a \in \{0, \dots, d-1\}\), a split value \(s \in \mathbb{Z}\) and two kd-trees, its left and right subtrees.
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
Used by 16
DefinitionKd-tree point traversal with an accumulator#✓fully proved
For a kd-tree \(t\) over points of \(\mathbb{Z}^d\) and a list \(\mathit{acc}\) of such points, the accumulator traversal of \(t\) onto \(\mathit{acc}\) is \(\mathit{acc}\) when \(t\) is empty, the point \(p\) followed by \(\mathit{acc}\) when \(t\) is a leaf holding \(p\), and, when \(t\) is a split node with left subtree \(L\) and right subtree \(R\), the traversal of \(L\) onto the traversal of \(R\) onto \(\mathit{acc}\).
Threading the output suffix avoids repeatedly appending (and copying) left-subtree results.
def toListAux : KdTree d → List (Fin d → Int) → List (Fin d → Int)
| .empty, acc => acc
| .leaf p, acc => p :: acc
| .node _ _ left right, acc => left.toListAux (right.toListAux acc)
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
Uses 1 · Used by 3
DefinitionPoint list of a kd-tree#✓fully proved
The point list of a kd-tree is the list of the points stored at its leaves, from left to right.
def toList (t : KdTree d) : List (Fin d → Int) :=
t.toListAux []
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
Uses 2 · Used by 15
TheoremAccumulator traversal of a kd-tree#✓fully proved
For every kd-tree \(t\) over \(\mathbb{Z}^d\) and every list \(acc\) of points, the accumulator traversal of \(t\) onto \(acc\) equals the list of points of \(t\) in left-to-right order followed by \(acc\).
@[simp]
theorem toListAux_eq (t : KdTree d) (acc : List (Fin d → Int)) :
t.toListAux acc = t.toList ++ acc
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
Uses 3 · Used by 1
TheoremPoint list of a kd-tree split node#✓fully proved
For a split node with axis \(a\), split value \(s\), left subtree \(L\) and right subtree \(R\), the point list of the node is the point list of \(L\) followed by the point list of \(R\).
@[simp]
theorem toList_node (a : Fin d) (s : Int) (left right : KdTree d) :
(KdTree.node a s left right).toList = left.toList ++ right.toList
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
Uses 4 · Used by 4
DefinitionSize of a kd-tree#✓fully proved
The size of a kd-tree is defined by recursion: the empty tree has size \(0\), a leaf has size \(1\), and a split node has the sum of the sizes of its two children. Since points are stored only at leaves, this is the number of points stored in the tree, counted with multiplicity.
def size : KdTree d → Nat
| .empty => 0
| .leaf _ => 1
| .node _ _ left right => left.size + right.size
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
Uses 1 · Used by 2
TheoremLength of the point list of a kd-tree#✓fully proved
For every kd-tree \(t\), the list of the points stored in \(t\), read from left to right, has length equal to the size of \(t\), the number of points stored in \(t\).
@[simp]
theorem length_toList (t : KdTree d) : t.toList.length = t.size
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
Uses 4 · Used by 1
DefinitionNext split axis of a kd-tree#✓fully proved
For a dimension \(d \ge 1\) and an axis \(a \in \{0, \dots, d - 1\}\), the next split axis is \((a + 1) \bmod d\), so the axes are visited cyclically.
AbbreviationMembership in an axis-aligned box#✓fully proved
For \(lo, hi, p \in \mathbb{Z}^d\), the point \(p\) lies in the closed axis-aligned box \([lo, hi]\) when \(lo_i \le p_i \le hi_i\) for every coordinate \(i \in \{0, \dots, d-1\}\).
Used by 8
DefinitionAccumulator range report of a kd-tree#✓fully proved
Points are vectors in \(\mathbb{Z}^d\) with coordinates \(p_0, \dots, p_{d-1}\); the box \([lo, hi]\) consists of the points \(p\) with \(lo_i \le p_i \le hi_i\) for every \(i\). For a kd-tree \(t\) and a list \(acc\) of points, the accumulator report of \(t\) for \([lo, hi]\) onto \(acc\) is defined by recursion on \(t\). For the empty tree it is \(acc\). For a leaf \(p\) it is \(p\) followed by \(acc\) if \(p\) lies in the box, and \(acc\) otherwise. For a split node with axis \(a\), split value \(s\), left child \(L\) and right child \(R\), let \(acc'\) be \(acc\) if \(hi_a < s\) and the report of \(R\) onto \(acc\) otherwise; the result is \(acc'\) if \(s < lo_a\) and the report of \(L\) onto \(acc'\) otherwise.
The accumulator avoids repeatedly appending the results of left subtrees, so building the output list costs work linear in the number of reported points; the traversal still visits every node that pruning does not cut, which can be the whole tree even for an empty report. No complexity bound is formalized.
def reportAux : KdTree d → (Fin d → Int) → (Fin d → Int) →
List (Fin d → Int) → List (Fin d → Int)
| .empty, _, _, acc => acc
| .leaf p, lo, hi, acc => if inBox lo hi p then p :: acc else acc
| .node a s left right, lo, hi, acc =>
let rightAcc := if hi a < s then acc else reportAux right lo hi acc
if s < lo a then rightAcc else reportAux left lo hi rightAcc
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
abbrev inBox (lo hi p : Fin d → Int) : Prop :=
∀ i, lo i ≤ p i ∧ p i ≤ hi i
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:123
Uses 2 · Used by 3
DefinitionOrthogonal range report of a kd-tree#✓fully proved
For a kd-tree \(t\) over \(\mathbb{Z}^d\) and \(lo, hi \in \mathbb{Z}^d\), the range report of \(t\) for the box \([lo, hi]\) is the accumulator range report of \(t\) for \([lo, hi]\) onto the empty list.
def report (t : KdTree d) (lo hi : Fin d → Int) : List (Fin d → Int) :=
reportAux t lo hi []
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
def reportAux : KdTree d → (Fin d → Int) → (Fin d → Int) →
List (Fin d → Int) → List (Fin d → Int)
| .empty, _, _, acc => acc
| .leaf p, lo, hi, acc => if inBox lo hi p then p :: acc else acc
| .node a s left right, lo, hi, acc =>
let rightAcc := if hi a < s then acc else reportAux right lo hi acc
if s < lo a then rightAcc else reportAux left lo hi rightAcc
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:143
Uses 2 · Used by 6
InductiveKd invariant#✓fully proved
A kd-tree satisfies the kd invariant when at every split node, with axis \(a\) and split value \(s\), every point of the left subtree has \(a\)-coordinate at most \(s\) and every point of the right subtree has \(a\)-coordinate at least \(s\).
inductive Valid : KdTree d → Prop where
| empty : Valid .empty
| leaf (p : Fin d → Int) : Valid (.leaf p)
| node {a : Fin d} {s : Int} {left right : KdTree d} (hLeft : Valid left)
(hRight : Valid right) (hL : ∀ p ∈ left.toList, p a ≤ s)
(hR : ∀ p ∈ right.toList, s ≤ p a) : Valid (.node a s left right)
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
Uses 2 · Used by 6
TheoremAccumulator range report of a valid kd-tree#✓fully proved
Let \(t\) be a valid kd-tree over \(\mathbb{Z}^d\), let \(lo, hi \in \mathbb{Z}^d\), and let \(acc\) be a list of points. The accumulator range report of \(t\) for the box \([lo, hi]\) onto \(acc\) equals the list of points of \(t\), in left-to-right order, that lie in the box (the points \(p\) with \(lo_i \le p_i \le hi_i\) for every coordinate \(i\)), followed by \(acc\).
theorem reportAux_eq_filter_append {t : KdTree d} (h : t.Valid)
(lo hi : Fin d → Int) (acc : List (Fin d → Int)) :
t.reportAux lo hi acc =
t.toList.filter (fun p => inBox lo hi p) ++ acc
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
abbrev inBox (lo hi p : Fin d → Int) : Prop :=
∀ i, lo i ≤ p i ∧ p i ≤ hi i
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:123
Uses 6 · Used by 1
TheoremCorrectness of the kd-tree range report#✓fully proved
For every valid kd-tree \(t\) over \(\mathbb{Z}^d\) and all \(lo, hi \in \mathbb{Z}^d\), the range report of \(t\) for the box \([lo, hi]\) equals the list of points of \(t\), in left-to-right order, that lie in the box, that is, the points \(p\) with \(lo_i \le p_i \le hi_i\) for every coordinate \(i\).
theorem report_eq_filter {t : KdTree d} (h : t.Valid)
(lo hi : Fin d → Int) :
t.report lo hi = t.toList.filter (fun p => inBox lo hi p)
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
abbrev inBox (lo hi p : Fin d → Int) : Prop :=
∀ i, lo i ≤ p i ∧ p i ≤ hi i
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:123
Uses 7 · Used by 2
TheoremRange report of a valid kd-tree#✓fully proved
Let \(t\) be a kd-tree over \(\mathbb{Z}^d\) that satisfies the kd invariant, and let \(lo, hi, p \in \mathbb{Z}^d\). Then \(p\) occurs in the range report of \(t\) for the box \([lo, hi]\) if and only if \(p\) is one of the points stored in \(t\) and \(lo_i \le p_i \le hi_i\) for every coordinate \(i\).
theorem mem_report_iff {t : KdTree d} (h : t.Valid)
{lo hi p : Fin d → Int} :
p ∈ t.report lo hi ↔ p ∈ t.toList ∧ inBox lo hi p
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
abbrev inBox (lo hi p : Fin d → Int) : Prop :=
∀ i, lo i ≤ p i ∧ p i ≤ hi i
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:123
Uses 6 · Used by 1
DefinitionFirst-point coordinate#✓fully proved
For an axis \(a \in \{0, \dots, d-1\}\) and a list of points in \(\mathbb{Z}^d\), this is the \(a\)-coordinate of the first point of the list, or \(0\) if the list is empty.
DefinitionKd-tree construction by median splits#✓fully proved
Let \(d \ge 1\), let \(a \in \{0, \dots, d-1\}\) be an axis and let \(P\) be a list of points in \(\mathbb{Z}^d\). The kd-tree built from \(P\) starting at axis \(a\) is the empty tree if \(P\) is empty and the leaf holding \(p\) if \(P = [p]\). If \(P\) has \(n \ge 2\) points, sort \(P\) by \(a\)-coordinate with merge sort, let \(L\) be the first \(\lfloor n/2 \rfloor\) points of the sorted list and \(R\) the remaining ones. The result is the split node with axis \(a\) whose split value is the \(a\)-coordinate of the first point of \(R\), whose left subtree is built from \(L\) and whose right subtree is built from \(R\), both starting at the next axis \((a + 1) \bmod d\).
Cslib.Algorithms.Lean.KdTree.build · 15 lines
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_mergeSort,
List.length_cons]
omega
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
def headCoord (a : Fin d) (xs : List (Fin d → Int)) : Int :=
(xs.head?.map (fun p => p a)).getD 0
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:231
def nextAxis [NeZero d] (a : Fin d) : Fin d :=
Fin.ofNat d (a.val + 1)
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:119
Uses 3 · Used by 8
TheoremMedian-split kd-trees satisfy the kd invariant#✓fully proved
For \(d \ge 1\), every axis \(a\) and every list of points of \(\mathbb{Z}^d\), the kd-tree built from the list by median splits starting at axis \(a\) satisfies the kd invariant.
theorem valid_build [NeZero d] (a : Fin d) (pts : List (Fin d → Int)) :
(build a pts).Valid
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
⋯
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:239
Uses 7 · Used by 3
TheoremBuilding a kd-tree preserves its points#✓fully proved
For \(d \ge 1\), every axis \(a\) and every list of points of \(\mathbb{Z}^d\), the point list of the kd-tree built from the list by median splits starting at axis \(a\) is a permutation of the list.
theorem toList_build_perm [NeZero d] (a : Fin d) (pts : List (Fin d → Int)) :
(build a pts).toList.Perm pts
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
⋯
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:239
Uses 7 · Used by 4
TheoremA built kd-tree holds the same points as its input#✓fully proved
Let \(d \ge 1\), let \(a \in \{0, \dots, d-1\}\) and let \(P\) be a list of points in \(\mathbb{Z}^d\). A point \(p \in \mathbb{Z}^d\) is stored in the kd-tree built from \(P\) by median splits starting at axis \(a\) if and only if \(p\) occurs in \(P\).
theorem mem_toList_build_iff [NeZero d] (a : Fin d) (pts : List (Fin d → Int))
(p : Fin d → Int) :
p ∈ (build a pts).toList ↔ p ∈ pts
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
⋯
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:239
Uses 3 · Used by 1
TheoremSize of a built kd-tree#✓fully proved
Let \(d \ge 1\). For every starting axis \(a\) and every list \(P\) of points of \(\mathbb{Z}^d\), the size of the kd-tree built from \(P\) starting at axis \(a\) equals the length of \(P\) (repeated points counted with multiplicity).
@[simp]
theorem size_build [NeZero d] (a : Fin d) (pts : List (Fin d → Int)) :
(build a pts).size = pts.length
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
⋯
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:239
Uses 5
DefinitionKd-tree construction from the first axis#✓fully proved
For \(d \ge 1\) and a list of points in \(\mathbb{Z}^d\), this is the kd-tree built from the list by alternating-axis median splits, starting with split axis \(0\).
def buildRoot [NeZero d] (pts : List (Fin d → Int)) : KdTree d :=
build (Fin.ofNat d 0) pts
inductive KdTree (d : Nat) where
| empty : KdTree d
| leaf : (Fin d → Int) → KdTree d
| node : Fin d → Int → KdTree d → KdTree d → KdTree d
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:50
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
⋯
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:239
Uses 2 · Used by 3
TheoremKd-trees built from axis 0 satisfy the kd invariant#✓fully proved
For \(d \ge 1\) and every list of points of \(\mathbb{Z}^d\), the kd-tree built from the list by median splits starting at axis \(0\) satisfies the kd invariant.
theorem valid_buildRoot [NeZero d] (pts : List (Fin d → Int)) :
(buildRoot pts).Valid
def buildRoot [NeZero d] (pts : List (Fin d → Int)) : KdTree d :=
build (Fin.ofNat d 0) pts
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:374
Uses 3
TheoremBuilding a kd-tree from axis 0 preserves its points#✓fully proved
For \(d \ge 1\) and every list of points of \(\mathbb{Z}^d\), the point list of the kd-tree built from the list by median splits starting at axis \(0\) is a permutation of the list.
theorem toList_buildRoot_perm [NeZero d] (pts : List (Fin d → Int)) :
(buildRoot pts).toList.Perm pts
def buildRoot [NeZero d] (pts : List (Fin d → Int)) : KdTree d :=
build (Fin.ofNat d 0) pts
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:374
Uses 3
TheoremRange report of a built kd-tree as a filter#✓fully proved
Let \(d \ge 1\). For every starting axis \(a\), every list \(P\) of points of \(\mathbb{Z}^d\) and all \(lo, hi \in \mathbb{Z}^d\), let \(T\) be the kd-tree built from \(P\) starting at axis \(a\). The range report of \(T\) for the box \([lo, hi]\) equals the list of points of \(T\), in left-to-right order, that lie in the box, that is, the points \(p\) with \(lo_i \le p_i \le hi_i\) for every coordinate \(i\).
theorem report_build [NeZero d] (a : Fin d) (pts : List (Fin d → Int))
(lo hi : Fin d → Int) :
(build a pts).report lo hi =
(build a pts).toList.filter (fun p => inBox lo hi p)
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
⋯
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:239
abbrev inBox (lo hi p : Fin d → Int) : Prop :=
∀ i, lo i ≤ p i ∧ p i ≤ hi i
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:123
Uses 6 · Used by 1
TheoremRange report of a built kd-tree up to order#✓fully proved
Let \(d \ge 1\). For every starting axis \(a\), every list \(P\) of points of \(\mathbb{Z}^d\) and all \(lo, hi \in \mathbb{Z}^d\), the range report for the box \([lo, hi]\) of the kd-tree built from \(P\) starting at axis \(a\) is a permutation of the list of entries of \(P\) that lie in the box, that is, the points \(p\) with \(lo_i \le p_i \le hi_i\) for every coordinate \(i\).
theorem report_build_perm [NeZero d] (a : Fin d) (pts : List (Fin d → Int))
(lo hi : Fin d → Int) :
((build a pts).report lo hi).Perm
(pts.filter (fun p => inBox lo hi p))
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
⋯
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:239
abbrev inBox (lo hi p : Fin d → Int) : Prop :=
∀ i, lo i ≤ p i ∧ p i ≤ hi i
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:123
TheoremMembership in the range report of a built kd-tree#✓fully proved
Let \(d \ge 1\), let \(a \in \{0, \dots, d-1\}\), let \(P\) be a list of points in \(\mathbb{Z}^d\) and let \(lo, hi, p \in \mathbb{Z}^d\). Then \(p\) occurs in the range report, for the box \([lo, hi]\), of the kd-tree built from \(P\) by median splits starting at axis \(a\) if and only if \(p\) occurs in \(P\) and \(lo_i \le p_i \le hi_i\) for every coordinate \(i\).
theorem mem_report_build_iff [NeZero d] (a : Fin d) (pts : List (Fin d → Int))
{lo hi p : Fin d → Int} :
p ∈ (build a pts).report lo hi ↔ p ∈ pts ∧ inBox lo hi p
def build [NeZero d] : Fin d → List (Fin d → Int) → KdTree d
| _, [] => .empty
| _, [p] => .leaf p
| a, pts@(_ :: _ :: _) =>
let sorted := pts.mergeSort (fun p q => p a ≤ q a)
let k := sorted.length / 2
.node a (headCoord a (sorted.drop k))
(build (nextAxis a) (sorted.take k))
(build (nextAxis a) (sorted.drop k))
termination_by _ pts => pts.length
decreasing_by
all_goals
⋯
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:239
abbrev inBox (lo hi p : Fin d → Int) : Prop :=
∀ i, lo i ≤ p i ∧ p i ≤ hi i
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:123
Uses 7 · Used by 1
TheoremRange report of a kd-tree built from the first axis#✓fully proved
Let \(d \ge 1\), let \(P\) be a list of points in \(\mathbb{Z}^d\) and let \(lo, hi, p \in \mathbb{Z}^d\). Then \(p\) occurs in the range report, for the box \([lo, hi]\), of the kd-tree built from \(P\) by median splits starting at axis \(0\) if and only if \(p\) occurs in \(P\) and \(lo_i \le p_i \le hi_i\) for every coordinate \(i\).
theorem mem_report_buildRoot_iff [NeZero d] (pts : List (Fin d → Int))
{lo hi p : Fin d → Int} :
p ∈ (buildRoot pts).report lo hi ↔ p ∈ pts ∧ inBox lo hi p
def buildRoot [NeZero d] (pts : List (Fin d → Int)) : KdTree d :=
build (Fin.ofNat d 0) pts
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:374
abbrev inBox (lo hi p : Fin d → Int) : Prop :=
∀ i, lo i ≤ p i ∧ p i ≤ hi i
CSLibExt/Algorithms/Lean/DataStructures/KdTree.lean:123
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.