///|
/// Result of spatial density-based clustering (DBSCAN).
pub struct ClusterResult {
labels : Array[Int]
num_clusters : Int
num_noise : Int
cluster_sizes : Array[Int]
} derive(Eq, Debug, Default)
///|
/// A discrete 2D spatial grid cell with item density count and bounding rectangle.
pub struct GridCell {
col : Int
row : Int
count : Int
bounds : Rect
} derive(Eq, Debug, Default)
///|
/// Aggregated spatial grid density summary and hotspot metrics.
pub struct GridDensitySummary {
cells : Array[GridCell]
total_cells : Int
max_density : Int
avg_density : Double
hotspot_cells : Array[GridCell]
} derive(Eq, Debug, Default)
///|
/// Performs spatial index-accelerated Density-Based Spatial Clustering of Applications with Noise (DBSCAN).
pub fn StrTree::dbscan(
self : StrTree,
eps : Double,
min_pts : Int,
) -> ClusterResult {
let res = self.inner.dbscan(eps, min_pts)
ClusterResult::{
labels: res.labels,
num_clusters: res.num_clusters,
num_noise: res.num_noise,
cluster_sizes: res.cluster_sizes,
}
}
///|
/// Partitions spatial items into uniform rectangular grid cells and computes density distribution.
pub fn StrTree::aggregate_grid(
self : StrTree,
cell_width : Double,
cell_height : Double,
hotspot_threshold? : Int = 1,
) -> GridDensitySummary {
let s = self.inner.aggregate_grid(cell_width, cell_height, hotspot_threshold~)
let cells : Array[GridCell] = []
for i = 0; i < s.cells.length(); i = i + 1 {
let c = s.cells[i]
cells.push(GridCell::{
col: c.col,
row: c.row,
count: c.count,
bounds: c.bounds,
})
}
let hotspots : Array[GridCell] = []
for i = 0; i < s.hotspot_cells.length(); i = i + 1 {
let c = s.hotspot_cells[i]
hotspots.push(GridCell::{
col: c.col,
row: c.row,
count: c.count,
bounds: c.bounds,
})
}
GridDensitySummary::{
cells,
total_cells: s.total_cells,
max_density: s.max_density,
avg_density: s.avg_density,
hotspot_cells: hotspots,
}
}
///|
/// Performs spatial index-accelerated 3D DBSCAN clustering.
pub fn StrTree3D::dbscan(
self : StrTree3D,
eps : Double,
min_pts : Int,
) -> ClusterResult {
let res = self.inner.dbscan(eps, min_pts)
ClusterResult::{
labels: res.labels,
num_clusters: res.num_clusters,
num_noise: res.num_noise,
cluster_sizes: res.cluster_sizes,
}
}
///|
/// DBSCAN result aligned with item_ids instead of allocating up to the largest user ID.
pub struct CompactClusterResult {
item_ids : Array[Int]
labels : Array[Int]
num_clusters : Int
num_noise : Int
cluster_sizes : Array[Int]
} derive(Eq, Debug, Default)
///|
fn map_compact_cluster(
result : @tree.CompactClusterResult,
) -> CompactClusterResult {
CompactClusterResult::{
item_ids: result.item_ids,
labels: result.labels,
num_clusters: result.num_clusters,
num_noise: result.num_noise,
cluster_sizes: result.cluster_sizes,
}
}
///|
pub fn StrTree::dbscan_compact(
self : StrTree,
eps : Double,
min_pts : Int,
) -> CompactClusterResult {
map_compact_cluster(self.inner.dbscan_compact(eps, min_pts))
}
///|
pub fn StrTree3D::dbscan_compact(
self : StrTree3D,
eps : Double,
min_pts : Int,
) -> CompactClusterResult {
map_compact_cluster(self.inner.dbscan_compact(eps, min_pts))
}