From 9a7454f4b00c96c2c31cf2422910d44cd0049410 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 1 Aug 2026 15:56:33 +0200 Subject: [PATCH 01/20] feat(spatial): lattice neighbour graphs for Visium and Visium HD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spots and bins sit on a known grid, so neighbours are integer arithmetic — no spatial index, no distances, nothing approximate. Sort by (row, col), build a row directory, and each neighbour is a binary search inside one row. Offsets verified against 10x's Space Ranger docs and by replicating squidpy's algorithm: Visium is doubled coordinates, (row + col) constant parity, six neighbours at (row, col±2) and (row±1, col±1). Documented capture area (78 rows x 64 spots = 4992) is a test case. Two traps this defends against: - squidpy ignores the lattice and runs Euclidean kNN on pixel coordinates with a median*1.3 cutoff. Exact on contiguous tissue, but the cutoff is global, so at 50% lattice occupancy about half its edges are not lattice-adjacent. Working from the integers has no such failure mode. - raw doubled coordinates are anisotropic (in-row 2 units, diagonal sqrt 2), so metric methods silently drop the in-row neighbours and return a diagonal-only graph. visium_isometric_coords() rescales so all six sit at the pitch, and passing offset coordinates instead of doubled is now a hard error rather than a wrong graph. Builds CSR directly in two passes; an edge list first would cost ~700 MB at HD scale. 10.5M bins / 21.1M edges in 954ms, 591 MB. 18 tests: exact adjacency on small grids, closed-form edge counts, interior and hand-computed boundary degrees, parity, tissue holes, permutation invariance, symmetry, u32::MAX coordinates. Plus the load-bearing one — Leiden on a lattice produces zero disconnected communities, i.e. spatially contiguous domains. --- src/error.rs | 48 +++ src/lib.rs | 1 + src/spatial/lattice.rs | 705 +++++++++++++++++++++++++++++++++++++++++ src/spatial/mod.rs | 14 + 4 files changed, 768 insertions(+) create mode 100644 src/spatial/lattice.rs create mode 100644 src/spatial/mod.rs diff --git a/src/error.rs b/src/error.rs index e741dbc..32cff75 100644 --- a/src/error.rs +++ b/src/error.rs @@ -54,6 +54,35 @@ pub enum ClusteringError { }, /// The supplied CSR arrays were not a well-formed sparse matrix. InvalidCsr(String), + /// Two observations claimed the same lattice position. + DuplicateLatticePosition { + /// Lattice row. + row: u32, + /// Lattice column. + col: u32, + /// The two node indices sharing it. + nodes: (usize, usize), + }, + /// Visium hex positions did not all share the same `(row + col)` parity. + /// + /// In doubled coordinates every spot has the same parity, so mixed parity means the + /// coordinates are not doubled — most often offset coordinates (`col / 2`), which would + /// silently produce a wrong graph rather than an empty one. + InconsistentHexParity { + /// A node with the majority parity. + expected_node: usize, + /// The first node found disagreeing with it. + node: usize, + /// The offending position. + position: (u32, u32), + }, + /// Parallel coordinate arrays had different lengths. + CoordinateLengthMismatch { + /// Length of the first array. + got: usize, + /// Expected length, from the first array supplied. + expected: usize, + }, /// The adjacency is not symmetric, so `Σ strength != 2 · total_weight`. /// /// Most often means an un-symmetrised k-NN graph was passed to @@ -100,6 +129,25 @@ impl fmt::Display for ClusteringError { crate::network::MAX_NODES ), Self::InvalidCsr(msg) => write!(f, "malformed CSR input: {msg}"), + Self::DuplicateLatticePosition { row, col, nodes } => write!( + f, + "nodes {} and {} both sit at lattice position ({row}, {col})", + nodes.0, nodes.1 + ), + Self::CoordinateLengthMismatch { got, expected } => { + write!(f, "coordinate array has length {got}, expected {expected}") + } + Self::InconsistentHexParity { + expected_node, + node, + position, + } => write!( + f, + "node {node} at ({}, {}) disagrees in (row + col) parity with node \ + {expected_node}. Visium doubled coordinates give every spot the same parity; \ + mixed parity usually means offset coordinates were passed instead", + position.0, position.1 + ), Self::AsymmetricGraph { degree_sum, expected, diff --git a/src/lib.rs b/src/lib.rs index 1a2c419..139351e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub mod error; #[cfg(feature = "knn")] pub mod neighborhood; pub mod network; +pub mod spatial; #[cfg(test)] pub(crate) mod testdata; diff --git a/src/spatial/lattice.rs b/src/spatial/lattice.rs new file mode 100644 index 0000000..0e6eb6f --- /dev/null +++ b/src/spatial/lattice.rs @@ -0,0 +1,705 @@ +//! Neighbour graphs for observations on a regular lattice. +//! +//! Visium spots and Visium HD bins sit on a known grid, so their neighbours follow from +//! integer arithmetic — no spatial index, no distance computation, nothing approximate. +//! At HD scale (millions of bins) that is the difference between seconds and minutes. +//! +//! # Why not distance-based +//! +//! `squidpy.gr.spatial_neighbors` ignores the lattice and runs Euclidean kNN on the float +//! pixel coordinates, keeping edges under `median(dist) * 1.3`. On contiguous tissue that +//! reproduces the lattice exactly, but the cutoff is global, so on a sparse or fragmented +//! lattice it bridges the gaps: at 50% occupancy roughly half the edges it produces are not +//! lattice-adjacent, and at 20% it is three quarters. Working from the integers is exact +//! everywhere and needs no heuristic. +//! +//! # The anisotropy trap +//! +//! Never run Euclidean kNN on raw doubled coordinates. In-row neighbours are 2 units apart +//! while diagonal ones are only √2, so a metric method silently drops the two in-row +//! neighbours and returns a diagonal-only graph — wrong, and wrong in a way that still looks +//! like a plausible clustering. [`visium_isometric_coords`] rescales to a space where all six +//! neighbours are equidistant; use it for anything distance-based. + +use crate::error::{ClusteringError, Result}; +use crate::network::{CSRNetwork, MAX_NODES}; + +/// The lattice the coordinates describe. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Lattice { + /// Visium's hex grid in doubled coordinates: `col` steps by 2 within a row, and odd rows + /// are offset by 1, so a spot exists only where `(row + col)` is even. Six neighbours: + /// `(row, col ± 2)` and `(row ± 1, col ± 1)`. + VisiumHex, + /// Square grid, edge-adjacent only. Four neighbours: `(row ± 1, col)`, `(row, col ± 1)`. + Square4, + /// Square grid including diagonals. Eight neighbours. + Square8, +} + +impl Lattice { + /// Half the neighbour offsets — enough that each undirected edge is generated exactly + /// once, by its lower endpoint in (row, col) order. The other half are these negated. + const fn forward_offsets(self) -> &'static [(i64, i64)] { + match self { + Self::VisiumHex => &[(0, 2), (1, -1), (1, 1)], + Self::Square4 => &[(0, 1), (1, 0)], + Self::Square8 => &[(0, 1), (1, 0), (1, 1), (1, -1)], + } + } + + /// Neighbours an interior position has. Only used for documentation and tests. + pub const fn degree(self) -> usize { + match self { + Self::VisiumHex => 6, + Self::Square4 => 4, + Self::Square8 => 8, + } + } +} + +/// Where each distinct row sits in the sorted node order. +struct RowIndex { + /// Distinct row values, ascending. + rows: Vec, + /// `starts[i]..starts[i + 1]` is row `rows[i]`'s slice of the sorted order. + starts: Vec, +} + +impl RowIndex { + /// Slice of the sorted order holding `row`, or `None` if the row is empty. + #[inline] + fn range(&self, row: u32) -> Option> { + let i = self.rows.binary_search(&row).ok()?; + Some(self.starts[i] as usize..self.starts[i + 1] as usize) + } +} + +/// Builds a neighbour graph from integer lattice coordinates. +/// +/// `rows` and `cols` give each observation's position; every edge has weight 1.0. Positions +/// that are absent — tissue-masked spots, trimmed bins — simply have no edge there, so a +/// partial capture area needs no special handling. +/// +/// Since the graph is exactly the lattice adjacency, Leiden's internal-connectivity guarantee +/// becomes spatial contiguity: no community can be split across disconnected regions. +/// +/// # Errors +/// +/// If the arrays differ in length, two observations share a position, or there are more +/// nodes than `u32` adjacency can address. +pub fn lattice_graph(rows: &[u32], cols: &[u32], lattice: Lattice) -> Result { + let n = rows.len(); + if cols.len() != n { + return Err(ClusteringError::CoordinateLengthMismatch { + got: cols.len(), + expected: n, + }); + } + if n > MAX_NODES { + return Err(ClusteringError::TooManyNodes { n_nodes: n }); + } + if n == 0 { + return CSRNetwork::from_csr_parts(vec![0], Vec::new(), Vec::new(), None); + } + + // Sorted by (row, col), so a row is contiguous and its columns ascend — which is what + // lets a neighbour lookup be a binary search inside one row rather than over everything. + let mut order: Vec = (0..n as u32).collect(); + order.sort_unstable_by_key(|&v| key(rows[v as usize], cols[v as usize])); + + // Columns in sorted order, held separately so the binary search reads contiguous memory. + // Going through `cols[order[i]]` gathers randomly on every comparison instead: 1.21s vs + // 954ms on 10.5M bins. + let sorted_cols: Vec = order.iter().map(|&v| cols[v as usize]).collect(); + + for (i, w) in order.windows(2).enumerate() { + let (a, b) = (w[0] as usize, w[1] as usize); + if rows[a] == rows[b] && sorted_cols[i] == sorted_cols[i + 1] { + return Err(ClusteringError::DuplicateLatticePosition { + row: rows[a], + col: cols[a], + nodes: (a.min(b), a.max(b)), + }); + } + } + + if lattice == Lattice::VisiumHex { + check_hex_parity(rows, cols)?; + } + + let index = build_row_index(&order, rows); + let offsets = lattice.forward_offsets(); + + // Two passes so the CSR arrays are allocated once at their final size. Materialising an + // edge list first would cost ~700 MB at HD scale before the graph even exists. + let mut degree = vec![0u32; n]; + visit_edges(&order, rows, cols, &sorted_cols, &index, offsets, |v, u| { + degree[v] += 1; + degree[u] += 1; + }); + + let mut node_ptrs = Vec::with_capacity(n + 1); + node_ptrs.push(0usize); + let mut total = 0usize; + for &d in °ree { + total += d as usize; + node_ptrs.push(total); + } + + let mut neighbors = vec![0u32; total]; + let mut weights = vec![1.0f32; total]; + let mut cursor: Vec = node_ptrs[..n].to_vec(); + visit_edges(&order, rows, cols, &sorted_cols, &index, offsets, |v, u| { + neighbors[cursor[v]] = u as u32; + cursor[v] += 1; + neighbors[cursor[u]] = v as u32; + cursor[u] += 1; + }); + weights.truncate(total); + + CSRNetwork::from_csr_parts(node_ptrs, neighbors, weights, None) +} + +/// Packs a position into one sortable integer. `i64` keeps the arithmetic honest for offsets +/// that would take a `u32` below zero. +#[inline] +const fn key(row: u32, col: u32) -> u64 { + ((row as u64) << 32) | col as u64 +} + +/// Rejects coordinates that are not doubled. +/// +/// Real Visium data is always `(row + col)` even, but only *consistency* is required here — +/// a shifted origin is fine, offset coordinates are not. Without this, passing `col / 2` +/// produces a graph that is wrong rather than empty, since the offsets still find something. +fn check_hex_parity(rows: &[u32], cols: &[u32]) -> Result<()> { + let parity = (rows[0] + cols[0]) % 2; + for v in 1..rows.len() { + if (rows[v] + cols[v]) % 2 != parity { + return Err(ClusteringError::InconsistentHexParity { + expected_node: 0, + node: v, + position: (rows[v], cols[v]), + }); + } + } + Ok(()) +} + +/// Rescales Visium doubled coordinates so all six neighbours sit at the same distance. +/// +/// Doubled coordinates are anisotropic — in-row neighbours are 2 units apart, diagonal ones +/// √2 — so any distance-based method must be given these instead. `pitch` is the +/// centre-to-centre spot spacing, 100.0 µm on standard Visium; the output is in the same +/// units, and every one of the six neighbours lands exactly `pitch` away. +/// +/// # Errors +/// +/// If the arrays differ in length. +pub fn visium_isometric_coords( + rows: &[u32], + cols: &[u32], + pitch: f64, +) -> Result<(Vec, Vec)> { + if cols.len() != rows.len() { + return Err(ClusteringError::CoordinateLengthMismatch { + got: cols.len(), + expected: rows.len(), + }); + } + // col carries the doubling, so it scales by pitch/2; row spacing is the hex height. + let (sx, sy) = (pitch / 2.0, pitch * f64::sqrt(3.0) / 2.0); + Ok(( + cols.iter().map(|&c| c as f64 * sx).collect(), + rows.iter().map(|&r| r as f64 * sy).collect(), + )) +} + +fn build_row_index(order: &[u32], rows: &[u32]) -> RowIndex { + let mut index = RowIndex { + rows: Vec::new(), + starts: Vec::new(), + }; + for (pos, &v) in order.iter().enumerate() { + let r = rows[v as usize]; + if index.rows.last() != Some(&r) { + index.rows.push(r); + index.starts.push(pos as u32); + } + } + index.starts.push(order.len() as u32); + index +} + +/// Calls `f(v, u)` once per undirected edge, with both node indices in the caller's +/// numbering. Runs identically in both passes, so degrees and fill can never disagree. +#[inline] +fn visit_edges( + order: &[u32], + rows: &[u32], + cols: &[u32], + sorted_cols: &[u32], + index: &RowIndex, + offsets: &[(i64, i64)], + mut f: impl FnMut(usize, usize), +) { + for &v in order { + let v = v as usize; + let (r, c) = (rows[v] as i64, cols[v] as i64); + for &(dr, dc) in offsets { + let (tr, tc) = (r + dr, c + dc); + if tr < 0 || tc < 0 || tr > u32::MAX as i64 || tc > u32::MAX as i64 { + continue; + } + if let Some(u) = lookup(order, sorted_cols, index, tr as u32, tc as u32) { + f(v, u); + } + } + } +} + +/// Node at `(row, col)`, or `None` if nothing sits there. +#[inline] +fn lookup( + order: &[u32], + sorted_cols: &[u32], + index: &RowIndex, + row: u32, + col: u32, +) -> Option { + let range = index.range(row)?; + // The row is short — 128 columns on Visium, ~3250 on HD — so this stays in L1. + let i = sorted_cols[range.clone()].binary_search(&col).ok()?; + Some(order[range.start + i] as usize) +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::SeedableRng; + use rand::seq::SliceRandom; + use std::collections::HashSet; + + /// Every position in an R x C block. + fn full_square(r: u32, c: u32) -> (Vec, Vec) { + let mut rows = Vec::new(); + let mut cols = Vec::new(); + for i in 0..r { + for j in 0..c { + rows.push(i); + cols.push(j); + } + } + (rows, cols) + } + + /// Visium's layout: `(row + col)` even, `col` stepping by 2 within a row. + fn full_hex(r: u32, c: u32) -> (Vec, Vec) { + let mut rows = Vec::new(); + let mut cols = Vec::new(); + for i in 0..r { + for j in 0..c { + if (i + j) % 2 == 0 { + rows.push(i); + cols.push(j); + } + } + } + (rows, cols) + } + + /// Undirected edges as coordinate pairs, so results can be compared across node orderings. + fn edge_set(g: &CSRNetwork, rows: &[u32], cols: &[u32]) -> HashSet<((u32, u32), (u32, u32))> { + let mut out = HashSet::new(); + for v in 0..g.node_count() { + for (u, _) in g.neighbors(v) { + out.insert(canon((rows[v], cols[v]), (rows[u], cols[u]))); + } + } + out + } + + /// Orders an edge's endpoints so the two directions collapse to one entry. + fn canon(a: (u32, u32), b: (u32, u32)) -> ((u32, u32), (u32, u32)) { + if a <= b { (a, b) } else { (b, a) } + } + + #[test] + fn square4_3x3_has_exactly_the_lattice_edges() { + let (rows, cols) = full_square(3, 3); + let g = lattice_graph(&rows, &cols, Lattice::Square4).unwrap(); + + let mut expected = HashSet::new(); + for r in 0..3u32 { + for c in 0..3u32 { + if c + 1 < 3 { + expected.insert(canon((r, c), (r, c + 1))); + } + if r + 1 < 3 { + expected.insert(canon((r, c), (r + 1, c))); + } + } + } + assert_eq!(edge_set(&g, &rows, &cols), expected); + assert_eq!(g.edge_count(), 12, "3x3 grid: 6 horizontal + 6 vertical"); + } + + #[test] + fn square8_3x3_adds_exactly_the_diagonals() { + let (rows, cols) = full_square(3, 3); + let four = lattice_graph(&rows, &cols, Lattice::Square4).unwrap(); + let eight = lattice_graph(&rows, &cols, Lattice::Square8).unwrap(); + let (a, b) = ( + edge_set(&four, &rows, &cols), + edge_set(&eight, &rows, &cols), + ); + assert!(a.is_subset(&b)); + assert_eq!(b.len() - a.len(), 8, "2x2 blocks x 2 diagonals each"); + } + + /// Closed form for a fully occupied grid, checked over a range of shapes. + #[test] + fn square_edge_counts_match_the_closed_form() { + for (r, c) in [(1, 1), (1, 7), (7, 1), (2, 2), (5, 9), (16, 16)] { + let (rows, cols) = full_square(r, c); + let g4 = lattice_graph(&rows, &cols, Lattice::Square4).unwrap(); + assert_eq!( + g4.edge_count() as u32, + r * (c - 1) + (r - 1) * c, + "Square4 {r}x{c}" + ); + let g8 = lattice_graph(&rows, &cols, Lattice::Square8).unwrap(); + assert_eq!( + g8.edge_count() as u32, + r * (c - 1) + (r - 1) * c + 2 * (r - 1) * (c - 1), + "Square8 {r}x{c}" + ); + } + } + + /// The property that would break if a forward offset were double-counted: duplicate + /// entries are summed on construction, so a double emission shows up as weight 2.0. + #[test] + fn every_edge_has_weight_exactly_one() { + for lattice in [Lattice::Square4, Lattice::Square8, Lattice::VisiumHex] { + let (rows, cols) = match lattice { + Lattice::VisiumHex => full_hex(9, 13), + _ => full_square(9, 13), + }; + let g = lattice_graph(&rows, &cols, lattice).unwrap(); + for v in 0..g.node_count() { + for (u, w) in g.neighbors(v) { + assert_eq!(w, 1.0, "{lattice:?}: edge {v}-{u} has weight {w}"); + } + } + assert!(!g.has_self_loops(), "{lattice:?} produced a self-loop"); + } + } + + #[test] + fn interior_degree_matches_the_lattice() { + for lattice in [Lattice::Square4, Lattice::Square8, Lattice::VisiumHex] { + let (r, c) = (11u32, 15u32); + let (rows, cols) = match lattice { + Lattice::VisiumHex => full_hex(r, c), + _ => full_square(r, c), + }; + let g = lattice_graph(&rows, &cols, lattice).unwrap(); + // Hex reaches two columns sideways, so its interior starts one further in. + let margin = if lattice == Lattice::VisiumHex { 2 } else { 1 }; + let mut checked = 0; + for v in 0..g.node_count() { + let (vr, vc) = (rows[v], cols[v]); + if vr >= margin && vr < r - margin && vc >= margin && vc < c - margin { + assert_eq!( + g.degree(v), + lattice.degree(), + "{lattice:?}: interior spot ({vr}, {vc})" + ); + checked += 1; + } + } + assert!(checked > 10, "{lattice:?}: only {checked} interior spots"); + } + } + + /// Visium's parity: neighbours of an even-parity spot are also even-parity, which is what + /// makes the doubled-coordinate scheme self-consistent. + #[test] + fn hex_neighbours_preserve_parity_and_are_the_six_offsets() { + let (rows, cols) = full_hex(9, 13); + let g = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); + let expected: HashSet<(i64, i64)> = + [(0, 2), (0, -2), (1, 1), (1, -1), (-1, 1), (-1, -1)].into(); + + for v in 0..g.node_count() { + assert_eq!((rows[v] + cols[v]) % 2, 0, "spot {v} has odd parity"); + for (u, _) in g.neighbors(v) { + let d = ( + rows[u] as i64 - rows[v] as i64, + cols[u] as i64 - cols[v] as i64, + ); + assert!(expected.contains(&d), "unexpected hex offset {d:?}"); + assert_eq!((rows[u] + cols[u]) % 2, 0); + } + } + } + + /// Boundary spots, worked out by hand on the layout in the module docs. + #[test] + fn hex_boundary_degrees_are_exact() { + let (rows, cols) = full_hex(5, 9); + let g = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); + let at = |r: u32, c: u32| { + (0..g.node_count()) + .find(|&v| rows[v] == r && cols[v] == c) + .unwrap_or_else(|| panic!("no spot at ({r}, {c})")) + }; + assert_eq!(g.degree(at(2, 4)), 6, "interior"); + assert_eq!(g.degree(at(0, 4)), 4, "top edge: no row above"); + assert_eq!(g.degree(at(2, 0)), 3, "left edge: nothing to the left"); + assert_eq!(g.degree(at(0, 0)), 2, "corner"); + assert_eq!(g.degree(at(4, 8)), 2, "opposite corner"); + } + + /// Tissue masking removes spots; the remaining ones must simply lose those edges. + #[test] + fn missing_positions_leave_holes_rather_than_shifting_neighbours() { + let (rows, cols) = full_square(5, 5); + let keep: Vec = (0..rows.len()) + .filter(|&i| !(rows[i] == 2 && cols[i] == 2)) + .collect(); + let r: Vec = keep.iter().map(|&i| rows[i]).collect(); + let c: Vec = keep.iter().map(|&i| cols[i]).collect(); + + let g = lattice_graph(&r, &c, Lattice::Square4).unwrap(); + let full = lattice_graph(&rows, &cols, Lattice::Square4).unwrap(); + assert_eq!(g.node_count(), 24); + assert_eq!(g.edge_count(), full.edge_count() - 4, "the hole's 4 edges"); + + for v in 0..g.node_count() { + for (u, _) in g.neighbors(v) { + let d = (r[u] as i64 - r[v] as i64).abs() + (c[u] as i64 - c[v] as i64).abs(); + assert_eq!(d, 1, "a hole must not join spots two apart"); + } + } + } + + /// Node order is the caller's; the graph must not depend on it. + #[test] + fn result_is_invariant_under_input_permutation() { + let (rows, cols) = full_hex(9, 13); + let reference = { + let g = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); + edge_set(&g, &rows, &cols) + }; + + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(7); + for _ in 0..8 { + let mut perm: Vec = (0..rows.len()).collect(); + perm.shuffle(&mut rng); + let r: Vec = perm.iter().map(|&i| rows[i]).collect(); + let c: Vec = perm.iter().map(|&i| cols[i]).collect(); + let g = lattice_graph(&r, &c, Lattice::VisiumHex).unwrap(); + assert_eq!(edge_set(&g, &r, &c), reference); + } + } + + #[test] + fn adjacency_is_symmetric() { + for lattice in [Lattice::Square4, Lattice::Square8, Lattice::VisiumHex] { + let (rows, cols) = match lattice { + Lattice::VisiumHex => full_hex(12, 17), + _ => full_square(12, 17), + }; + let g = lattice_graph(&rows, &cols, lattice).unwrap(); + g.validate_symmetry() + .unwrap_or_else(|e| panic!("{lattice:?}: {e}")); + } + } + + /// Real Visium geometry: 78 rows, `array_col` 0..126 even / 1..127 odd, 64 spots per row. + /// Verified against 10x's Space Ranger spatial-outputs documentation. + #[test] + fn matches_the_documented_visium_capture_area() { + let mut rows = Vec::new(); + let mut cols = Vec::new(); + for r in 0..78u32 { + for i in 0..64u32 { + rows.push(r); + cols.push(2 * i + (r % 2)); + } + } + assert_eq!(rows.len(), 4992, "10x documents 4992 spots"); + + let g = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); + assert_eq!(g.node_count(), 4992); + // Interior spots: rows 1..77 with both in-row neighbours present. + let interior = (0..g.node_count()) + .filter(|&v| rows[v] > 0 && rows[v] < 77 && cols[v] >= 2 && cols[v] <= 125) + .count(); + assert!(interior > 4000); + for v in 0..g.node_count() { + if rows[v] > 0 && rows[v] < 77 && cols[v] >= 2 && cols[v] <= 125 { + assert_eq!(g.degree(v), 6, "spot ({}, {})", rows[v], cols[v]); + } + } + } + + /// The trap: offset coordinates look like valid input but describe a different lattice. + #[test] + fn rejects_offset_coordinates_masquerading_as_doubled() { + let (rows, doubled) = full_hex(9, 13); + let offset: Vec = doubled.iter().map(|&c| c / 2).collect(); + assert!( + matches!( + lattice_graph(&rows, &offset, Lattice::VisiumHex), + Err(ClusteringError::InconsistentHexParity { .. }) + ), + "offset coordinates must not be silently accepted" + ); + // Square lattices have no parity constraint, so they stay unaffected. + assert!(lattice_graph(&rows, &offset, Lattice::Square4).is_ok()); + } + + /// A shifted origin is still doubled, so it must be allowed. + #[test] + fn accepts_a_shifted_hex_origin() { + let (rows, cols) = full_hex(9, 13); + let shifted: Vec = cols.iter().map(|&c| c + 1).collect(); + let g = lattice_graph(&rows, &shifted, Lattice::VisiumHex).unwrap(); + let reference = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); + assert_eq!(g.edge_count(), reference.edge_count()); + } + + /// All six neighbours must land at exactly `pitch` in the rescaled space — the property + /// that makes distance-based methods safe on Visium. + #[test] + fn isometric_coords_equalise_all_six_neighbours() { + let (rows, cols) = full_hex(9, 13); + let g = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); + let (x, y) = visium_isometric_coords(&rows, &cols, 100.0).unwrap(); + + for v in 0..g.node_count() { + for (u, _) in g.neighbors(v) { + let d = ((x[u] - x[v]).powi(2) + (y[u] - y[v]).powi(2)).sqrt(); + assert!( + (d - 100.0).abs() < 1e-9, + "neighbour distance {d}, expected the 100 µm pitch" + ); + } + } + + // And nothing else is that close, so a radius query at 1.1x pitch is exactly the + // lattice — which is what makes the isometric form usable for kNN. + let v = (0..g.node_count()) + .find(|&v| rows[v] == 4 && cols[v] == 6) + .unwrap(); + let within = (0..g.node_count()) + .filter(|&u| u != v && ((x[u] - x[v]).powi(2) + (y[u] - y[v]).powi(2)).sqrt() < 110.0) + .count(); + assert_eq!(within, 6); + } + + #[test] + fn rejects_bad_input() { + assert!(matches!( + lattice_graph(&[0, 1], &[0], Lattice::Square4), + Err(ClusteringError::CoordinateLengthMismatch { + got: 1, + expected: 2 + }) + )); + assert!(matches!( + lattice_graph(&[3, 3], &[7, 7], Lattice::Square4), + Err(ClusteringError::DuplicateLatticePosition { row: 3, col: 7, .. }) + )); + } + + #[test] + fn handles_degenerate_input() { + let empty = lattice_graph(&[], &[], Lattice::Square4).unwrap(); + assert_eq!(empty.node_count(), 0); + assert_eq!(empty.edge_count(), 0); + + let single = lattice_graph(&[5], &[9], Lattice::VisiumHex).unwrap(); + assert_eq!(single.node_count(), 1); + assert_eq!(single.edge_count(), 0); + + // Far apart, so nothing is adjacent. + let scattered = lattice_graph(&[0, 100, 200], &[0, 100, 200], Lattice::Square8).unwrap(); + assert_eq!(scattered.edge_count(), 0); + } + + /// Leiden guarantees internally-connected communities, so on a lattice every domain must + /// be a spatially contiguous region. This is the property the whole approach rests on. + #[test] + fn leiden_domains_are_spatially_contiguous() { + use crate::community_search::leiden::{LeidenConfig, ObjectiveKind, leiden}; + + let (rows, cols) = full_square(40, 40); + let g = lattice_graph(&rows, &cols, Lattice::Square4).unwrap(); + for resolution in [0.05, 0.1, 0.5] { + let c = leiden( + &g, + &LeidenConfig { + objective: ObjectiveKind::Cpm { resolution }, + ..Default::default() + }, + ) + .unwrap(); + assert_eq!( + crate::testdata::disconnected_community_count(&g, c.labels()), + 0, + "resolution {resolution} produced a spatially split domain" + ); + assert!( + c.n_clusters() > 1, + "resolution {resolution} found one domain" + ); + } + } + + /// Coordinates at the top of the `u32` range must not wrap when an offset goes negative. + #[test] + fn extreme_coordinates_do_not_wrap() { + let rows = [0u32, 0, u32::MAX, u32::MAX]; + let cols = [0u32, u32::MAX, 0, u32::MAX]; + let g = lattice_graph(&rows, &cols, Lattice::Square8).unwrap(); + assert_eq!(g.edge_count(), 0, "corners of the space are not adjacent"); + } + + /// Visium HD at 2 µm. Sources disagree on the grid: 10x's row count implies 3350², while + /// spatialdata documents 3250². Only a size for the benchmark, so either does — but the + /// builder never assumes an extent, and callers shouldn't either. + /// + /// ```text + /// cargo test --release --no-default-features visium_hd_scale -- --ignored --nocapture + /// ``` + #[test] + #[ignore = "takes a few seconds and allocates ~1 GB"] + fn visium_hd_scale() { + let side = 3250u32; + let t = std::time::Instant::now(); + let (rows, cols) = full_square(side, side); + let coords = t.elapsed(); + + let t = std::time::Instant::now(); + let g = lattice_graph(&rows, &cols, Lattice::Square4).unwrap(); + let build = t.elapsed(); + + println!( + "{}x{} = {} bins, {} edges\n coords {:.2?}, graph {:.2?}, {:.1} MB", + side, + side, + g.node_count(), + g.edge_count(), + coords, + build, + g.memory_bytes() as f64 / 1e6 + ); + assert_eq!(g.node_count(), (side * side) as usize); + assert_eq!(g.edge_count() as u32, 2 * side * (side - 1)); + } +} diff --git a/src/spatial/mod.rs b/src/spatial/mod.rs new file mode 100644 index 0000000..5cdfb8c --- /dev/null +++ b/src/spatial/mod.rs @@ -0,0 +1,14 @@ +//! Spatial neighbour graphs. +//! +//! Spatial domain detection is mostly a graph-construction problem: build the right graph and +//! the clustering is the same Leiden used everywhere else. Because refinement guarantees +//! internally-connected communities, running it on a spatial graph gives spatially contiguous +//! domains for free. +//! +//! Use [`ObjectiveKind::Cpm`](crate::community_search::leiden::ObjectiveKind::Cpm) rather than +//! RB for spatial domains — modularity's resolution limit bites harder here, where domains +//! tend to be numerous and small. + +pub mod lattice; + +pub use lattice::{Lattice, lattice_graph, visium_isometric_coords}; From c48e6fe658169bffe29b7f82922a7b5dc0734901 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 1 Aug 2026 16:50:46 +0200 Subject: [PATCH 02/20] feat(spatial): radius and kNN neighbour graphs on a uniform grid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Point-based assays (Xenium, MERFISH, CosMx, Slide-seq) position cells rather than slotting them into a grid, so neighbours have to be searched for. Both builders run over a uniform-grid index rather than a kd-tree. That started as a performance choice — tissue is close to uniformly dense, so bucketing beats traversal — but became a correctness one. kiddo 5.2.2 is unusable here on two counts, both found by tests in this commit: - KdTree panics outright past 32 points sharing a coordinate on one axis. Every Visium row is 64 spots at one y; every HD row is thousands. - ImmutableKdTree returns neighbour ids that do not match the coordinates it measured. Querying a collinear run, it reported distance 0 for a point five units away: the distances are right for the true neighbours, the ids are not. A graph built from it joins each cell to someone else's neighbours — wrong, and wrong in a way that still looks like a plausible clustering. The grid has no such failure modes. Duplicates and collinear runs are ordinary inputs, everything is exact, and it needs no dependency at all, so the spatial builders are unconditional rather than feature-gated. Radius is symmetric by construction. kNN is not, so Symmetry::Union (scanpy's convention, degree >= k) or Intersection (mutual only, degree <= k) reconciles it explicitly — emitting both directions and letting construction merge them would silently give mutual pairs twice the weight. Ties break on the lower index, so pixel-rounded coordinates still give a reproducible graph. Verified against O(n^2) brute force across seven degenerate point sets (collinear, all-identical, duplicated pairs, dense spike, far clumps) x three radii and three k. 500k cells: knn(6) 299ms, radius(30) 80ms. --- Cargo.toml | 2 + src/spatial/grid.rs | 180 +++++++++++ src/spatial/mod.rs | 17 + src/spatial/points.rs | 738 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 937 insertions(+) create mode 100644 src/spatial/grid.rs create mode 100644 src/spatial/points.rs diff --git a/Cargo.toml b/Cargo.toml index a14e921..a05f580 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,8 @@ default = ["knn"] # clustering core can be built and tested without the HNSW/kd-tree stack, which does not # compile on every target. knn = ["dep:hnsw_rs", "dep:kiddo", "dep:ndarray"] +# Spatial neighbour graphs are always available: the uniform-grid index they use has no +# dependencies, so there is no build to opt out of. [dependencies] anyhow = "1.0.100" diff --git a/src/spatial/grid.rs b/src/spatial/grid.rs new file mode 100644 index 0000000..4961618 --- /dev/null +++ b/src/spatial/grid.rs @@ -0,0 +1,180 @@ +//! Uniform-grid spatial index. +//! +//! Tissue is close to uniformly dense, so bucketing points into fixed cells beats a tree: +//! queries are O(points nearby) with no traversal, duplicates and collinear runs are ordinary +//! inputs rather than pathological ones, and there is nothing approximate anywhere. +//! +//! It also replaces a dependency that turned out to be wrong. `kiddo` 5.2.2's `KdTree` panics +//! once more than 32 points share a coordinate on one axis — which every Visium row does — +//! and its `ImmutableKdTree` returns neighbour *ids* that do not match the coordinates it +//! measured, so a graph built from it joins each cell to someone else's neighbours. + +/// Points bucketed into cells of a fixed size, stored CSR-style. +pub(crate) struct Grid { + cell: f64, + min: [f64; D], + dims: [usize; D], + /// `starts[c]..starts[c + 1]` is cell `c`'s slice of `items`. + starts: Vec, + items: Vec, +} + +impl Grid { + /// Buckets `points` into cells of roughly `target_cell`. + /// + /// The cell size is enlarged if it would need more cells than points, so a handful of + /// far-flung outliers cannot make the index enormous. + pub(crate) fn new(points: &[[f64; D]], target_cell: f64) -> Self { + debug_assert!(!points.is_empty()); + let mut min = [f64::INFINITY; D]; + let mut max = [f64::NEG_INFINITY; D]; + for p in points { + for d in 0..D { + min[d] = min[d].min(p[d]); + max[d] = max[d].max(p[d]); + } + } + + // Cap total cells at ~2 per point: sparse data gets coarser cells rather than a + // gigantic mostly-empty index. + let mut cell = target_cell.max(f64::MIN_POSITIVE); + let mut dims = [0usize; D]; + loop { + let mut total = 1usize; + let mut overflow = false; + for d in 0..D { + let span = max[d] - min[d]; + dims[d] = ((span / cell).floor() as usize).saturating_add(1); + match total.checked_mul(dims[d]) { + Some(t) => total = t, + None => { + overflow = true; + break; + } + } + } + if !overflow && total <= points.len().saturating_mul(2).max(64) { + break; + } + cell *= 2.0; + } + + let n_cells: usize = dims.iter().product(); + let mut starts = vec![0u32; n_cells + 1]; + let index_of = |p: &[f64; D]| -> usize { + let mut idx = 0usize; + for d in 0..D { + let c = (((p[d] - min[d]) / cell).floor() as usize).min(dims[d] - 1); + idx = idx * dims[d] + c; + } + idx + }; + + for p in points { + starts[index_of(p) + 1] += 1; + } + for c in 0..n_cells { + starts[c + 1] += starts[c]; + } + let mut items = vec![0u32; points.len()]; + let mut cursor: Vec = starts[..n_cells].to_vec(); + for (i, p) in points.iter().enumerate() { + let c = index_of(p); + items[cursor[c] as usize] = i as u32; + cursor[c] += 1; + } + + Self { + cell, + min, + dims, + starts, + items, + } + } + + #[inline] + pub(crate) fn cell_size(&self) -> f64 { + self.cell + } + + /// Which cell a point falls in, per axis. + #[inline] + pub(crate) fn cell_of(&self, p: &[f64; D]) -> [usize; D] { + let mut out = [0usize; D]; + for d in 0..D { + out[d] = (((p[d] - self.min[d]) / self.cell).floor() as usize).min(self.dims[d] - 1); + } + out + } + + /// Largest Chebyshev ring that could still hold a point, from `centre`. + pub(crate) fn max_ring(&self, centre: &[usize; D]) -> usize { + centre + .iter() + .zip(&self.dims) + .fold(0usize, |r, (&c, &dim)| r.max(c).max(dim - 1 - c)) + } + + /// Calls `f` for every point in a cell at Chebyshev distance exactly `ring` from `centre`. + /// + /// Walking one ring at a time is what lets a k-nearest search stop as soon as its current + /// k-th distance is provably better than anything left unvisited. + pub(crate) fn for_each_in_ring( + &self, + centre: &[usize; D], + ring: usize, + mut f: impl FnMut(u32), + ) { + // Clamp each axis to the grid, then walk the box with an odometer, skipping the + // interior — those cells belong to a smaller ring and were visited already. + let mut lo = [0usize; D]; + let mut hi = [0usize; D]; + for d in 0..D { + lo[d] = centre[d].saturating_sub(ring); + hi[d] = (centre[d] + ring).min(self.dims[d] - 1); + } + + let mut at = lo; + loop { + let on_surface = ring == 0 + || (0..D).any(|d| { + (at[d] == centre[d].wrapping_sub(ring) && centre[d] >= ring) + || at[d] == centre[d] + ring + }); + if on_surface { + let idx = at + .iter() + .zip(&self.dims) + .fold(0usize, |acc, (&a, &dim)| acc * dim + a); + for &item in &self.items[self.starts[idx] as usize..self.starts[idx + 1] as usize] { + f(item); + } + } + + // Odometer step over the clamped box. + let mut d = D; + loop { + if d == 0 { + return; + } + d -= 1; + if at[d] < hi[d] { + at[d] += 1; + break; + } + at[d] = lo[d]; + } + } + } +} + +#[inline] +pub(crate) fn distance_sq(a: &[f64; D], b: &[f64; D]) -> f64 { + let mut s = 0.0; + for d in 0..D { + let diff = a[d] - b[d]; + s += diff * diff; + } + s +} diff --git a/src/spatial/mod.rs b/src/spatial/mod.rs index 5cdfb8c..345c7cf 100644 --- a/src/spatial/mod.rs +++ b/src/spatial/mod.rs @@ -9,6 +9,23 @@ //! RB for spatial domains — modularity's resolution limit bites harder here, where domains //! tend to be numerous and small. +//! # Reading Visium data +//! +//! Two things to know before wiring up a loader, both verified against the upstream source: +//! +//! * Space Ranger ≥ 2.0 renamed `tissue_positions_list.csv` to `tissue_positions.csv` **and +//! added a header row**. Parse the header rather than assuming column positions — scanpy +//! branches on the filename to decide. +//! * `scanpy.read_visium` labels the two pixel columns the wrong way round, then selects them +//! in the wrong order. The errors cancel, so `obsm["spatial"]` really is `(x, y)`, but the +//! names in `obs` are swapped. Don't trust `pxl_row_in_fullres` / `pxl_col_in_fullres` if +//! you read those columns directly. +//! +//! Neither affects `array_row` / `array_col`, which is what [`lattice_graph`] wants. + +pub(crate) mod grid; pub mod lattice; +pub mod points; pub use lattice::{Lattice, lattice_graph, visium_isometric_coords}; +pub use points::{SpatialWeight, Symmetry, knn_graph, radius_graph}; diff --git a/src/spatial/points.rs b/src/spatial/points.rs new file mode 100644 index 0000000..eacf2bd --- /dev/null +++ b/src/spatial/points.rs @@ -0,0 +1,738 @@ +//! Neighbour graphs from point coordinates, for assays that are not on a lattice. +//! +//! Xenium, MERFISH, CosMx and Slide-seq give each cell a position rather than a grid slot, so +//! neighbours have to be searched for. Both builders here are exact, over the uniform grid in +//! [`grid`](super::grid) — no approximation, so no recall gaps to make a graph +//! irreproducible. Both are checked against brute force on degenerate inputs. +//! +//! On Visium data, pass [`visium_isometric_coords`](super::visium_isometric_coords) rather +//! than raw lattice coordinates; see the module docs for why. + +use rayon::prelude::*; + +use crate::error::{ClusteringError, Result}; +use crate::network::{CSRNetwork, MAX_NODES}; +use crate::spatial::grid::{Grid, distance_sq}; + +/// How to reconcile the two directions of a k-nearest-neighbour relation. +/// +/// kNN is directed — `j` being among `i`'s nearest does not make `i` among `j`'s — but the +/// quality functions need a symmetric graph, so one of these has to be chosen. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum Symmetry { + /// Keep an edge if either endpoint chose the other. Degrees come out at or above `k`. + /// This is what scanpy and squidpy do. + #[default] + Union, + /// Keep an edge only if both endpoints chose each other. Degrees come out at or below + /// `k`, and the graph is sparser and more conservative — hub cells stop dragging in + /// distant neighbours. + Intersection, +} + +/// Weight to give an edge, as a function of its length. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum SpatialWeight { + /// Every edge weighs 1.0. Adjacency alone carries the signal. + Uniform, + /// `exp(-d² / (2σ²))`, so nearby cells count for more. `sigma` is in the same units as + /// the coordinates. + Gaussian { + /// Kernel bandwidth. + sigma: f64, + }, +} + +impl SpatialWeight { + #[inline] + fn apply(self, distance_sq: f64) -> f64 { + match self { + Self::Uniform => 1.0, + Self::Gaussian { sigma } => (-distance_sq / (2.0 * sigma * sigma)).exp(), + } + } + + fn validate(self) -> Result<()> { + match self { + Self::Gaussian { sigma } if !sigma.is_finite() || sigma <= 0.0 => { + Err(ClusteringError::InvalidConfig(format!( + "gaussian sigma must be finite and positive, got {sigma}" + ))) + } + _ => Ok(()), + } + } +} + +/// A neighbour and the square of its distance, kept squared to avoid a pointless `sqrt`. +type Candidate = (u32, f64); + +fn validate_points(points: &[[f64; D]]) -> Result<()> { + if points.len() > MAX_NODES { + return Err(ClusteringError::TooManyNodes { + n_nodes: points.len(), + }); + } + for (i, p) in points.iter().enumerate() { + if let Some(bad) = p.iter().find(|c| !c.is_finite()) { + return Err(ClusteringError::InvalidConfig(format!( + "point {i} has a non-finite coordinate {bad}" + ))); + } + } + Ok(()) +} + +/// Joins every pair of points closer than `radius`. +/// +/// The relation is symmetric by construction, so no reconciliation step is needed and the +/// result does not depend on any tie-breaking. `radius` is in coordinate units — for spatial +/// assays that means it is directly interpretable, e.g. 30 µm. +/// +/// Degree is unbounded: in dense tissue a generous radius can give a cell thousands of +/// neighbours, and cost downstream is linear in degree. `max_degree` caps it by keeping only +/// the nearest, but note the cap is applied **before** symmetrisation, so a node can still +/// finish slightly above it when a neighbour kept an edge it dropped. +/// +/// # Errors +/// +/// If `radius` is not finite and positive, a coordinate is not finite, or there are more +/// points than `u32` adjacency can address. +pub fn radius_graph( + points: &[[f64; D]], + radius: f64, + weight: SpatialWeight, + max_degree: Option, +) -> Result { + if !radius.is_finite() || radius <= 0.0 { + return Err(ClusteringError::InvalidConfig(format!( + "radius must be finite and positive, got {radius}" + ))); + } + validate_points(points)?; + weight.validate()?; + if points.is_empty() { + return CSRNetwork::from_csr_parts(vec![0], Vec::new(), Vec::new(), None); + } + + // Cells the size of the radius, so everything in range sits in the 3^D block around a + // point and one ring is all that ever needs visiting. + let grid = Grid::new(points, radius); + let r2 = radius * radius; + + let mut adjacency: Vec> = points + .par_iter() + .enumerate() + .map(|(i, p)| { + let centre = grid.cell_of(p); + let reach = (radius / grid.cell_size()).ceil() as usize; + let mut found: Vec = Vec::new(); + for ring in 0..=reach.min(grid.max_ring(¢re)) { + grid.for_each_in_ring(¢re, ring, |j| { + if j as usize != i { + let d2 = distance_sq(p, &points[j as usize]); + if d2 <= r2 { + found.push((j, d2)); + } + } + }); + } + // Sorted by (distance, id) so a capped result never depends on visit order — + // points at equal distance are the norm on regular tissue. + found.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0))); + if let Some(cap) = max_degree { + found.truncate(cap); + } + found + }) + .collect(); + + // Capping breaks symmetry, so restore it. Without a cap this is already a no-op. + if max_degree.is_some() { + symmetrise(&mut adjacency, Symmetry::Union); + } + assemble(adjacency, weight) +} + +/// Joins every point to its `k` nearest neighbours, then makes the relation symmetric. +/// +/// Ties are broken on the lower node index, so a fixed input gives a fixed graph even where +/// many points sit at identical coordinates — which happens whenever coordinates have been +/// rounded to a pixel grid. +/// +/// # Errors +/// +/// If `k` is zero, a coordinate is not finite, or there are more points than `u32` adjacency +/// can address. +pub fn knn_graph( + points: &[[f64; D]], + k: usize, + symmetry: Symmetry, + weight: SpatialWeight, +) -> Result { + if k == 0 { + return Err(ClusteringError::InvalidConfig( + "k must be at least 1".into(), + )); + } + validate_points(points)?; + weight.validate()?; + if points.is_empty() { + return CSRNetwork::from_csr_parts(vec![0], Vec::new(), Vec::new(), None); + } + + // Aim for a handful of points per cell, so the first ring or two usually suffices. + let grid = Grid::new(points, typical_spacing(points, k)); + + let mut adjacency: Vec> = points + .par_iter() + .enumerate() + .map(|(i, p)| { + let centre = grid.cell_of(p); + let limit = grid.max_ring(¢re); + let mut found: Vec = Vec::with_capacity(k * 2); + + for ring in 0..=limit { + grid.for_each_in_ring(¢re, ring, |j| { + if j as usize != i { + found.push((j, distance_sq(p, &points[j as usize]))); + } + }); + if found.len() < k { + continue; + } + // Anything still unvisited sits at Chebyshev distance >= ring + 1, so it is + // at least `ring * cell` away — a point can be anywhere inside its own cell, + // which costs one ring of slack. Once the k-th best beats that, stop. + found.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0))); + found.truncate(k.max(1).min(found.len())); + let safe = ring as f64 * grid.cell_size(); + if found[found.len() - 1].1 <= safe * safe { + break; + } + } + + found.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0))); + found.truncate(k); + found + }) + .collect(); + + symmetrise(&mut adjacency, symmetry); + assemble(adjacency, weight) +} + +/// A cell size that puts roughly `k` points in each cell. +fn typical_spacing(points: &[[f64; D]], k: usize) -> f64 { + let mut min = [f64::INFINITY; D]; + let mut max = [f64::NEG_INFINITY; D]; + for p in points { + for d in 0..D { + min[d] = min[d].min(p[d]); + max[d] = max[d].max(p[d]); + } + } + let mut volume = 1.0f64; + for d in 0..D { + volume *= (max[d] - min[d]).max(f64::MIN_POSITIVE); + } + let per_cell = (k.max(1) as f64).max(1.0); + let cells = (points.len() as f64 / per_cell).max(1.0); + (volume / cells).powf(1.0 / D as f64).max(f64::MIN_POSITIVE) +} + +/// Rewrites `adjacency` in place so `j ∈ adj[i]` exactly when `i ∈ adj[j]`. +/// +/// Done explicitly rather than by emitting both directions and letting construction merge +/// them: duplicates are *summed* there, which would quietly give mutual pairs twice the +/// weight of one-sided ones. +fn symmetrise(adjacency: &mut [Vec], symmetry: Symmetry) { + let n = adjacency.len(); + + // Reverse lists via counting sort — O(total edges), and no per-node allocation. + let mut counts = vec![0u32; n + 1]; + for list in adjacency.iter() { + for &(u, _) in list { + counts[u as usize + 1] += 1; + } + } + for i in 0..n { + counts[i + 1] += counts[i]; + } + let mut reverse = vec![(0u32, 0.0f64); counts[n] as usize]; + let mut cursor: Vec = counts[..n].to_vec(); + for (v, list) in adjacency.iter().enumerate() { + for &(u, d) in list { + reverse[cursor[u as usize] as usize] = (v as u32, d); + cursor[u as usize] += 1; + } + } + + for (v, list) in adjacency.iter_mut().enumerate() { + let incoming = &reverse[counts[v] as usize..counts[v + 1] as usize]; + match symmetry { + Symmetry::Union => { + list.extend_from_slice(incoming); + list.sort_unstable_by_key(|&(u, _)| u); + list.dedup_by_key(|&mut (u, _)| u); + } + Symmetry::Intersection => { + let mut mutual: Vec = incoming.iter().map(|&(u, _)| u).collect(); + mutual.sort_unstable(); + list.retain(|&(u, _)| mutual.binary_search(&u).is_ok()); + list.sort_unstable_by_key(|&(u, _)| u); + } + } + } +} + +/// Flattens symmetric adjacency lists into a graph. +fn assemble(adjacency: Vec>, weight: SpatialWeight) -> Result { + let n = adjacency.len(); + let mut node_ptrs = Vec::with_capacity(n + 1); + node_ptrs.push(0usize); + let mut total = 0usize; + for list in &adjacency { + total += list.len(); + node_ptrs.push(total); + } + + let mut neighbors = Vec::with_capacity(total); + let mut weights = Vec::with_capacity(total); + for list in &adjacency { + for &(u, d2) in list { + neighbors.push(u); + weights.push(weight.apply(d2) as f32); + } + } + + CSRNetwork::from_csr_parts(node_ptrs, neighbors, weights, None) +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::{Rng, SeedableRng}; + use std::collections::HashSet; + + fn grid(side: usize) -> Vec<[f64; 2]> { + (0..side) + .flat_map(|r| (0..side).map(move |c| [c as f64, r as f64])) + .collect() + } + + fn edge_set(g: &CSRNetwork) -> HashSet<(usize, usize)> { + let mut out = HashSet::new(); + for v in 0..g.node_count() { + for (u, _) in g.neighbors(v) { + out.insert((v.min(u), v.max(u))); + } + } + out + } + + /// On a unit grid the radius picks out a known connectivity, so this is exact. + #[test] + fn radius_on_a_unit_grid_is_exactly_the_expected_connectivity() { + let pts = grid(6); + let four = radius_graph(&pts, 1.01, SpatialWeight::Uniform, None).unwrap(); + let eight = radius_graph(&pts, 1.5, SpatialWeight::Uniform, None).unwrap(); + + // 6x6 grid: 4-connected has 2*6*5 = 60 edges, 8-connected adds 2*5*5 = 50 diagonals. + assert_eq!(four.edge_count(), 60); + assert_eq!(eight.edge_count(), 110); + assert!(edge_set(&four).is_subset(&edge_set(&eight))); + + for (v, p) in pts.iter().enumerate() { + if p[0] > 0.0 && p[0] < 5.0 && p[1] > 0.0 && p[1] < 5.0 { + assert_eq!(four.degree(v), 4); + assert_eq!(eight.degree(v), 8); + } + } + } + + /// A radius relation is symmetric before anything is done to it, so this must hold with + /// no reconciliation step at all. + #[test] + fn radius_is_symmetric_without_reconciliation() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(4); + let pts: Vec<[f64; 2]> = (0..400) + .map(|_| [rng.random::() * 20.0, rng.random::() * 20.0]) + .collect(); + let g = radius_graph(&pts, 2.0, SpatialWeight::Uniform, None).unwrap(); + g.validate_symmetry().unwrap(); + assert!(g.edge_count() > 0); + } + + /// The cross-check that matters: the two builders must agree on Visium. + #[test] + fn isometric_radius_reproduces_the_exact_hex_lattice() { + use crate::spatial::lattice::{Lattice, lattice_graph, visium_isometric_coords}; + + let (mut rows, mut cols) = (Vec::new(), Vec::new()); + for r in 0..20u32 { + for i in 0..16u32 { + rows.push(r); + cols.push(2 * i + (r % 2)); + } + } + let exact = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); + + let (x, y) = visium_isometric_coords(&rows, &cols, 100.0).unwrap(); + let pts: Vec<[f64; 2]> = x.iter().zip(&y).map(|(&a, &b)| [a, b]).collect(); + // Anything past the pitch but short of the next shell at pitch*sqrt(3). + let searched = radius_graph(&pts, 110.0, SpatialWeight::Uniform, None).unwrap(); + + assert_eq!(edge_set(&exact), edge_set(&searched)); + } + + #[test] + fn knn_union_contains_intersection_and_both_are_symmetric() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(11); + let pts: Vec<[f64; 2]> = (0..300) + .map(|_| [rng.random::() * 50.0, rng.random::() * 50.0]) + .collect(); + + let u = knn_graph(&pts, 6, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + let i = knn_graph(&pts, 6, Symmetry::Intersection, SpatialWeight::Uniform).unwrap(); + u.validate_symmetry().unwrap(); + i.validate_symmetry().unwrap(); + + assert!(edge_set(&i).is_subset(&edge_set(&u))); + assert!( + i.edge_count() < u.edge_count(), + "random points give some one-sided pairs" + ); + + for v in 0..pts.len() { + assert!(u.degree(v) >= 6, "union degree is at least k"); + assert!(i.degree(v) <= 6, "intersection degree is at most k"); + } + } + + /// Coordinates rounded to a pixel grid produce many exact ties; those must not make the + /// result depend on kd-tree traversal order. + #[test] + fn duplicate_points_still_give_a_deterministic_graph() { + let mut pts = Vec::new(); + for i in 0..40 { + // Four coincident points at each of ten sites. + for _ in 0..4 { + pts.push([(i % 10) as f64, 0.0]); + } + } + let first = knn_graph(&pts, 5, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + for _ in 0..8 { + let again = knn_graph(&pts, 5, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + assert_eq!(edge_set(&first), edge_set(&again)); + } + assert!( + !first.has_self_loops(), + "a point must not be its own neighbour" + ); + } + + #[test] + fn gaussian_weights_fall_off_with_distance() { + let pts = vec![[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]; + let g = radius_graph(&pts, 2.5, SpatialWeight::Gaussian { sigma: 1.0 }, None).unwrap(); + + let w = |a: usize, b: usize| g.neighbors(a).find(|&(u, _)| u == b).unwrap().1; + // exp(-1/2) and exp(-4/2), to f32 precision. + assert!((w(0, 1) - (-0.5f64).exp()).abs() < 1e-6, "got {}", w(0, 1)); + assert!((w(0, 2) - (-2.0f64).exp()).abs() < 1e-6, "got {}", w(0, 2)); + assert!(w(0, 1) > w(0, 2)); + assert_eq!(w(0, 1), w(1, 0), "the kernel must be symmetric"); + } + + #[test] + fn max_degree_bounds_the_hubs() { + // One dense clump: without a cap, every point sees every other. + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(2); + let pts: Vec<[f64; 2]> = (0..200) + .map(|_| [rng.random::(), rng.random::()]) + .collect(); + + let uncapped = radius_graph(&pts, 5.0, SpatialWeight::Uniform, None).unwrap(); + let capped = radius_graph(&pts, 5.0, SpatialWeight::Uniform, Some(10)).unwrap(); + assert_eq!(uncapped.degree(0), 199, "everything is within the radius"); + capped.validate_symmetry().unwrap(); + assert!(capped.edge_count() < uncapped.edge_count() / 5); + // Documented as a soft cap: symmetrisation can push a node back over it. + for v in 0..pts.len() { + assert!(capped.degree(v) >= 10, "each node keeps its own 10"); + } + } + + #[test] + fn works_in_three_dimensions() { + let pts: Vec<[f64; 3]> = (0..4) + .flat_map(|z| { + (0..4).flat_map(move |y| (0..4).map(move |x| [x as f64, y as f64, z as f64])) + }) + .collect(); + let g = radius_graph(&pts, 1.01, SpatialWeight::Uniform, None).unwrap(); + g.validate_symmetry().unwrap(); + // 4x4x4 grid, 6-connected: 3 * 4 * 4 * 3 = 144 edges. + assert_eq!(g.edge_count(), 144); + let interior = (0..pts.len()) + .find(|&v| pts[v].iter().all(|&c| c > 0.0 && c < 3.0)) + .unwrap(); + assert_eq!(g.degree(interior), 6); + } + + #[test] + fn node_order_does_not_change_the_graph() { + use rand::seq::SliceRandom; + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(9); + let pts: Vec<[f64; 2]> = (0..250) + .map(|_| [rng.random::() * 30.0, rng.random::() * 30.0]) + .collect(); + let reference: HashSet<(u64, u64)> = { + let g = knn_graph(&pts, 5, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + edge_set(&g) + .into_iter() + .map(|(a, b)| (a as u64, b as u64)) + .collect() + }; + + for _ in 0..5 { + let mut perm: Vec = (0..pts.len()).collect(); + perm.shuffle(&mut rng); + let shuffled: Vec<[f64; 2]> = perm.iter().map(|&i| pts[i]).collect(); + let g = knn_graph(&shuffled, 5, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + // Map back through the permutation and compare as sets. + let mapped: HashSet<(u64, u64)> = edge_set(&g) + .into_iter() + .map(|(a, b)| { + let (a, b) = (perm[a] as u64, perm[b] as u64); + (a.min(b), a.max(b)) + }) + .collect(); + assert_eq!(mapped, reference); + } + } + + /// `KdTree` panics past 32 items sharing a value on one axis. Spatial data does that as a + /// matter of course, so this covers the shapes that actually occur. + #[test] + fn survives_heavy_axis_alignment() { + // A full Visium row is 64 spots at one y; a capture area is 78 of them. + let mut visium = Vec::new(); + for r in 0..78 { + for i in 0..64 { + visium.push([(2 * i + (r % 2)) as f64 * 50.0, r as f64 * 86.6]); + } + } + let g = knn_graph(&visium, 6, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + g.validate_symmetry().unwrap(); + assert_eq!(g.node_count(), 4992); + + // A whole HD-sized row at a single y. + let row: Vec<[f64; 2]> = (0..3250).map(|i| [i as f64, 0.0]).collect(); + let g = radius_graph(&row, 1.5, SpatialWeight::Uniform, None).unwrap(); + assert_eq!(g.edge_count(), 3249, "a path along the row"); + + // Every point identical — the worst case for any tree. + let same = vec![[7.0, 7.0]; 200]; + for sym in [Symmetry::Union, Symmetry::Intersection] { + let g = knn_graph(&same, 5, sym, SpatialWeight::Uniform).unwrap(); + g.validate_symmetry() + .unwrap_or_else(|e| panic!("{sym:?}: {e}")); + assert!(!g.has_self_loops()); + } + } + + /// Point sets covering the shapes that break spatial indices: duplicates, collinear runs, + /// tight clumps, near-empty space. + fn awkward_point_sets(seed: u64) -> Vec<(String, Vec<[f64; 2]>)> { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + let mut out: Vec<(String, Vec<[f64; 2]>)> = Vec::new(); + + out.push(( + "uniform".into(), + (0..300) + .map(|_| [rng.random::() * 40.0, rng.random::() * 40.0]) + .collect(), + )); + out.push(( + "collinear".into(), + (0..200).map(|i| [i as f64, 0.0]).collect(), + )); + out.push(( + "grid_with_ties".into(), + (0..20) + .flat_map(|r| (0..20).map(move |c| [c as f64, r as f64])) + .collect(), + )); + out.push(("all_identical".into(), vec![[3.0, 4.0]; 150])); + out.push(( + "duplicated_pairs".into(), + (0..150).map(|i| [(i / 2) as f64, 0.0]).collect(), + )); + out.push(( + "two_far_clumps".into(), + (0..200) + .map(|i| { + let off = if i < 100 { 0.0 } else { 1000.0 }; + [off + rng.random::(), rng.random::()] + }) + .collect(), + )); + out.push(( + "one_dense_spike".into(), + (0..250) + .map(|i| { + if i < 200 { + [rng.random::() * 0.001, rng.random::() * 0.001] + } else { + [rng.random::() * 100.0, rng.random::() * 100.0] + } + }) + .collect(), + )); + out + } + + /// The radius search must agree with O(n²) brute force exactly, on every shape. + #[test] + fn radius_matches_brute_force() { + for (name, pts) in awkward_point_sets(21) { + for &radius in &[0.5f64, 1.5, 7.0] { + let g = radius_graph(&pts, radius, SpatialWeight::Uniform, None).unwrap(); + let got = edge_set(&g); + + let r2 = radius * radius; + let mut want = HashSet::new(); + for i in 0..pts.len() { + for j in (i + 1)..pts.len() { + let d2 = (pts[i][0] - pts[j][0]).powi(2) + (pts[i][1] - pts[j][1]).powi(2); + if d2 <= r2 { + want.insert((i, j)); + } + } + } + assert_eq!(got, want, "{name} at radius {radius}"); + } + } + } + + /// The k-nearest search must pick exactly the same neighbours brute force would, + /// including how it breaks ties. + #[test] + fn knn_matches_brute_force() { + for (name, pts) in awkward_point_sets(22) { + for &k in &[1usize, 3, 8] { + // Compare pre-symmetrisation, which is where the search itself is decided. + let mut want: Vec> = Vec::with_capacity(pts.len()); + for i in 0..pts.len() { + let mut all: Vec<(f64, u32)> = (0..pts.len()) + .filter(|&j| j != i) + .map(|j| { + let d2 = + (pts[i][0] - pts[j][0]).powi(2) + (pts[i][1] - pts[j][1]).powi(2); + (d2, j as u32) + }) + .collect(); + all.sort_unstable_by(|a, b| a.0.partial_cmp(&b.0).unwrap().then(a.1.cmp(&b.1))); + all.truncate(k); + let mut ids: Vec = all.into_iter().map(|(_, j)| j).collect(); + ids.sort_unstable(); + want.push(ids); + } + + // Intersection keeps only mutual pairs, so recover the directed lists by + // asking for the union and checking containment both ways instead. + let g = knn_graph(&pts, k, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + for (i, truth) in want.iter().enumerate() { + let neigh: HashSet = g.neighbors(i).map(|(u, _)| u).collect(); + for &j in truth { + assert!( + neigh.contains(&(j as usize)), + "{name} k={k}: node {i} lost its true neighbour {j}" + ); + } + } + // And every union edge must be justified by one side's true k-nearest. + for (i, truth) in want.iter().enumerate() { + for (u, _) in g.neighbors(i) { + assert!( + truth.contains(&(u as u32)) || want[u].contains(&(i as u32)), + "{name} k={k}: edge {i}-{u} is in neither node's k-nearest" + ); + } + } + } + } + } + + /// Xenium-scale: a few hundred thousand cells over a tissue section. + /// + /// ```text + /// cargo test --release --no-default-features xenium_scale -- --ignored --nocapture + /// ``` + #[test] + #[ignore = "takes a few seconds"] + fn xenium_scale() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); + let n = 500_000; + // ~12 mm square at roughly Xenium cell density. + let pts: Vec<[f64; 2]> = (0..n) + .map(|_| { + [ + rng.random::() * 12_000.0, + rng.random::() * 12_000.0, + ] + }) + .collect(); + + let t = std::time::Instant::now(); + let g = knn_graph(&pts, 6, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + let knn = t.elapsed(); + + let t = std::time::Instant::now(); + let r = radius_graph(&pts, 30.0, SpatialWeight::Uniform, None).unwrap(); + let rad = t.elapsed(); + + println!( + "{n} cells\n knn(6) {:.2?} {} edges\n radius(30) {:.2?} {} edges", + knn, + g.edge_count(), + rad, + r.edge_count() + ); + g.validate_symmetry().unwrap(); + r.validate_symmetry().unwrap(); + } + + #[test] + fn rejects_bad_input() { + let pts = grid(3); + assert!(radius_graph(&pts, 0.0, SpatialWeight::Uniform, None).is_err()); + assert!(radius_graph(&pts, f64::NAN, SpatialWeight::Uniform, None).is_err()); + assert!(knn_graph(&pts, 0, Symmetry::Union, SpatialWeight::Uniform).is_err()); + assert!(radius_graph(&pts, 1.0, SpatialWeight::Gaussian { sigma: 0.0 }, None).is_err()); + let bad = vec![[0.0, 0.0], [f64::NAN, 1.0]]; + assert!(radius_graph(&bad, 1.0, SpatialWeight::Uniform, None).is_err()); + } + + #[test] + fn handles_degenerate_input() { + let none: Vec<[f64; 2]> = Vec::new(); + assert_eq!( + radius_graph(&none, 1.0, SpatialWeight::Uniform, None) + .unwrap() + .node_count(), + 0 + ); + let one = vec![[1.0, 2.0]]; + let g = knn_graph(&one, 5, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + assert_eq!(g.node_count(), 1); + assert_eq!(g.edge_count(), 0); + + // Nothing within the radius. + let far = vec![[0.0, 0.0], [1000.0, 0.0]]; + let g = radius_graph(&far, 1.0, SpatialWeight::Uniform, None).unwrap(); + assert_eq!(g.edge_count(), 0); + } +} From 448f927a272ab2e4462c887b6bf67f7cc1e2ca0a Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 1 Aug 2026 18:01:05 +0200 Subject: [PATCH 03/20] feat(spatial): Delaunay neighbour graphs with adaptive pruning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parameter-free neighbourhoods: no radius, no k, and the triangulation adapts to local density on its own. Verified exactly via Euler — a triangulation of n points with h on the convex hull has precisely 3n - 3 - h edges. A triangulation covers the convex hull, so it invents edges across ventricles, concave boundaries and between detached fragments. Joining two sides of a hole is exactly the error that yields a plausible-looking meaningless domain, so pruning is not optional. HullPruning::Adaptive drops an edge longer than `factor` times the local edge scale at *both* endpoints. Three details, each measured rather than assumed: - local scale is the 25th percentile of incident edge lengths, not the median. A node on a hole rim has several edges spanning the void, and those inflate its median until the artefact looks normal — the statistic hides what it is meant to expose. At the median, 6 of 42 fragment bridges survived at any factor. - compares against max of the two scales, not min. With min, a genuine boundary between a dense nest and loose stroma keeps only 19-40% of its edges; with max, 92-95%. - factor defaults to 2.0: the largest value that fully separates two detached fragments, the one unambiguous requirement. Costs ~5% of edges on uniform points, less on real tissue. It will not clear a hole 2-3 cells across; that needs ~1.5 and costs 16% everywhere, and at that width it is arguable whether the cells either side are neighbours anyway. Gabriel and relative-neighbourhood graphs are not the answer despite being parameter-free: their emptiness tests pass for a hole, so Gabriel leaves 19 of 42 fragment bridges and drops 21% of real edges, RNG drops 52%. Degenerate input (collinear, all-coincident) is a hard error rather than an edgeless graph, which would cluster into singletons and look like a result. 11 tests including Euler exactness, hole clearance, fragment separation, density-boundary preservation, permutation invariance, and contiguity of Leiden domains on the result. --- Cargo.lock | 16 + Cargo.toml | 1 + src/error.rs | 14 + src/spatial/delaunay.rs | 666 ++++++++++++++++++++++++++++++++++++++++ src/spatial/mod.rs | 2 + src/spatial/points.rs | 6 + 6 files changed, 705 insertions(+) create mode 100644 src/spatial/delaunay.rs diff --git a/Cargo.lock b/Cargo.lock index e6eae2d..6c06d49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -347,6 +347,15 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +[[package]] +name = "delaunator" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1ee323c1275374f7e612d3724d12707079fb6a2117349fe144def656f5a880" +dependencies = [ + "robust", +] + [[package]] name = "divrem" version = "1.0.0" @@ -1131,6 +1140,12 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "robust" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e27ee8bb91ca0adcf0ecb116293afa12d393f9c2b9b9cd54d33e8078fe19839" + [[package]] name = "rustversion" version = "1.0.20" @@ -1237,6 +1252,7 @@ version = "0.7.0" dependencies = [ "anyhow", "criterion", + "delaunator", "hnsw_rs", "kiddo", "nalgebra-sparse", diff --git a/Cargo.toml b/Cargo.toml index a05f580..e4e9a5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ rand_chacha = { version = "0.9.0" } kiddo = { version = "5.2.2", optional = true } ndarray = { version = "0.16.1", features = ["rayon"], optional = true } hnsw_rs = { version = "0.3.2", features = ["simdeez_f"], optional = true } +delaunator = "1.1.0" [dev-dependencies] serde_json = "1.0" diff --git a/src/error.rs b/src/error.rs index 32cff75..1dc995b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -76,6 +76,15 @@ pub enum ClusteringError { /// The offending position. position: (u32, u32), }, + /// No triangulation exists for the given points — they are collinear, or fewer than + /// three distinct positions. + /// + /// Reported rather than returning an edgeless graph, which would cluster into singletons + /// and look like a result. + DegenerateTriangulation { + /// How many points were supplied. + n_points: usize, + }, /// Parallel coordinate arrays had different lengths. CoordinateLengthMismatch { /// Length of the first array. @@ -134,6 +143,11 @@ impl fmt::Display for ClusteringError { "nodes {} and {} both sit at lattice position ({row}, {col})", nodes.0, nodes.1 ), + Self::DegenerateTriangulation { n_points } => write!( + f, + "no Delaunay triangulation exists for these {n_points} points: they are \ + collinear, or fewer than three distinct positions" + ), Self::CoordinateLengthMismatch { got, expected } => { write!(f, "coordinate array has length {got}, expected {expected}") } diff --git a/src/spatial/delaunay.rs b/src/spatial/delaunay.rs new file mode 100644 index 0000000..a01ddec --- /dev/null +++ b/src/spatial/delaunay.rs @@ -0,0 +1,666 @@ +//! Delaunay neighbour graphs. +//! +//! Parameter-free: no radius, no `k`. Each cell is joined to the ones it actually borders, +//! and the triangulation adapts to local density on its own — dense regions get short edges, +//! sparse regions long ones, with no threshold to tune. Average degree is just under 6, since +//! a triangulation of `n` points with `h` on the convex hull has exactly `3n - 3 - h` edges. +//! +//! # Why pruning is still needed +//! +//! A triangulation covers the *convex hull* of the points, so it invents edges wherever the +//! tissue is not convex: across ventricles and vessels, around concave boundaries, and +//! between physically separate fragments on the same section. Those edges are long, and +//! joining two sides of a hole is exactly the kind of error that produces a plausible-looking +//! but meaningless domain. +//! +//! Note that the parameter-free subgraphs — Gabriel, relative-neighbourhood — do **not** fix +//! this. Their tests ask whether other points lie near the edge, and the whole point of a +//! hole is that nothing does, so a hole-spanning edge passes. Measured on two detached +//! fragments, Gabriel leaves 19 of 42 bridges standing and drops 21% of genuine edges +//! elsewhere; the relative-neighbourhood graph drops 52%. Removing an artefact edge needs a +//! rule about length. See [`HullPruning`]. +//! +//! # What other tools do +//! +//! Worth knowing, because the defaults differ sharply: +//! +//! * **squidpy** applies no pruning at all — `delaunay=True` returns the raw triangulation, +//! convex hull included. Its `radius` and `percentile` filters both default to off, and in +//! 1.6.x a scalar `radius` is *silently ignored* on the Delaunay path. +//! * **Giotto** is the only one that derives a cutoff automatically, using a global Tukey +//! whisker over all edge lengths. Being global, it fails exactly where tissue density +//! varies: on a dense block beside 24x sparser stroma it shatters the sparse side into +//! ~570 components while barely touching the dense one. +//! +//! That is the case for a local rule, and why [`HullPruning::Adaptive`] is the default here. + +use crate::error::{ClusteringError, Result}; +use crate::network::{CSRNetwork, MAX_NODES}; +use crate::spatial::points::SpatialWeight; + +/// How to drop the edges a triangulation invents across empty space. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum HullPruning { + /// Keep the whole triangulation. Correct only when the tissue really is convex and + /// gap-free, which is rare. + None, + /// Drop edges longer than this, in coordinate units. Use when the tissue has a known + /// scale and roughly uniform density. + MaxDistance(f64), + /// Drop the longest `fraction` of all edges. + /// + /// One global cutoff, so it over-prunes sparse regions and under-prunes dense ones + /// whenever density varies — which in tissue it always does. + Percentile { + /// Share of edges to drop, in `[0, 1)`. + fraction: f64, + }, + /// Drop an edge longer than `factor` times the local edge scale at **both** its + /// endpoints, where local scale is a low quantile of a node's incident edge lengths. + /// + /// Compares against `max` of the two scales rather than `min`, so an edge that is long + /// only because one end sits in sparse tissue survives — a real boundary between a dense + /// nest and loose stroma should stay connected. A hole-spanning edge is long relative to + /// both ends and goes. + /// + /// The default of 2.0 is measured, by `calibrate_adaptive_factor`: it is the largest + /// factor that fully separates two detached tissue fragments, which is the one + /// unambiguous requirement — separate pieces must never be joined. It costs about 5% of + /// edges on uniform-random points, and less on real tissue, whose cells pack more + /// regularly than a Poisson process. + /// + /// What it will *not* do is clear a hole only two or three cells across. Removing those + /// needs a factor around 1.5, which drops ~16% of genuine edges everywhere. That is a + /// resolution limit rather than a tuning failure: at two cells wide it is genuinely + /// arguable whether the cells either side are neighbours. + Adaptive { + /// Multiple of the local scale above which an edge is dropped. + factor: f64, + }, +} + +impl Default for HullPruning { + fn default() -> Self { + Self::Adaptive { factor: 2.0 } + } +} + +impl HullPruning { + fn validate(self) -> Result<()> { + match self { + Self::MaxDistance(d) if !d.is_finite() || d <= 0.0 => { + Err(ClusteringError::InvalidConfig(format!( + "max distance must be finite and positive, got {d}" + ))) + } + Self::Percentile { fraction } if !(0.0..1.0).contains(&fraction) => { + Err(ClusteringError::InvalidConfig(format!( + "fraction must be in [0, 1), got {fraction}" + ))) + } + Self::Adaptive { factor } if !factor.is_finite() || factor <= 0.0 => { + Err(ClusteringError::InvalidConfig(format!( + "factor must be finite and positive, got {factor}" + ))) + } + _ => Ok(()), + } + } +} + +/// Builds a Delaunay neighbour graph from 2D coordinates. +/// +/// 2D only — the 3D equivalent is a tetrahedralisation, which is a different algorithm and a +/// much heavier dependency. For 3D use [`radius_graph`](super::radius_graph) or +/// [`knn_graph`](super::knn_graph). +/// +/// # Errors +/// +/// If the points are degenerate (all collinear, or fewer than three distinct positions), so +/// no triangulation exists. That is reported rather than returning an empty graph, since an +/// edgeless graph would cluster into singletons and look like a result. +pub fn delaunay_graph( + points: &[[f64; 2]], + pruning: HullPruning, + weight: SpatialWeight, +) -> Result { + pruning.validate()?; + if points.len() > MAX_NODES { + return Err(ClusteringError::TooManyNodes { + n_nodes: points.len(), + }); + } + for (i, p) in points.iter().enumerate() { + if !p[0].is_finite() || !p[1].is_finite() { + return Err(ClusteringError::InvalidConfig(format!( + "point {i} has a non-finite coordinate" + ))); + } + } + + let n = points.len(); + if n < 2 { + return CSRNetwork::from_csr_parts(vec![0; n + 1], Vec::new(), Vec::new(), None); + } + // Two points have no triangle but do border each other. + if n == 2 { + let d2 = distance_sq(points[0], points[1]); + return build(n, &[(0, 1, d2)], weight); + } + + let coords: Vec = points + .iter() + .map(|p| delaunator::Point { x: p[0], y: p[1] }) + .collect(); + let tri = delaunator::triangulate(&coords); + if tri.triangles.is_empty() { + return Err(ClusteringError::DegenerateTriangulation { n_points: n }); + } + + // Each triangle contributes three edges; neighbouring triangles share them, so collect + // into a set keyed on the ordered pair. + let mut edges: Vec<(u32, u32, f64)> = Vec::with_capacity(tri.triangles.len()); + for t in tri.triangles.chunks_exact(3) { + for &(a, b) in &[(t[0], t[1]), (t[1], t[2]), (t[2], t[0])] { + if a < b { + edges.push((a as u32, b as u32, distance_sq(points[a], points[b]))); + } else { + edges.push((b as u32, a as u32, distance_sq(points[a], points[b]))); + } + } + } + edges.sort_unstable_by_key(|e| (e.0, e.1)); + edges.dedup_by_key(|e| (e.0, e.1)); + + let kept = prune(&edges, n, pruning); + build(n, &kept, weight) +} + +#[inline] +fn distance_sq(a: [f64; 2], b: [f64; 2]) -> f64 { + let (dx, dy) = (a[0] - b[0], a[1] - b[1]); + dx * dx + dy * dy +} + +fn prune(edges: &[(u32, u32, f64)], n: usize, pruning: HullPruning) -> Vec<(u32, u32, f64)> { + match pruning { + HullPruning::None => edges.to_vec(), + HullPruning::MaxDistance(d) => { + let limit = d * d; + edges.iter().copied().filter(|e| e.2 <= limit).collect() + } + HullPruning::Percentile { fraction } => { + let mut lengths: Vec = edges.iter().map(|e| e.2).collect(); + lengths.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); + let keep = ((edges.len() as f64) * (1.0 - fraction)).ceil() as usize; + if keep >= edges.len() { + return edges.to_vec(); + } + let limit = lengths[keep.saturating_sub(1).min(lengths.len() - 1)]; + edges.iter().copied().filter(|e| e.2 <= limit).collect() + } + HullPruning::Adaptive { factor } => { + let scale = local_scale(edges, n); + let f2 = factor * factor; + edges + .iter() + .copied() + .filter(|&(a, b, d2)| { + // Squared throughout, so the factor is squared too. + let s = scale[a as usize].max(scale[b as usize]); + d2 <= f2 * s + }) + .collect() + } + } +} + +/// Quantile of incident edge length used as a node's local spacing. +/// +/// Deliberately below the median. A node on the rim of a hole has several long edges reaching +/// across it, and those drag its median up until the spurious edges look normal — the median +/// hides exactly what we are trying to find. A lower quantile reads the genuine local +/// spacing, since at least a quarter of any node's edges go to real neighbours. +const SCALE_QUANTILE: f64 = 0.25; + +/// Squared local length scale per node. One small sort each, since Delaunay degree averages +/// just under 6. +fn local_scale(edges: &[(u32, u32, f64)], n: usize) -> Vec { + let mut incident: Vec> = vec![Vec::new(); n]; + for &(a, b, d2) in edges { + incident[a as usize].push(d2); + incident[b as usize].push(d2); + } + incident + .iter_mut() + .map(|lengths| { + if lengths.is_empty() { + return f64::INFINITY; + } + lengths.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); + let idx = ((lengths.len() - 1) as f64 * SCALE_QUANTILE).round() as usize; + lengths[idx] + }) + .collect() +} + +/// Turns an undirected edge list into a symmetric graph. +fn build(n: usize, edges: &[(u32, u32, f64)], weight: SpatialWeight) -> Result { + let mut degree = vec![0u32; n]; + for &(a, b, _) in edges { + degree[a as usize] += 1; + degree[b as usize] += 1; + } + let mut node_ptrs = Vec::with_capacity(n + 1); + node_ptrs.push(0usize); + let mut total = 0usize; + for &d in °ree { + total += d as usize; + node_ptrs.push(total); + } + + let mut neighbors = vec![0u32; total]; + let mut weights = vec![0.0f32; total]; + let mut cursor: Vec = node_ptrs[..n].to_vec(); + for &(a, b, d2) in edges { + let w = weight.of(d2) as f32; + neighbors[cursor[a as usize]] = b; + weights[cursor[a as usize]] = w; + cursor[a as usize] += 1; + neighbors[cursor[b as usize]] = a; + weights[cursor[b as usize]] = w; + cursor[b as usize] += 1; + } + + CSRNetwork::from_csr_parts(node_ptrs, neighbors, weights, None) +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::{Rng, SeedableRng}; + use std::collections::HashSet; + + fn uniform(n: usize, span: f64, seed: u64) -> Vec<[f64; 2]> { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + (0..n) + .map(|_| [rng.random::() * span, rng.random::() * span]) + .collect() + } + + /// A square of tissue with a circular hole punched out of the middle. + fn tissue_with_hole(seed: u64) -> (Vec<[f64; 2]>, [f64; 2], f64) { + tissue_with_hole_radius(seed, 15.0) + } + + fn tissue_with_hole_radius(seed: u64, hole: f64) -> (Vec<[f64; 2]>, [f64; 2], f64) { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + let centre = [50.0, 50.0]; + let pts = (0..3000) + .map(|_| [rng.random::() * 100.0, rng.random::() * 100.0]) + .filter(|p: &[f64; 2]| { + (p[0] - centre[0]).powi(2) + (p[1] - centre[1]).powi(2) > hole * hole + }) + .collect(); + (pts, centre, hole) + } + + /// Tissue in two pieces with a gap between, as a torn or folded section gives. + fn two_fragments(seed: u64) -> Vec<[f64; 2]> { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + (0..2000) + .map(|i| { + let off = if i % 2 == 0 { 0.0 } else { 75.0 }; + [off + rng.random::() * 50.0, rng.random::() * 50.0] + }) + .collect() + } + + /// Does the segment a-b pass through the disc? + fn crosses(a: [f64; 2], b: [f64; 2], centre: [f64; 2], r: f64) -> bool { + let (dx, dy) = (b[0] - a[0], b[1] - a[1]); + let len2 = dx * dx + dy * dy; + if len2 == 0.0 { + return false; + } + let t = (((centre[0] - a[0]) * dx + (centre[1] - a[1]) * dy) / len2).clamp(0.0, 1.0); + let (px, py) = (a[0] + t * dx, a[1] + t * dy); + (px - centre[0]).powi(2) + (py - centre[1]).powi(2) < r * r + } + + fn edge_set(g: &CSRNetwork) -> HashSet<(usize, usize)> { + let mut out = HashSet::new(); + for v in 0..g.node_count() { + for (u, _) in g.neighbors(v) { + out.insert((v.min(u), v.max(u))); + } + } + out + } + + /// Euler's formula: a Delaunay triangulation of `n` points with `h` on the convex hull + /// has exactly `3n - 3 - h` edges. Nothing approximate about it. + #[test] + fn unpruned_edge_count_matches_eulers_formula() { + for (n, seed) in [(50usize, 1u64), (500, 2), (2000, 3)] { + let pts = uniform(n, 100.0, seed); + let g = delaunay_graph(&pts, HullPruning::None, SpatialWeight::Uniform).unwrap(); + + let coords: Vec = pts + .iter() + .map(|p| delaunator::Point { x: p[0], y: p[1] }) + .collect(); + let h = delaunator::triangulate(&coords).hull.len(); + + assert_eq!(g.edge_count(), 3 * n - 3 - h, "n={n}, hull={h}"); + // Which puts average degree just under 6. + let avg = 2.0 * g.edge_count() as f64 / n as f64; + assert!(avg < 6.0 && avg > 5.0, "average degree {avg} at n={n}"); + } + } + + /// The reason pruning exists: a triangulation spans holes, and the default must not. + #[test] + fn adaptive_pruning_clears_a_tissue_hole() { + let (pts, centre, hole) = tissue_with_hole(7); + let count_crossing = |g: &CSRNetwork| { + edge_set(g) + .iter() + .filter(|&&(a, b)| crosses(pts[a], pts[b], centre, hole * 0.9)) + .count() + }; + + let raw = delaunay_graph(&pts, HullPruning::None, SpatialWeight::Uniform).unwrap(); + let pruned = delaunay_graph(&pts, HullPruning::default(), SpatialWeight::Uniform).unwrap(); + + let before = count_crossing(&raw); + let after = count_crossing(&pruned); + println!("hole-crossing edges: {before} raw -> {after} pruned"); + assert!( + before >= 5, + "the hole should be bridged before pruning: {before}" + ); + assert_eq!(after, 0, "{after} edges still cross the hole"); + // And it must not gut the rest of the graph. The default costs ~5% on uniform-random + // points, which are less regularly packed than real cells, so this is the pessimistic + // end of the range. + assert!( + pruned.edge_count() as f64 > 0.92 * raw.edge_count() as f64, + "pruning removed {} of {} edges", + raw.edge_count() - pruned.edge_count(), + raw.edge_count() + ); + } + + /// Why the rule compares against `max` of the two local scales, not `min`: a genuine + /// boundary between dense and sparse tissue has to survive. + #[test] + fn adaptive_pruning_keeps_a_dense_to_sparse_boundary() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(5); + let mut pts: Vec<[f64; 2]> = Vec::new(); + // Dense nest on the left, loose stroma on the right, touching at x = 50. + for _ in 0..1500 { + pts.push([rng.random::() * 50.0, rng.random::() * 50.0]); + } + for _ in 0..150 { + pts.push([ + 50.0 + rng.random::() * 50.0, + rng.random::() * 50.0, + ]); + } + + let g = delaunay_graph(&pts, HullPruning::default(), SpatialWeight::Uniform).unwrap(); + let spanning = edge_set(&g) + .iter() + .filter(|&&(a, b)| (pts[a][0] - 50.0).signum() != (pts[b][0] - 50.0).signum()) + .count(); + assert!( + spanning > 10, + "only {spanning} edges cross the density boundary; the two regions are severed" + ); + } + + /// Sweeps the one tuned constant across every artefact it has to remove and everything it + /// must not, over several seeds, so the default is a measurement rather than a guess. + /// + /// A large hole is easy and tells you little. The discriminating cases are a + /// capillary-scale hole a few cell spacings across, and two separated fragments. + /// + /// ```text + /// cargo test --release --no-default-features calibrate_adaptive -- --ignored --nocapture + /// ``` + #[test] + #[ignore = "diagnostic sweep, not an assertion"] + fn calibrate_adaptive_factor() { + println!( + "{:>6} | {:>9} | {:>8} | {:>9} | {:>6} | {:>8}", + "factor", "hole r=15", "hole r=4", "fragments", "kept", "boundary" + ); + + for factor in [1.5, 2.0, 2.5, 3.0, 4.0, 6.0] { + let p = HullPruning::Adaptive { factor }; + let (mut big, mut small, mut bridges, mut kept, mut boundary) = + (0usize, 0usize, 0usize, 0.0f64, 0usize); + + for seed in 0..4u64 { + for (radius, counter) in [(15.0, &mut big), (4.0, &mut small)] { + let (pts, centre, hole) = tissue_with_hole_radius(seed, radius); + let g = delaunay_graph(&pts, p, SpatialWeight::Uniform).unwrap(); + *counter += edge_set(&g) + .iter() + .filter(|&&(a, b)| crosses(pts[a], pts[b], centre, hole * 0.9)) + .count(); + if radius == 15.0 { + let raw = delaunay_graph(&pts, HullPruning::None, SpatialWeight::Uniform) + .unwrap(); + kept += 100.0 * g.edge_count() as f64 / raw.edge_count() as f64; + } + } + + let frag = two_fragments(seed); + let g = delaunay_graph(&frag, p, SpatialWeight::Uniform).unwrap(); + bridges += edge_set(&g) + .iter() + .filter(|&&(a, b)| (frag[a][0] < 60.0) != (frag[b][0] < 60.0)) + .count(); + + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(100 + seed); + let mut mixed: Vec<[f64; 2]> = Vec::new(); + for _ in 0..1500 { + mixed.push([rng.random::() * 50.0, rng.random::() * 50.0]); + } + for _ in 0..150 { + mixed.push([ + 50.0 + rng.random::() * 50.0, + rng.random::() * 50.0, + ]); + } + let m = delaunay_graph(&mixed, p, SpatialWeight::Uniform).unwrap(); + boundary += edge_set(&m) + .iter() + .filter(|&&(a, b)| { + (mixed[a][0] - 50.0).signum() != (mixed[b][0] - 50.0).signum() + }) + .count(); + } + + println!( + "{factor:>6.1} | {big:>9} | {small:>8} | {bridges:>9} | {:>5.1}% | {boundary:>8}", + kept / 4.0 + ); + } + } + + /// Detached tissue pieces must never be joined — the criterion the default is set by. + #[test] + fn detached_fragments_are_never_bridged() { + for seed in 0..4 { + let pts = two_fragments(seed); + let g = delaunay_graph(&pts, HullPruning::default(), SpatialWeight::Uniform).unwrap(); + let bridges = edge_set(&g) + .iter() + .filter(|&&(a, b)| (pts[a][0] < 60.0) != (pts[b][0] < 60.0)) + .count(); + assert_eq!(bridges, 0, "seed {seed} left {bridges} bridging edges"); + + // And each fragment must survive intact rather than being shattered. + let c = crate::testdata::disconnected_community_count( + &g, + &pts.iter() + .map(|p| usize::from(p[0] >= 60.0)) + .collect::>(), + ); + assert_eq!(c, 0, "seed {seed}: a fragment came apart"); + } + } + + #[test] + fn pruning_modes_are_ordered_by_aggressiveness() { + let pts = uniform(1000, 100.0, 11); + let raw = delaunay_graph(&pts, HullPruning::None, SpatialWeight::Uniform).unwrap(); + + let mut previous = raw.edge_count(); + for fraction in [0.01, 0.05, 0.2] { + let g = delaunay_graph( + &pts, + HullPruning::Percentile { fraction }, + SpatialWeight::Uniform, + ) + .unwrap(); + assert!(g.edge_count() < previous, "fraction {fraction} kept more"); + previous = g.edge_count(); + } + + let mut previous = raw.edge_count(); + for factor in [4.0, 2.0, 1.2] { + let g = delaunay_graph( + &pts, + HullPruning::Adaptive { factor }, + SpatialWeight::Uniform, + ) + .unwrap(); + assert!(g.edge_count() <= previous, "factor {factor} kept more"); + previous = g.edge_count(); + } + } + + #[test] + fn is_symmetric_and_order_independent() { + use rand::seq::SliceRandom; + let pts = uniform(600, 80.0, 13); + let g = delaunay_graph(&pts, HullPruning::default(), SpatialWeight::Uniform).unwrap(); + g.validate_symmetry().unwrap(); + assert!(!g.has_self_loops()); + + let reference: HashSet<(usize, usize)> = edge_set(&g); + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(3); + for _ in 0..4 { + let mut perm: Vec = (0..pts.len()).collect(); + perm.shuffle(&mut rng); + let shuffled: Vec<[f64; 2]> = perm.iter().map(|&i| pts[i]).collect(); + let h = + delaunay_graph(&shuffled, HullPruning::default(), SpatialWeight::Uniform).unwrap(); + let mapped: HashSet<(usize, usize)> = edge_set(&h) + .into_iter() + .map(|(a, b)| (perm[a].min(perm[b]), perm[a].max(perm[b]))) + .collect(); + assert_eq!(mapped, reference); + } + } + + #[test] + fn max_distance_is_exact() { + let pts = uniform(500, 50.0, 17); + let limit = 3.0; + let g = delaunay_graph( + &pts, + HullPruning::MaxDistance(limit), + SpatialWeight::Uniform, + ) + .unwrap(); + for (a, b) in edge_set(&g) { + let d = distance_sq(pts[a], pts[b]).sqrt(); + assert!(d <= limit + 1e-9, "kept an edge of length {d}"); + } + } + + #[test] + fn degenerate_input_is_reported_not_silently_empty() { + // Collinear points have no triangulation. + let line: Vec<[f64; 2]> = (0..50).map(|i| [i as f64, 0.0]).collect(); + assert!(matches!( + delaunay_graph(&line, HullPruning::None, SpatialWeight::Uniform), + Err(ClusteringError::DegenerateTriangulation { .. }) + )); + + // As do coincident ones. + let same = vec![[1.0, 1.0]; 40]; + assert!(matches!( + delaunay_graph(&same, HullPruning::None, SpatialWeight::Uniform), + Err(ClusteringError::DegenerateTriangulation { .. }) + )); + } + + #[test] + fn handles_small_inputs() { + let none: Vec<[f64; 2]> = Vec::new(); + assert_eq!( + delaunay_graph(&none, HullPruning::None, SpatialWeight::Uniform) + .unwrap() + .node_count(), + 0 + ); + let one = vec![[0.0, 0.0]]; + let g = delaunay_graph(&one, HullPruning::None, SpatialWeight::Uniform).unwrap(); + assert_eq!((g.node_count(), g.edge_count()), (1, 0)); + + // Two points border each other even though there is no triangle. + let two = vec![[0.0, 0.0], [1.0, 0.0]]; + let g = delaunay_graph(&two, HullPruning::None, SpatialWeight::Uniform).unwrap(); + assert_eq!((g.node_count(), g.edge_count()), (2, 1)); + + let three = vec![[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]; + let g = delaunay_graph(&three, HullPruning::None, SpatialWeight::Uniform).unwrap(); + assert_eq!(g.edge_count(), 3, "a single triangle"); + } + + #[test] + fn rejects_bad_config() { + let pts = uniform(50, 10.0, 1); + for bad in [ + HullPruning::MaxDistance(0.0), + HullPruning::MaxDistance(f64::NAN), + HullPruning::Percentile { fraction: 1.0 }, + HullPruning::Percentile { fraction: -0.1 }, + HullPruning::Adaptive { factor: 0.0 }, + ] { + assert!( + delaunay_graph(&pts, bad, SpatialWeight::Uniform).is_err(), + "{bad:?} should be rejected" + ); + } + let bad = vec![[0.0, 0.0], [f64::NAN, 1.0], [1.0, 1.0]]; + assert!(delaunay_graph(&bad, HullPruning::None, SpatialWeight::Uniform).is_err()); + } + + /// Leiden on a Delaunay graph must still give spatially contiguous domains. + #[test] + fn leiden_domains_stay_contiguous() { + use crate::community_search::leiden::{LeidenConfig, ObjectiveKind, leiden}; + let pts = uniform(2000, 100.0, 23); + let g = delaunay_graph(&pts, HullPruning::default(), SpatialWeight::Uniform).unwrap(); + let c = leiden( + &g, + &LeidenConfig { + objective: ObjectiveKind::Cpm { resolution: 0.2 }, + ..Default::default() + }, + ) + .unwrap(); + assert_eq!( + crate::testdata::disconnected_community_count(&g, c.labels()), + 0 + ); + assert!(c.n_clusters() > 1); + } +} diff --git a/src/spatial/mod.rs b/src/spatial/mod.rs index 345c7cf..4440286 100644 --- a/src/spatial/mod.rs +++ b/src/spatial/mod.rs @@ -23,9 +23,11 @@ //! //! Neither affects `array_row` / `array_col`, which is what [`lattice_graph`] wants. +pub mod delaunay; pub(crate) mod grid; pub mod lattice; pub mod points; +pub use delaunay::{HullPruning, delaunay_graph}; pub use lattice::{Lattice, lattice_graph, visium_isometric_coords}; pub use points::{SpatialWeight, Symmetry, knn_graph, radius_graph}; diff --git a/src/spatial/points.rs b/src/spatial/points.rs index eacf2bd..042e1dd 100644 --- a/src/spatial/points.rs +++ b/src/spatial/points.rs @@ -44,6 +44,12 @@ pub enum SpatialWeight { } impl SpatialWeight { + /// Weight for an edge of the given squared length. + #[inline] + pub(crate) fn of(self, distance_sq: f64) -> f64 { + self.apply(distance_sq) + } + #[inline] fn apply(self, distance_sq: f64) -> f64 { match self { From a36aad77fd9967fd7f2f716edace86781c8dff24 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 1 Aug 2026 18:07:14 +0200 Subject: [PATCH 04/20] docs(spatial): ground the Delaunay pruning rule in prior art MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The adaptive rule turns out to be Zahn's 1971 inconsistent-edge criterion: delete an edge "significantly larger than the average of nearby edge weights on both sides", which is the same both-endpoints shape used here. He reports "a factor of 2 usually means the separation is quite apparent", with worked examples from 1.3 to 2.6 — so the default of 2.0, arrived at by measurement, is also the canonical value. Records his limitation too, since it carries over unchanged: the criterion "doesn't detect one-way gradients however steep", so a smoothly ramping density gives it no discontinuity to find. Also notes what it would take to add Gabriel/RNG later: Lingas (1994) extracts either from an existing triangulation in O(n), and the exclusion region must be open, since the closed variant disconnects on ties and gridded coordinates are made of ties. --- src/spatial/delaunay.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/spatial/delaunay.rs b/src/spatial/delaunay.rs index a01ddec..c6a6625 100644 --- a/src/spatial/delaunay.rs +++ b/src/spatial/delaunay.rs @@ -20,6 +20,13 @@ //! elsewhere; the relative-neighbourhood graph drops 52%. Removing an artefact edge needs a //! rule about length. See [`HullPruning`]. //! +//! They may still be worth adding as an option one day — MST ⊆ RNG ⊆ GG ⊆ Delaunay, both are +//! always connected, and Lingas (1994) extracts either from an existing triangulation in +//! O(n), so they are nearly free once the Delaunay exists. Two things to get right if so: +//! use the **open** exclusion region, since the closed variant disconnects on ties and +//! gridded coordinates are made of ties; and expect mean degree ~4 for Gabriel and ~2.56 for +//! RNG against Delaunay's 6. +//! //! # What other tools do //! //! Worth knowing, because the defaults differ sharply: @@ -69,10 +76,17 @@ pub enum HullPruning { /// edges on uniform-random points, and less on real tissue, whose cells pack more /// regularly than a Poisson process. /// - /// What it will *not* do is clear a hole only two or three cells across. Removing those - /// needs a factor around 1.5, which drops ~16% of genuine edges everywhere. That is a - /// resolution limit rather than a tuning failure: at two cells wide it is genuinely - /// arguable whether the cells either side are neighbours. + /// It also happens to be the canonical value. Zahn's 1971 inconsistent-edge criterion is + /// this same shape — an edge "significantly larger than the average of nearby edge + /// weights on **both sides** of the edge" — and he reports that "a factor of 2 usually + /// means the separation is quite apparent", with worked examples spanning 1.3 to 2.6. + /// + /// Two things it will not do. It cannot clear a hole only two or three cells across: + /// that needs a factor near 1.5, which drops ~16% of genuine edges everywhere, and at + /// that width it is arguable whether the cells either side are neighbours at all. And, + /// as Zahn notes of the same criterion, it "doesn't detect one-way gradients however + /// steep" — a tissue whose density ramps smoothly across the section has no local + /// discontinuity for the rule to find. Adaptive { /// Multiple of the local scale above which an edge is dropped. factor: f64, From 4426206d6b7ce8a8c370edf32a01a95f78b204d4 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 1 Aug 2026 20:32:33 +0200 Subject: [PATCH 05/20] test(spatial): stability and validity of the neighbour graphs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing tests prove each builder produces the graph it claims to. These ask the different question: does what comes out survive what real data does to you — cells missed by segmentation, centroids off by a fraction of a cell, a parameter picked slightly differently. Writing them turned up a limitation worth stating plainly. A bare spatial graph carries no expression, so the only thing it can recover is spatial structure. Physical separation it gets exactly: detached fragments and masked-apart tissue come back as connected components, with no resolution to choose, unchanged by 30% subsampling, by coordinate jitter, and across every parameter tried. Boundaries *inside* continuous tissue it does not get. There is nothing for the objective to anchor to, so it returns a tiling whose blob size the resolution sets. The tiling is spatially contiguous and looks exactly like a result, and it is arbitrary — resample and the boundaries move. My first attempt at these tests assumed otherwise and asserted domain recovery on planted density nests; it came back at ARI 0.09, which is the correct answer to the wrong question. So the file now asserts the limitation too: on homogeneous tissue the tiling must *fail* to reproduce under resampling. If that ever starts holding up, the assertion fires and says the docs need revisiting. 9 tests. The meaningful guarantee across resolutions is that a domain may subdivide an island but never spans two. --- tests/common/mod.rs | 30 ++++ tests/spatial_stability.rs | 334 +++++++++++++++++++++++++++++++++++++ 2 files changed, 364 insertions(+) create mode 100644 tests/spatial_stability.rs diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 7f2cc17..4bce6bf 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -129,6 +129,36 @@ pub fn test_graphs() -> Vec<(String, CSRNetwork)> { out } +/// Adjusted Rand Index: agreement between two labellings, corrected for chance. +/// +/// 1.0 is exact agreement, 0.0 is what random labelling scores. Unlike NMI it does not +/// reward splitting, so a partition that shatters one of the two is penalised. +pub fn adjusted_rand_index(a: &[usize], b: &[usize]) -> f64 { + let n = a.len() as f64; + if a.len() < 2 { + return 1.0; + } + let ka = a.iter().max().map_or(0, |m| m + 1); + let kb = b.iter().max().map_or(0, |m| m + 1); + let mut joint = std::collections::HashMap::new(); + let (mut sa, mut sb) = (vec![0.0f64; ka], vec![0.0f64; kb]); + for i in 0..a.len() { + *joint.entry((a[i], b[i])).or_insert(0.0f64) += 1.0; + sa[a[i]] += 1.0; + sb[b[i]] += 1.0; + } + let comb2 = |x: f64| x * (x - 1.0) / 2.0; + let sum_ij: f64 = joint.values().map(|&c| comb2(c)).sum(); + let sum_a: f64 = sa.iter().map(|&c| comb2(c)).sum(); + let sum_b: f64 = sb.iter().map(|&c| comb2(c)).sum(); + let expected = sum_a * sum_b / comb2(n); + let max = 0.5 * (sum_a + sum_b); + if (max - expected).abs() < 1e-12 { + return 1.0; + } + (sum_ij - expected) / (max - expected) +} + /// Normalized mutual information between two labellings, in `[0, 1]`. pub fn nmi(a: &[usize], b: &[usize]) -> f64 { let n = a.len() as f64; diff --git a/tests/spatial_stability.rs b/tests/spatial_stability.rs new file mode 100644 index 0000000..5df7d70 --- /dev/null +++ b/tests/spatial_stability.rs @@ -0,0 +1,334 @@ +//! Stability and validity of the spatial neighbour graphs. +//! +//! The unit tests prove each builder produces the graph it claims to. That is necessary but +//! not sufficient: what matters on real data is whether what you get out survives what real +//! data does to you — cells missed by segmentation, coordinates off by a fraction of a cell, +//! a parameter chosen slightly differently. +//! +//! # What a bare spatial graph can and cannot do +//! +//! It carries no expression, so the only structure it encodes is spatial: which cells are +//! near which. Two consequences, and both are asserted here. +//! +//! It reliably recovers **physical separation** — detached fragments, tissue masked apart, +//! anything with a real gap. That shows up as connected components, needs no resolution +//! choice, and is stable under every perturbation tried below. +//! +//! It does **not** find boundaries inside continuous tissue. There is nothing for the +//! objective to anchor to, so it returns a tiling whose blob size is set by the resolution. +//! The tiling is spatially contiguous and looks exactly like a result, but it is arbitrary, +//! and therefore unstable: resample and the boundaries move. That is asserted too, so the +//! limitation cannot quietly stop being true. +//! +//! So the resolution-free question — "which cells could possibly be in the same domain" — is +//! the one a spatial graph answers. Choosing among the domains inside a connected region +//! needs expression, which arrives with neighbourhood feature averaging. + +mod common; + +use common::{adjusted_rand_index, disconnected_community_count}; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use single_clustering::community_search::leiden::{LeidenConfig, ObjectiveKind, leiden}; +use single_clustering::network::CSRNetwork; +use single_clustering::spatial::{ + HullPruning, Lattice, SpatialWeight, Symmetry, delaunay_graph, knn_graph, lattice_graph, + radius_graph, +}; + +/// Four tissue islands with clear space between them. +fn separated_tissue(seed: u64) -> (Vec<[f64; 2]>, Vec) { + let mut rng = ChaCha8Rng::seed_from_u64(seed); + let centres = [[20.0, 20.0], [80.0, 20.0], [20.0, 80.0], [80.0, 80.0]]; + let radius = 18.0; + + let mut pts = Vec::new(); + let mut truth = Vec::new(); + for (i, c) in centres.iter().enumerate() { + for _ in 0..700 { + let a = rng.random::() * std::f64::consts::TAU; + let r = radius * rng.random::().sqrt(); + pts.push([c[0] + r * a.cos(), c[1] + r * a.sin()]); + truth.push(i); + } + } + (pts, truth) +} + +/// Featureless tissue at one density — nothing for a spatial objective to find. +fn homogeneous_tissue(seed: u64) -> Vec<[f64; 2]> { + let mut rng = ChaCha8Rng::seed_from_u64(seed); + (0..2500) + .map(|_| [rng.random::() * 100.0, rng.random::() * 100.0]) + .collect() +} + +/// Connected component of each node — the resolution-free structure a spatial graph encodes. +fn components(graph: &CSRNetwork) -> Vec { + let n = graph.node_count(); + let mut label = vec![usize::MAX; n]; + let mut next = 0; + for start in 0..n { + if label[start] != usize::MAX { + continue; + } + let mut stack = vec![start]; + label[start] = next; + while let Some(v) = stack.pop() { + for (u, _) in graph.neighbors(v) { + if label[u] == usize::MAX { + label[u] = next; + stack.push(u); + } + } + } + next += 1; + } + label +} + +fn cluster(graph: &CSRNetwork, resolution: f64) -> Vec { + let config = LeidenConfig { + objective: ObjectiveKind::Cpm { resolution }, + ..Default::default() + }; + leiden(graph, &config).unwrap().labels().to_vec() +} + +const BUILDERS: [&str; 3] = ["radius", "knn", "delaunay"]; + +fn build(name: &str, pts: &[[f64; 2]]) -> CSRNetwork { + match name { + "radius" => radius_graph(pts, 4.0, SpatialWeight::Uniform, None).unwrap(), + "knn" => knn_graph(pts, 8, Symmetry::Union, SpatialWeight::Uniform).unwrap(), + _ => delaunay_graph(pts, HullPruning::default(), SpatialWeight::Uniform).unwrap(), + } +} + +/// Validity: separated tissue must come back as separate components — exactly, and with no +/// resolution to choose. +#[test] +fn every_builder_separates_disconnected_tissue() { + let (pts, truth) = separated_tissue(1); + for name in BUILDERS { + let agreement = adjusted_rand_index(&components(&build(name, &pts)), &truth); + assert!( + (agreement - 1.0).abs() < 1e-9, + "{name}: components do not match the islands (ARI {agreement:.4})" + ); + } +} + +/// Validity: a domain may subdivide an island, but must never span two. That holds at every +/// resolution, which is what makes it the meaningful guarantee. +#[test] +fn no_domain_ever_spans_separated_tissue() { + let (pts, truth) = separated_tissue(7); + for name in BUILDERS { + let graph = build(name, &pts); + for resolution in [0.01, 0.05, 0.2, 1.0] { + let labels = cluster(&graph, resolution); + let mut owner = std::collections::HashMap::new(); + for (v, &c) in labels.iter().enumerate() { + let island = *owner.entry(c).or_insert(truth[v]); + assert_eq!( + island, truth[v], + "{name} at resolution {resolution}: a domain spans two islands" + ); + } + } + } +} + +/// Stability: segmentation misses cells, so dropping some must not change the structure. +#[test] +fn structure_survives_subsampling() { + let (pts, _) = separated_tissue(2); + for name in BUILDERS { + let full = components(&build(name, &pts)); + + for drop in [0.05, 0.15, 0.3] { + let mut rng = ChaCha8Rng::seed_from_u64(99); + let keep: Vec = (0..pts.len()) + .filter(|_| rng.random::() > drop) + .collect(); + let sub: Vec<[f64; 2]> = keep.iter().map(|&i| pts[i]).collect(); + let restricted: Vec = keep.iter().map(|&i| full[i]).collect(); + + let agreement = adjusted_rand_index(&components(&build(name, &sub)), &restricted); + assert!( + agreement > 0.99, + "{name}: dropping {:.0}% of cells changed the structure ({agreement:.4})", + drop * 100.0 + ); + } + } +} + +/// Stability: segmentation centroids are not exact, so jitter below cell spacing must not +/// move anything. +#[test] +fn structure_survives_coordinate_jitter() { + let (pts, _) = separated_tissue(3); + for name in BUILDERS { + let reference = components(&build(name, &pts)); + + let mut rng = ChaCha8Rng::seed_from_u64(7); + let jittered: Vec<[f64; 2]> = pts + .iter() + .map(|p| { + [ + p[0] + (rng.random::() - 0.5) * 0.5, + p[1] + (rng.random::() - 0.5) * 0.5, + ] + }) + .collect(); + + let agreement = adjusted_rand_index(&components(&build(name, &jittered)), &reference); + assert!( + agreement > 0.99, + "{name}: coordinate jitter changed the structure ({agreement:.4})" + ); + } +} + +/// The builders define "neighbour" differently, but must agree about real structure. +#[test] +fn builders_agree_on_real_structure() { + let (pts, _) = separated_tissue(5); + let labels: Vec<(&str, Vec)> = BUILDERS + .iter() + .map(|&name| (name, components(&build(name, &pts)))) + .collect(); + + for i in 0..labels.len() { + for j in (i + 1)..labels.len() { + let agreement = adjusted_rand_index(&labels[i].1, &labels[j].1); + assert!( + agreement > 0.99, + "{} and {} disagree ({agreement:.4})", + labels[i].0, + labels[j].0 + ); + } + } +} + +/// Stability: neighbouring parameter values must give the same structure. A cliff would mean +/// the parameter is load-bearing in a way users cannot reason about. +#[test] +fn parameters_do_not_change_the_structure() { + let (pts, truth) = separated_tissue(4); + + for radius in [2.5f64, 3.0, 3.5, 4.0, 5.0] { + let g = radius_graph(&pts, radius, SpatialWeight::Uniform, None).unwrap(); + let agreement = adjusted_rand_index(&components(&g), &truth); + assert!( + agreement > 0.99, + "radius {radius} broke the structure ({agreement:.4})" + ); + } + for k in [4usize, 6, 8, 12, 16] { + let g = knn_graph(&pts, k, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + let agreement = adjusted_rand_index(&components(&g), &truth); + assert!( + agreement > 0.99, + "k {k} broke the structure ({agreement:.4})" + ); + } + for factor in [1.5f64, 2.0, 2.5, 3.0] { + let g = delaunay_graph( + &pts, + HullPruning::Adaptive { factor }, + SpatialWeight::Uniform, + ) + .unwrap(); + let agreement = adjusted_rand_index(&components(&g), &truth); + assert!( + agreement > 0.99, + "factor {factor} broke the structure ({agreement:.4})" + ); + } +} + +/// The documented limitation, asserted so it cannot quietly stop being true. +/// +/// On uniform tissue there is nothing spatial to find, so the result is an arbitrary tiling: +/// contiguous, plausible-looking, and not reproducible under resampling. Anyone clustering a +/// bare spatial graph on continuous tissue is reading tea leaves, and this is the evidence. +#[test] +fn homogeneous_tissue_gives_an_arbitrary_unstable_tiling() { + let pts = homogeneous_tissue(4); + let graph = build("delaunay", &pts); + let reference = cluster(&graph, 0.1); + + assert_eq!( + components(&graph).iter().max(), + Some(&0), + "one tissue region" + ); + assert!( + reference.iter().max().unwrap() > &3, + "yet the clustering carves it into many blobs" + ); + assert_eq!( + disconnected_community_count(&graph, &reference), + 0, + "each of them contiguous, which is what makes the tiling look like a result" + ); + + let mut rng = ChaCha8Rng::seed_from_u64(31); + let keep: Vec = (0..pts.len()) + .filter(|_| rng.random::() > 0.1) + .collect(); + let sub: Vec<[f64; 2]> = keep.iter().map(|&i| pts[i]).collect(); + let restricted: Vec = keep.iter().map(|&i| reference[i]).collect(); + let agreement = adjusted_rand_index(&cluster(&build("delaunay", &sub), 0.1), &restricted); + + assert!( + agreement < 0.8, + "a tiling of featureless tissue reproduced at ARI {agreement:.3}; if that now holds \ + up, the limitation documented in this file no longer applies and the module docs \ + need revisiting" + ); +} + +/// Whatever the builder or resolution, a domain must be one connected region of tissue. +#[test] +fn domains_are_always_spatially_contiguous() { + let (pts, _) = separated_tissue(6); + for name in BUILDERS { + let graph = build(name, &pts); + for resolution in [0.01, 0.05, 0.1, 0.3, 1.0] { + let labels = cluster(&graph, resolution); + assert_eq!( + disconnected_community_count(&graph, &labels), + 0, + "{name} at resolution {resolution} split a domain across space" + ); + } + } +} + +/// The lattice path: tissue detection masking a band must split the capture area. +#[test] +fn lattice_masking_splits_the_capture_area_cleanly() { + let (mut rows, mut cols, mut truth) = (Vec::new(), Vec::new(), Vec::new()); + for r in 0..78u32 { + if (30..48).contains(&r) { + continue; + } + for i in 0..64u32 { + rows.push(r); + cols.push(2 * i + (r % 2)); + truth.push(usize::from(r >= 48)); + } + } + let g = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); + let agreement = adjusted_rand_index(&components(&g), &truth); + assert!( + (agreement - 1.0).abs() < 1e-9, + "the masked-apart regions were not separated ({agreement:.4})" + ); + assert_eq!(disconnected_community_count(&g, &cluster(&g, 0.05)), 0); +} From 93f143f78ce0ca5c7f578f21dab01dd0bfd62348 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 1 Aug 2026 21:10:08 +0200 Subject: [PATCH 06/20] docs: pre-register the DLPFC benchmark target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Written before implementing spatial domain detection so the target cannot drift to meet the result. Target: median ARI 0.46-0.52 across the 12 sections, against a non-spatial baseline of 0.38-0.43. The range is a real disagreement, not imprecision — BANKSY self-reports 0.518 from its own deposited artifacts, while the Genome Biology benchmark puts it near 0.46 running the same method on the same sections. Take the lower one. Records the independent medians for ten methods, the protocol rule that decides comparability (median ARI over resolutions yielding the correct cluster count, not best-of-sweep), and two traps: BANKSY's published ARIs are on smoothed labels via a SmoothLabels call visible only in its deposited code and never mentioned in the paper, and configuration can swamp method differences — DeepST scores 0.538 and 0.229 on the same section in two independent benchmarks. Also pins BANKSY's Visium parameters, including that lambda is 0.2 for Visium domain segmentation rather than the 0.8 used elsewhere, and that use_agf=TRUE means mean + gradient, so a mean-only implementation is not a faithful replication. --- docs/spatial-benchmark.md | 116 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 docs/spatial-benchmark.md diff --git a/docs/spatial-benchmark.md b/docs/spatial-benchmark.md new file mode 100644 index 0000000..4c707ad --- /dev/null +++ b/docs/spatial-benchmark.md @@ -0,0 +1,116 @@ +# DLPFC benchmark target + +Written **before** implementing spatial domain detection, so the target cannot drift to meet +the result. Everything here is sourced; anything unverified is marked. + +Dataset: 10x Visium human dorsolateral prefrontal cortex, Maynard et al. 2021. 12 sections, +3431–4788 spots each, manual annotation of cortical layers L1–L6 + white matter. + +## The target + +**Median ARI 0.46–0.52 across the 12 sections**, against a **non-spatial baseline of +0.38–0.43**. + +The range on the target is not imprecision — it is a real disagreement: + +| Source | BANKSY median ARI | +|---|---| +| Self-reported (authors' deposited artifacts) | 0.518 | +| Independent (Hu et al., Genome Biology 2024) | ~0.46 | + +Take the lower number as the bar. Method papers grade their own homework. + +## Where everyone else lands + +Independent, all 12 sections, computed from the BenchmarkST repo's per-section ARI files +(Hu et al., Genome Biology 2024;25(1):212): + +| Method | median | mean | +|---|---|---| +| GraphST | 0.559 | 0.557 | +| STAGATE | 0.523 | 0.505 | +| ADEPT | 0.519 | 0.531 | +| **BANKSY** | **~0.46** | — | +| CCST | 0.434 | 0.459 | +| SEDR | 0.426 | 0.414 | +| ConGI | 0.419 | 0.419 | +| SpaGCN | 0.412 | 0.392 | +| conST | 0.394 | 0.395 | +| DeepST | 0.262 | 0.300 | + +GraphST is the ceiling set by heavy deep-learning methods. It is **not** our bar — a +feature-augmentation approach that then runs ordinary Leiden should be measured against +BANKSY, which is the same shape. + +## The bar that justifies existing + +Non-spatial clustering on expression alone, section 151673: + +| | ARI | +|---|---| +| Seurat (expression only) | 0.430 | +| BANKSY's own λ=0 arm, same pipeline | 0.382 | +| Leiden / Louvain | **unconfirmed**, stated as below Seurat's 0.430 | + +If we do not clear ~0.43 by a clear margin, the spatial machinery is decoration. BANKSY's +claimed gain over its own baseline is ~0.58 vs ~0.38 on that section, i.e. **+0.184**. + +## Protocol — the part that decides comparability + +**Cluster count.** Sweep Leiden resolution 0.1–1.5. Keep only runs whose cluster count +exactly matches the section's annotated layer count. Report the **median ARI over all +qualifying resolutions** — not the best. Reporting best-of-sweep makes the number +incomparable with every published figure. Fallback when nothing matches: widen to k±1; if +still nothing, report nothing. + +**Exclude unannotated spots.** 28 of 3639 on 151673. Small effect (~0.004) but it shifts +everything. + +**5 vs 7 clusters.** Most sections have 7 layers; some have 5 (L3, L4, L5, L6, WM). Reported +as the 151669–151672 group — *unverified*, check each section's annotation set directly. + +**ARI implementation** is not a source of difference: `sklearn.adjusted_rand_score` and +`mclust::adjustedRandIndex` agree, and an independent from-scratch implementation reproduced +published values to three decimals. + +## Two traps + +**BANKSY's published ARIs are on smoothed labels, and the paper never says so.** The +deposited script calls `SmoothLabels(k = 6)` before scoring — visible only in code. Comparing +our raw labels against 0.518 would understate us. Either replicate the smoothing or state +plainly that the comparison is unsmoothed-to-smoothed. + +**Configuration can swamp method differences.** DeepST scores 0.538 in one independent +benchmark and 0.229 in another, on the same section — a swing of 0.31, far larger than the +gaps between most methods. GraphST, by contrast, reproduces to three decimals across groups. +Budget for this before concluding anything from a single number. + +## Matching BANKSY, if we replicate it + +Parameters for Visium domain segmentation, confirmed from the benchmark run script and a +quoted reply from BANKSY's author: + +- `lambda = 0.2` — for Visium v1/v2 domain segmentation. **Not 0.8**; that is for Visium HD + and other technologies. +- `k_geom = c(18, 18)` for DLPFC +- `use_agf = TRUE` — the feature matrix is neighbourhood **mean + azimuthal Gabor gradient**. + A mean-only implementation is not a faithful replication and should not be compared + against BANKSY's number. +- 2000 HVGs, 20 PCs, SNN graph at k_expr = 50 + +## Getting the data + +`zenodo.org/records/15114362` → `Benchmark_ST_analysis-master.zip`, **18.8 MB**. Contains a +complete section 151673 (`filtered_feature_bc_matrix.h5`, `metadata.tsv`, `spatial/`) **plus +predicted labels from 14 competing methods**, so a single-section comparison costs one small +download and no reimplementation of anyone else's method. + +Full source is spatialLIBD, `http://spatial.libd.org/spatialLIBD/`; annotations ship with the +data as `layer_guess` / `layer_guess_reordered` columns in `metadata.tsv`. + +## Unconfirmed + +Self-reported numbers from the BayesSpace / SpaGCN / STAGATE / GraphST papers (so no +self-vs-independent gap for any of them); exact Leiden/Louvain DLPFC ARI; BANKSY's λ=0 arm +across all 12 sections and whether it too was smoothed; SDMBench (Yuan et al., Nature Methods +2024) numbers, which is the most likely source of a clean independent Leiden figure. From fc8329c2707d944376fbf54449740c00df03a696 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 1 Aug 2026 21:21:46 +0200 Subject: [PATCH 07/20] docs: which DLPFC numbers actually reproduce MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fills in the self-reported vs independent comparison, which is the part that decides what to trust: GraphST 151673 self 0.635 indep 0.633/0.638 gap ~0.00 BayesSpace 151673 self 0.55 indep 0.550 gap 0.00 STAGATE 151676 self 0.60 indep 0.493 gap 0.11 BANKSY 12-slice self 0.518 indep 0.469 gap 0.05 Two of four survive independent replication. BayesSpace also disagrees between two independent benchmarks (0.550 vs ~0.40 on the same section), so independence alone does not settle it either. Verifies from code what no paper states: sample 2 (151669-151672) is annotated L3-L6 + WM, so 5 clusters, the other eight sections 7. Also that the benchmark drops unannotated spots before clustering rather than before scoring — GraphST's own tutorial does the opposite, letting them train the model and vote in spatial refinement, and hardcodes 7 clusters for every section including the 5-cluster ones. Expands the independent table to 15 methods and marks which are machine-readable from the benchmark's raw per-run files versus recovered from the figure. BANKSY is figure-derived and new in the published version, so 0.469 carries +/-0.01 and is not an exact published value. --- docs/spatial-benchmark.md | 98 ++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/docs/spatial-benchmark.md b/docs/spatial-benchmark.md index 4c707ad..bb3f28d 100644 --- a/docs/spatial-benchmark.md +++ b/docs/spatial-benchmark.md @@ -22,26 +22,68 @@ Take the lower number as the bar. Method papers grade their own homework. ## Where everyone else lands -Independent, all 12 sections, computed from the BenchmarkST repo's per-section ARI files -(Hu et al., Genome Biology 2024;25(1):212): +Independent, all 12 sections, mean across slices of each slice's 20-run mean. Computed from +the BenchmarkST repo's raw per-run ARI files (Hu et al., Genome Biology 2024;25(1):212). -| Method | median | mean | +| Method | mean over 12 slices | source | |---|---|---| -| GraphST | 0.559 | 0.557 | -| STAGATE | 0.523 | 0.505 | -| ADEPT | 0.519 | 0.531 | -| **BANKSY** | **~0.46** | — | -| CCST | 0.434 | 0.459 | -| SEDR | 0.426 | 0.414 | -| ConGI | 0.419 | 0.419 | -| SpaGCN | 0.412 | 0.392 | -| conST | 0.394 | 0.395 | -| DeepST | 0.262 | 0.300 | +| GraphST | 0.557 | raw data | +| ADEPT | 0.530 | raw data | +| STAGATE | 0.503 | raw data | +| BASS | ~0.49 | figure | +| SpatialPCA | ~0.48 | figure | +| **BANKSY** | **0.469** | figure, ±0.01 | +| CCST | 0.451 | raw data | +| PRECAST | ~0.46 | figure | +| ConGI | 0.422 | raw data | +| SEDR | 0.411 | raw data | +| SpaGCN | 0.392 | raw data | +| conST | 0.385 | raw data | +| BayesSpace | ~0.37 | figure | +| DeepST | 0.322 | raw data | +| DR.SC | ~0.33 | figure | + +Nine methods have machine-readable per-run results in `ari_results/*.txt`; the rest exist +only inside the Fig. 2a raster and were recovered by colourmap inversion cross-checked +against the bioRxiv preprint's vector figures. **BANKSY is one of the figure-derived ones** +— it is new in the published version, so there is no vector cross-check. Treat 0.469 as +±0.01, not an exact published value. + +This benchmark contains **no non-spatial baseline** — no Seurat, Leiden, Louvain or k-means +anywhere in it. It cannot answer the question that matters most to us. GraphST is the ceiling set by heavy deep-learning methods. It is **not** our bar — a feature-augmentation approach that then runs ordinary Leiden should be measured against BANKSY, which is the same shape. +## Self-reported vs independent + +Which published numbers survive someone else running them. Self-reported values are the +stored outputs in each tool's own tutorial notebooks. + +| Method | section | self-reported | independent | gap | +|---|---|---|---|---| +| GraphST | 151673 | 0.635 | 0.633 (Kang), 0.638 (Hu) | **~0.00** | +| BayesSpace | 151673 | 0.55 | 0.550 (Kang) | **0.00** | +| STAGATE | 151676 | 0.60 | 0.493 (Hu) | **0.11** | +| BANKSY | 12-slice | 0.518 | 0.469 (Hu) | **0.05** | + +GraphST and BayesSpace reproduce essentially exactly. STAGATE and BANKSY do not. That is the +single most useful fact here: a published number is not evidence unless someone independent +has reproduced it, and two of the four checked did not survive. + +BayesSpace also disagrees *between* independent benchmarks — 0.550 (Kang) vs ~0.40 (Hu) on +the same section — so "independent" is not automatically decisive either. + +Two protocol details found in the tools' own tutorials, both of which change results: + +* **GraphST's own tutorial hardcodes `n_clusters = 7` for every section.** Run as-published + on 151669–151672, it asks for 7 clusters against 5-layer truth. The 5/7 split exists only + in third-party benchmark repos. +* **GraphST filters unannotated spots *after* clustering and spatial refinement**, so those + spots still train the model and still vote in the refinement step. Hu's benchmark drops + them before the graph is built. Same nominal rule, different graph. + ## The bar that justifies existing Non-spatial clustering on expression alone, section 151673: @@ -63,11 +105,23 @@ qualifying resolutions** — not the best. Reporting best-of-sweep makes the num incomparable with every published figure. Fallback when nothing matches: widen to k±1; if still nothing, report nothing. -**Exclude unannotated spots.** 28 of 3639 on 151673. Small effect (~0.004) but it shifts -everything. +**Exclude unannotated spots — before clustering, not just before scoring.** 28 of 3639 on +151673. The benchmark drops them in `load_DLPFC` (`ad.obs.dropna()`) so they never enter the +graph at all. Dropping them only at scoring time gives a different graph and a different +answer. + +**5 vs 7 clusters — verified from code, and not stated in the paper.** Hard-coded +byte-identically across every run script in the benchmark: + +```python +[[7,'151507'],[7,'151508'],[7,'151509'],[7,'151510'], + [5,'151669'],[5,'151670'],[5,'151671'],[5,'151672'], + [7,'151673'],[7,'151674'],[7,'151675'],[7,'151676']] +``` -**5 vs 7 clusters.** Most sections have 7 layers; some have 5 (L3, L4, L5, L6, WM). Reported -as the 151669–151672 group — *unverified*, check each section's annotation set directly. +So **sample 2 (151669–151672) is 5 clusters**, annotated L3–L6 + WM only — no L1 or L2. The +other eight sections are 7. Getting this wrong makes every affected section incomparable, +and no paper states it. **ARI implementation** is not a source of difference: `sklearn.adjusted_rand_score` and `mclust::adjustedRandIndex` agree, and an independent from-scratch implementation reproduced @@ -80,10 +134,12 @@ deposited script calls `SmoothLabels(k = 6)` before scoring — visible only in our raw labels against 0.518 would understate us. Either replicate the smoothing or state plainly that the comparison is unsmoothed-to-smoothed. -**Configuration can swamp method differences.** DeepST scores 0.538 in one independent -benchmark and 0.229 in another, on the same section — a swing of 0.31, far larger than the -gaps between most methods. GraphST, by contrast, reproduces to three decimals across groups. -Budget for this before concluding anything from a single number. +**Configuration can swamp method differences.** On section 151673, across two independent +benchmarks: DeepST scores 0.538 and 0.229 — a swing of 0.31, far larger than the gaps +between most methods on the list. BayesSpace scores 0.550 and ~0.40. GraphST, by contrast, +reproduces to three decimals (0.633 vs 0.638). So a method's number says as much about who +ran it as about the method, unless it is one of the reproducible ones. Budget for that before +concluding anything from a single figure — including ours. ## Matching BANKSY, if we replicate it From 1bcbcf875d17844d55d3a3be6263e3534fb57660 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 2 Aug 2026 12:11:37 +0200 Subject: [PATCH 08/20] feat(spatial): BANKSY feature augmentation, checked against the reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Augments each cell's expression with a summary of its neighbourhood so ordinary Leiden finds spatial domains. Verified differentially against banksy-py's own functions via committed fixtures, not against a reading of the paper — which matters, because four details are wrong if you transcribe from the paper, and three of them I got wrong first time. - The lambda budget is not split evenly across harmonics. Each successive harmonic gets half the weight of the one before, so at max_m=1 the mean takes 2/3 of lambda and the gradient 1/3, not half each. - Every block is z-scored per column before scaling, so lambda mixes standardised blocks. Without it the block with larger variance dominates regardless of lambda. - The gradient term subtracts its own neighbourhood mean before the phase sum. This lives in the reference's matrix builder, not its weight construction, so a matmul against the weights silently omits it — my first fixtures did exactly that and would have passed against a wrong reference. - The neighbourhood size differs per harmonic, and the two references disagree about how: R uses k_geom[m] (18 for both on DLPFC), Python multiplies internally as k*(m+1) (so 18 and 36). R produced the published numbers, so k is explicit per harmonic here rather than derived. Also documents, from source: the scaled_gaussian kernel has no factor of 2 in its exponent; R and Python disagree on the ranked kernel, which additionally crashes for m>0 in Python; and the reference stores azimuths as float32, which is why the fixtures agree to 1e-6 rather than tighter. 5 differential tests over 5 decay kernels, harmonics 0-2, lambda 0 to 1. --- src/spatial/banksy.rs | 460 +++++++++++++++++++++++++++ src/spatial/mod.rs | 1 + tests/banksy_reference.rs | 291 +++++++++++++++++ tests/fixtures/banksy_reference.json | 1 + tools/gen_banksy_fixtures.py | 118 +++++++ 5 files changed, 871 insertions(+) create mode 100644 src/spatial/banksy.rs create mode 100644 tests/banksy_reference.rs create mode 100644 tests/fixtures/banksy_reference.json create mode 100644 tools/gen_banksy_fixtures.py diff --git a/src/spatial/banksy.rs b/src/spatial/banksy.rs new file mode 100644 index 0000000..71bae20 --- /dev/null +++ b/src/spatial/banksy.rs @@ -0,0 +1,460 @@ +//! BANKSY-style feature augmentation. +//! +//! Turns spatial domain detection into ordinary clustering: augment each cell's expression +//! with a summary of its neighbourhood, then run Leiden on the result exactly as you would +//! without coordinates. Nothing here knows about clustering. +//! +//! Every formula below was read from the reference implementation (`banksy-py`, +//! `banksy/main.py` and `banksy/embed_banksy.py`), not from the paper, and is pinned by +//! differential fixtures in `tests/fixtures/banksy_reference.json`. Two details are easy to +//! get wrong from the paper alone: +//! +//! * The λ budget is **not** split evenly across harmonics. Each successive harmonic gets +//! half the weight of the previous one, so at `max_m = 1` the mean takes ⅔ of λ and the +//! gradient ⅓ — see [`scale_factors`]. +//! * Every block is **z-scored per column before scaling**, so λ mixes standardised blocks +//! rather than raw ones. Without that, a block with larger variance dominates regardless +//! of λ. +//! +//! The weight matrix is row-normalised, hence asymmetric, so it is a +//! [`NeighbourhoodOperator`] rather than a [`CSRNetwork`](crate::network::CSRNetwork). + +use rayon::prelude::*; + +use crate::error::{ClusteringError, Result}; +use crate::spatial::grid::{Grid, distance_sq}; + +/// How neighbour weights fall off with distance, before row normalisation. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum Decay { + /// Every neighbour counts the same. + Uniform, + /// `1 / r`. + Reciprocal, + /// `1 / r²`. + ReciprocalSquared, + /// `exp(-(r / median_r)²)`, where `median_r` is the median neighbour distance **for that + /// cell**. Scale-free per cell, which is why it is the reference default. + #[default] + ScaledGaussian, + /// `exp(-((rank + 1) · 1.5 / k)²)`, assigned in order of distance. Ignores the distances + /// themselves, so it is unaffected by local density. + Ranked, +} + +/// Row-normalised directed neighbour weights. +/// +/// Not a graph: row normalisation makes it asymmetric, so `w[i][j] != w[j][i]`. It is an +/// operator applied to a feature matrix. +pub struct NeighbourhoodOperator { + node_ptrs: Vec, + neighbours: Vec, + /// Row-normalised magnitudes, summing to 1 per cell. + weights: Vec, + /// Azimuth from each cell to each of its neighbours, `atan2(dy, dx)`. + theta: Vec, + n_cells: usize, + /// Harmonic order this operator was built for. + m: usize, +} + +impl NeighbourhoodOperator { + /// Builds the operator for harmonic `m` over `k` nearest neighbours. + /// + /// `k` is explicit per harmonic rather than derived from `m`, because the two references + /// disagree: R takes a `k_geom` vector and uses `k_geom[m]` (both 18 for DLPFC), while + /// Python silently multiplies, `num_neighbours * (m + 1)`, so the same nominal settings + /// give the gradient twice the neighbourhood. R produced the published DLPFC numbers, so + /// its convention is the one exposed here — pass `k * (m + 1)` yourself to reproduce + /// Python. + /// + /// Excludes the cell itself — its own expression enters the augmented matrix as its own + /// block, not through the neighbourhood. + /// + /// # Errors + /// + /// If `k` is zero or a coordinate is not finite. + pub fn for_harmonic(coords: &[[f64; 2]], k: usize, m: usize, decay: Decay) -> Result { + Self::knn(coords, k, decay, m) + } + + fn knn(coords: &[[f64; 2]], k: usize, decay: Decay, m: usize) -> Result { + if k == 0 { + return Err(ClusteringError::InvalidConfig( + "k must be at least 1".into(), + )); + } + for (i, p) in coords.iter().enumerate() { + if !p[0].is_finite() || !p[1].is_finite() { + return Err(ClusteringError::InvalidConfig(format!( + "cell {i} has a non-finite coordinate" + ))); + } + } + let n = coords.len(); + if n == 0 { + return Ok(Self { + node_ptrs: vec![0], + neighbours: Vec::new(), + weights: Vec::new(), + theta: Vec::new(), + n_cells: 0, + m, + }); + } + + let want = k.min(n.saturating_sub(1)); + let grid = Grid::new(coords, typical_spacing(coords, want.max(1))); + + // Nearest `want` neighbours per cell, with distances, sorted by (distance, id) so + // ties never depend on visit order. + let found: Vec> = coords + .par_iter() + .enumerate() + .map(|(i, p)| { + let centre = grid.cell_of(p); + let mut cand: Vec<(u32, f64)> = Vec::with_capacity(want * 2); + for ring in 0..=grid.max_ring(¢re) { + grid.for_each_in_ring(¢re, ring, |j| { + if j as usize != i { + cand.push((j, distance_sq(p, &coords[j as usize]))); + } + }); + if cand.len() >= want { + cand.sort_unstable_by(|a, b| { + a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0)) + }); + cand.truncate(want); + let safe = ring as f64 * grid.cell_size(); + if cand[cand.len() - 1].1 <= safe * safe { + break; + } + } + } + cand.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0))); + cand.truncate(want); + cand + }) + .collect(); + + let mut node_ptrs = Vec::with_capacity(n + 1); + node_ptrs.push(0usize); + let mut total = 0; + for row in &found { + total += row.len(); + node_ptrs.push(total); + } + + let mut neighbours = Vec::with_capacity(total); + let mut weights = Vec::with_capacity(total); + let mut theta = Vec::with_capacity(total); + + for (i, row) in found.iter().enumerate() { + let distances: Vec = row.iter().map(|&(_, d2)| d2.sqrt()).collect(); + let mut w = decay_weights(&distances, decay); + + // Row-normalise. Done *before* any phase factor, matching the reference: the + // magnitudes sum to 1, the complex weights do not. + let sum: f64 = w.iter().sum(); + if sum > 0.0 { + for x in &mut w { + *x /= sum; + } + } + + for (slot, &(j, _)) in row.iter().enumerate() { + neighbours.push(j); + weights.push(w[slot]); + let (dx, dy) = ( + coords[j as usize][0] - coords[i][0], + coords[j as usize][1] - coords[i][1], + ); + theta.push(dy.atan2(dx)); + } + } + + Ok(Self { + node_ptrs, + neighbours, + weights, + theta, + n_cells: n, + m, + }) + } + + /// Number of cells. + pub fn n_cells(&self) -> usize { + self.n_cells + } + + /// Harmonic order this operator computes. + pub fn harmonic(&self) -> usize { + self.m + } + + /// Applies this operator's harmonic to a feature matrix. + /// + /// `m = 0` is the plain weighted neighbourhood mean. For `m >= 1` the weights carry a + /// phase `exp(i·m·θ)`, and the result is the **magnitude** of the complex sum — large + /// where a gene varies systematically with direction, near zero where the neighbourhood + /// looks the same all round. That is the "gradient" term. + /// + /// `features` is row-major, `n_cells × n_features`. + /// + /// # Errors + /// + /// If `features` does not match the cell count. + pub fn apply(&self, features: &[f64], n_features: usize) -> Result> { + let m = self.m; + if n_features == 0 { + return Ok(Vec::new()); + } + if features.len() != self.n_cells * n_features { + return Err(ClusteringError::InvalidConfig(format!( + "features has {} entries, expected {} cells x {n_features}", + features.len(), + self.n_cells + ))); + } + + let mut out = vec![0.0f64; self.n_cells * n_features]; + out.par_chunks_mut(n_features) + .enumerate() + .for_each(|(i, row)| { + let span = self.node_ptrs[i]..self.node_ptrs[i + 1]; + #[allow(clippy::reversed_empty_ranges)] + if m == 0 { + for e in span { + let (w, j) = (self.weights[e], self.neighbours[e] as usize); + let src = &features[j * n_features..(j + 1) * n_features]; + for (o, &x) in row.iter_mut().zip(src) { + *o += w * x; + } + } + } else { + // Centre on this cell's neighbourhood before taking the phase sum. + // Without it the result measures the neighbourhood's overall level as + // well as its directional variation, because the phase sum + // `sum_j w_ij e^{i m phi}` is generally non-zero, so subtracting a + // constant is not a no-op. Easy to miss: it lives in the reference's + // matrix builder, not in its weight construction. + let mut centre = vec![0.0f64; n_features]; + for e in span.clone() { + let (w, j) = (self.weights[e], self.neighbours[e] as usize); + let src = &features[j * n_features..(j + 1) * n_features]; + for (c, &x) in centre.iter_mut().zip(src) { + *c += w * x; + } + } + + let mut im = vec![0.0f64; n_features]; + for e in span { + let (w, j) = (self.weights[e], self.neighbours[e] as usize); + let angle = m as f64 * self.theta[e]; + let (re_w, im_w) = (w * angle.cos(), w * angle.sin()); + let src = &features[j * n_features..(j + 1) * n_features]; + for (((o, i_acc), &x), &c) in row + .iter_mut() + .zip(im.iter_mut()) + .zip(src) + .zip(centre.iter()) + { + *o += re_w * (x - c); + *i_acc += im_w * (x - c); + } + } + for (o, &i_acc) in row.iter_mut().zip(im.iter()) { + *o = (*o * *o + i_acc * i_acc).sqrt(); + } + } + }); + Ok(out) + } +} + +/// Unnormalised weights for one cell's neighbour distances. +fn decay_weights(distances: &[f64], decay: Decay) -> Vec { + match decay { + Decay::Uniform => vec![1.0; distances.len()], + Decay::Reciprocal => distances.iter().map(|&r| 1.0 / r).collect(), + Decay::ReciprocalSquared => distances.iter().map(|&r| 1.0 / (r * r)).collect(), + Decay::ScaledGaussian => { + let mut sorted = distances.to_vec(); + sorted.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); + // numpy's median: mean of the middle two on even counts. + let n = sorted.len(); + let median = if n == 0 { + 0.0 + } else if n % 2 == 1 { + sorted[n / 2] + } else { + 0.5 * (sorted[n / 2 - 1] + sorted[n / 2]) + }; + distances + .iter() + .map(|&r| (-(r / median).powi(2)).exp()) + .collect() + } + Decay::Ranked => { + let k = distances.len(); + // Rank by distance, then assign a fixed decreasing profile in that order. + let mut order: Vec = (0..k).collect(); + order.sort_unstable_by(|&a, &b| { + distances[a] + .partial_cmp(&distances[b]) + .unwrap() + .then(a.cmp(&b)) + }); + let mut w = vec![0.0; k]; + for (rank, &idx) in order.iter().enumerate() { + let t = (rank + 1) as f64 * 1.5 / k as f64; + w[idx] = (-t * t).exp(); + } + w + } + } +} + +/// Column z-scores, using the **population** variance `E[x²] − E[x]²`. +/// +/// Not the sample variance — the reference divides by `n`, not `n − 1`, and a column with +/// zero variance becomes zero rather than NaN. +fn zscore_columns(matrix: &mut [f64], n_rows: usize, n_cols: usize) { + if n_rows == 0 || n_cols == 0 { + return; + } + for c in 0..n_cols { + let (mut sum, mut sum_sq) = (0.0f64, 0.0f64); + for r in 0..n_rows { + let x = matrix[r * n_cols + c]; + sum += x; + sum_sq += x * x; + } + let n = n_rows as f64; + let mean = sum / n; + let variance = sum_sq / n - mean * mean; + let sd = variance.max(0.0).sqrt(); + for r in 0..n_rows { + let slot = &mut matrix[r * n_cols + c]; + *slot = if sd > 0.0 { (*slot - mean) / sd } else { 0.0 }; + } + } +} + +/// Block scale factors for `max_m` harmonics at neighbourhood contribution `lambda`. +/// +/// Returns `max_m + 2` factors: own expression first, then one per harmonic. +/// +/// **Each harmonic gets half the weight of the one before it**, not an equal share. With +/// `max_m = 1` that makes the mean ⅔ of λ and the gradient ⅓ — assuming an even split would +/// over-weight the gradient by a factor of two. +pub fn scale_factors(max_m: usize, lambda: f64) -> Vec { + let n_blocks = max_m + 1; + let mut squared = vec![0.0f64; n_blocks + 1]; + squared[0] = 1.0 - lambda; + + let denom: f64 = (0..n_blocks).map(|k| 1.0 / 2f64.powi(k as i32 + 1)).sum(); + for k in 0..n_blocks { + squared[k + 1] = 1.0 / 2f64.powi(k as i32 + 1) / denom * lambda; + } + squared.iter().map(|&s| s.max(0.0).sqrt()).collect() +} + +/// Assembles the augmented matrix from the own-expression block and the harmonic blocks. +/// +/// Each block is z-scored per column and then scaled, so λ mixes standardised blocks. The +/// result is `n_cells × (n_features · (max_m + 2))`, row-major, ready to PCA and cluster. +/// +/// # Errors +/// +/// If `lambda` is outside `[0, 1]` or a block has the wrong length. +pub fn banksy_matrix( + own: &[f64], + harmonics: &[Vec], + n_cells: usize, + n_features: usize, + lambda: f64, +) -> Result> { + if !(0.0..=1.0).contains(&lambda) || !lambda.is_finite() { + return Err(ClusteringError::InvalidConfig(format!( + "lambda must be in [0, 1], got {lambda}" + ))); + } + let expected = n_cells * n_features; + if own.len() != expected { + return Err(ClusteringError::InvalidConfig(format!( + "own block has {} entries, expected {expected}", + own.len() + ))); + } + for (m, h) in harmonics.iter().enumerate() { + if h.len() != expected { + return Err(ClusteringError::InvalidConfig(format!( + "harmonic {m} has {} entries, expected {expected}", + h.len() + ))); + } + } + + let factors = scale_factors(harmonics.len().saturating_sub(1), lambda); + let n_blocks = harmonics.len() + 1; + let width = n_features * n_blocks; + let mut out = vec![0.0f64; n_cells * width]; + + for (b, block) in std::iter::once(own) + .chain(harmonics.iter().map(|h| h.as_slice())) + .enumerate() + { + let mut scaled = block.to_vec(); + zscore_columns(&mut scaled, n_cells, n_features); + let f = factors[b]; + for r in 0..n_cells { + let dst = r * width + b * n_features; + for c in 0..n_features { + out[dst + c] = f * scaled[r * n_features + c]; + } + } + } + Ok(out) +} + +/// One-call BANKSY augmentation. +/// +/// Builds the neighbourhood operator, applies harmonics `0..=max_m`, and assembles the +/// augmented matrix. `lambda = 0.2` and `k = 18` are the reference's Visium settings for +/// domain segmentation; `max_m = 1` includes the gradient term. +/// +/// # Errors +/// +/// If any argument is out of range or the feature matrix does not match the cell count. +pub fn banksy_augment( + coords: &[[f64; 2]], + features: &[f64], + n_features: usize, + k: usize, + max_m: usize, + lambda: f64, + decay: Decay, +) -> Result> { + let harmonics: Vec> = (0..=max_m) + .map(|m| { + NeighbourhoodOperator::for_harmonic(coords, k, m, decay)?.apply(features, n_features) + }) + .collect::>()?; + banksy_matrix(features, &harmonics, coords.len(), n_features, lambda) +} + +/// A cell size that puts roughly `k` points in each grid cell. +fn typical_spacing(points: &[[f64; 2]], k: usize) -> f64 { + let (mut min, mut max) = ([f64::INFINITY; 2], [f64::NEG_INFINITY; 2]); + for p in points { + for d in 0..2 { + min[d] = min[d].min(p[d]); + max[d] = max[d].max(p[d]); + } + } + let area = (max[0] - min[0]).max(f64::MIN_POSITIVE) * (max[1] - min[1]).max(f64::MIN_POSITIVE); + let cells = (points.len() as f64 / (k.max(1) as f64)).max(1.0); + (area / cells).sqrt().max(f64::MIN_POSITIVE) +} diff --git a/src/spatial/mod.rs b/src/spatial/mod.rs index 4440286..1af9f54 100644 --- a/src/spatial/mod.rs +++ b/src/spatial/mod.rs @@ -23,6 +23,7 @@ //! //! Neither affects `array_row` / `array_col`, which is what [`lattice_graph`] wants. +pub mod banksy; pub mod delaunay; pub(crate) mod grid; pub mod lattice; diff --git a/tests/banksy_reference.rs b/tests/banksy_reference.rs new file mode 100644 index 0000000..fd26e7c --- /dev/null +++ b/tests/banksy_reference.rs @@ -0,0 +1,291 @@ +//! Differential tests for the BANKSY feature augmentation. +//! +//! Fixtures come from `banksy-py` itself via `tools/gen_banksy_fixtures.py` — the reference's +//! own `generate_spatial_weights_fixed_nbrs` and `concatenate_all`, not a reimplementation of +//! them. So this checks against what BANKSY computes rather than against a reading of the +//! paper. Fixtures are committed; the suite needs no Python. +//! +//! Three things this pins that a formula transcribed from the paper would get wrong: the λ +//! budget halves with each harmonic rather than splitting evenly, every block is z-scored +//! before scaling, and the gradient term is centred on its own neighbourhood first. +//! +//! Tolerance is 1e-6, not tighter, because the reference stores azimuths as `float32` +//! (`theta_data = np.zeros_like(..., dtype=np.float32)`). We carry f64 throughout, so the +//! residual is the reference's precision, not ours. + +use serde_json::Value; +use single_clustering::spatial::banksy::{Decay, NeighbourhoodOperator, banksy_matrix}; + +fn fixtures() -> Value { + let raw = include_str!("fixtures/banksy_reference.json"); + serde_json::from_str(raw).expect("fixture JSON should parse") +} + +fn coords(v: &Value) -> Vec<[f64; 2]> { + v.as_array() + .unwrap() + .iter() + .map(|p| { + let a = p.as_array().unwrap(); + [a[0].as_f64().unwrap(), a[1].as_f64().unwrap()] + }) + .collect() +} + +/// Row-major flatten of a nested JSON matrix. +fn matrix(v: &Value) -> Vec { + v.as_array() + .unwrap() + .iter() + .flat_map(|row| { + row.as_array() + .unwrap() + .iter() + .map(|x| x.as_f64().unwrap()) + .collect::>() + }) + .collect() +} + +fn decay_of(name: &str) -> Decay { + match name { + "uniform" => Decay::Uniform, + "reciprocal" => Decay::Reciprocal, + "reciprocal_squared" => Decay::ReciprocalSquared, + "scaled_gaussian" => Decay::ScaledGaussian, + "ranked" => Decay::Ranked, + other => panic!("unknown decay {other}"), + } +} + +/// Largest absolute difference, and where. +fn max_abs_diff(a: &[f64], b: &[f64]) -> (f64, usize) { + assert_eq!(a.len(), b.len(), "matrix shapes differ"); + let mut worst = (0.0f64, 0usize); + for (i, (&x, &y)) in a.iter().zip(b).enumerate() { + let d = (x - y).abs(); + if d > worst.0 { + worst = (d, i); + } + } + worst +} + +/// Points on a regular grid have many exactly-equidistant neighbours, and nothing specifies +/// which of them a k-nearest search returns. Our tie-break is (distance, index); sklearn's is +/// unspecified, so that case is compared structurally elsewhere rather than value-for-value. +fn has_distance_ties(name: &str) -> bool { + name.starts_with("grid") +} + +/// Every harmonic must match the reference elementwise. +#[test] +fn harmonics_match_the_reference() { + let f = fixtures(); + let mut checked = 0; + + for c in f["cases"].as_array().unwrap() { + let name = c["name"].as_str().unwrap(); + if has_distance_ties(name) { + continue; + } + let pts = coords(&c["locations"]); + let features = matrix(&c["features"]); + let n_features = c["n_genes"].as_u64().unwrap() as usize; + let ks: Vec = c["k_per_harmonic"] + .as_array() + .unwrap() + .iter() + .map(|v| v.as_u64().unwrap() as usize) + .collect(); + let decay = decay_of(c["decay"].as_str().unwrap()); + + for (m, expected) in c["harmonics"].as_array().unwrap().iter().enumerate() { + let op = NeighbourhoodOperator::for_harmonic(&pts, ks[m], m, decay).unwrap(); + let got = op.apply(&features, n_features).unwrap(); + let want = matrix(expected); + + let (diff, at) = max_abs_diff(&got, &want); + assert!( + diff < 1e-6, + "{name} harmonic {m}: max |ours - reference| = {diff:e} at entry {at} \ + (ours {}, reference {})", + got[at], + want[at] + ); + checked += 1; + } + } + assert!(checked >= 12, "only {checked} harmonics compared"); +} + +/// The assembled matrix — scaling, z-scoring and block layout together. +#[test] +fn augmented_matrix_matches_the_reference() { + let f = fixtures(); + let mut checked = 0; + + for c in f["cases"].as_array().unwrap() { + let name = c["name"].as_str().unwrap(); + if has_distance_ties(name) { + continue; + } + let pts = coords(&c["locations"]); + let features = matrix(&c["features"]); + let n_cells = c["n_cells"].as_u64().unwrap() as usize; + let n_features = c["n_genes"].as_u64().unwrap() as usize; + let ks: Vec = c["k_per_harmonic"] + .as_array() + .unwrap() + .iter() + .map(|v| v.as_u64().unwrap() as usize) + .collect(); + let max_m = c["max_m"].as_u64().unwrap() as usize; + let decay = decay_of(c["decay"].as_str().unwrap()); + + let harmonics: Vec> = (0..=max_m) + .map(|m| { + NeighbourhoodOperator::for_harmonic(&pts, ks[m], m, decay) + .unwrap() + .apply(&features, n_features) + .unwrap() + }) + .collect(); + + for (lambda_str, expected) in c["banksy"].as_object().unwrap() { + let lambda: f64 = lambda_str.parse().unwrap(); + let got = banksy_matrix(&features, &harmonics, n_cells, n_features, lambda).unwrap(); + let want = matrix(expected); + + let (diff, at) = max_abs_diff(&got, &want); + assert!( + diff < 1e-6, + "{name} at lambda {lambda}: max |ours - reference| = {diff:e} at entry {at} \ + (ours {}, reference {})", + got[at], + want[at] + ); + checked += 1; + } + } + assert!(checked >= 10, "only {checked} matrices compared"); +} + +/// On a regular grid the neighbour *set* is ambiguous, but the neighbourhood mean over a +/// symmetric lattice should still land close — a large gap would mean something worse than a +/// tie-break difference. +#[test] +fn grid_case_agrees_up_to_tie_breaking() { + let f = fixtures(); + for c in f["cases"].as_array().unwrap() { + let name = c["name"].as_str().unwrap(); + if !has_distance_ties(name) { + continue; + } + let pts = coords(&c["locations"]); + let features = matrix(&c["features"]); + let n_features = c["n_genes"].as_u64().unwrap() as usize; + let k = c["k_per_harmonic"][0].as_u64().unwrap() as usize; + let decay = decay_of(c["decay"].as_str().unwrap()); + + let op = NeighbourhoodOperator::for_harmonic(&pts, k, 0, decay).unwrap(); + let got = op.apply(&features, n_features).unwrap(); + let want = matrix(&c["harmonics"][0]); + + // Features are standard normal and weights sum to 1, so a mean is O(1/sqrt(k)). + let (diff, _) = max_abs_diff(&got, &want); + assert!( + diff < 1.0, + "{name}: means differ by {diff:e}, too much for tie-breaking alone" + ); + } +} + +/// λ = 0 must leave only the own-expression block carrying signal, λ = 1 only the +/// neighbourhood blocks. Checked against the reference, so the convention is theirs. +#[test] +fn lambda_endpoints_behave() { + let f = fixtures(); + let c = f["cases"] + .as_array() + .unwrap() + .iter() + .find(|c| c["name"] == "uniform_small") + .expect("uniform_small carries lambda 0 and 1"); + + let pts = coords(&c["locations"]); + let features = matrix(&c["features"]); + let n_cells = c["n_cells"].as_u64().unwrap() as usize; + let n_features = c["n_genes"].as_u64().unwrap() as usize; + let ks: Vec = c["k_per_harmonic"] + .as_array() + .unwrap() + .iter() + .map(|v| v.as_u64().unwrap() as usize) + .collect(); + let max_m = c["max_m"].as_u64().unwrap() as usize; + let decay = decay_of(c["decay"].as_str().unwrap()); + + let harmonics: Vec> = (0..=max_m) + .map(|m| { + NeighbourhoodOperator::for_harmonic(&pts, ks[m], m, decay) + .unwrap() + .apply(&features, n_features) + .unwrap() + }) + .collect(); + + let width = n_features * (max_m + 2); + + let at_zero = banksy_matrix(&features, &harmonics, n_cells, n_features, 0.0).unwrap(); + let nbr_energy: f64 = (0..n_cells) + .flat_map(|r| (n_features..width).map(move |c| (r, c))) + .map(|(r, c)| at_zero[r * width + c].abs()) + .sum(); + assert!( + nbr_energy < 1e-9, + "lambda 0 left {nbr_energy:e} in the neighbour blocks" + ); + + let at_one = banksy_matrix(&features, &harmonics, n_cells, n_features, 1.0).unwrap(); + let own_energy: f64 = (0..n_cells) + .flat_map(|r| (0..n_features).map(move |c| (r, c))) + .map(|(r, c)| at_one[r * width + c].abs()) + .sum(); + assert!( + own_energy < 1e-9, + "lambda 1 left {own_energy:e} in the own block" + ); +} + +/// The halving rule, stated explicitly so it cannot drift. +#[test] +fn scale_factors_halve_with_each_harmonic() { + use single_clustering::spatial::banksy::scale_factors; + + // max_m = 0: one neighbour block takes all of lambda. + let f = scale_factors(0, 0.2); + assert!((f[0] - 0.8f64.sqrt()).abs() < 1e-12); + assert!((f[1] - 0.2f64.sqrt()).abs() < 1e-12); + + // max_m = 1: two-thirds to the mean, one-third to the gradient — not half each. + let f = scale_factors(1, 0.2); + assert!((f[0] - 0.8f64.sqrt()).abs() < 1e-12); + assert!((f[1] - (2.0 / 3.0 * 0.2f64).sqrt()).abs() < 1e-12); + assert!((f[2] - (1.0 / 3.0 * 0.2f64).sqrt()).abs() < 1e-12); + assert!( + (f[1] / f[2] - 2f64.sqrt()).abs() < 1e-12, + "the mean block should carry twice the gradient's variance" + ); + + // Squared factors always partition 1. + for max_m in 0..4 { + for lambda in [0.0, 0.2, 0.5, 0.8, 1.0] { + let total: f64 = scale_factors(max_m, lambda).iter().map(|f| f * f).sum(); + assert!( + (total - 1.0).abs() < 1e-12, + "max_m {max_m}, lambda {lambda}" + ); + } + } +} diff --git a/tests/fixtures/banksy_reference.json b/tests/fixtures/banksy_reference.json new file mode 100644 index 0000000..7c84002 --- /dev/null +++ b/tests/fixtures/banksy_reference.json @@ -0,0 +1 @@ +{"cases": [{"name": "uniform_small", "n_cells": 60, "n_genes": 4, "k": 6, "max_m": 1, "decay": "scaled_gaussian", "k_per_harmonic": [6, 12], "locations": [[25.591081235012837, 47.52318481629676], [7.207980635981687, 47.43247235686219], [15.591572600524273, 21.166322448628783], [41.38512969102209, 20.459956818458064], [27.479684383652973, 1.3779556621534184], [37.67565543374033, 26.907165660963912], [16.48658582495461, 39.421435171420214], [15.159741464582249, 22.674894474032577], [6.702084862358237, 20.15564932235646], [10.17276203380748, 13.115667022092476], [37.51823363150263, 14.020437899301996], [24.25954872158175, 49.036859990061934], [48.08285968318934, 36.23949703867668], [27.06134277737171, 13.844560202268541], [8.032600438756344, 48.49627066080663], [25.803429277393935, 5.793280623538516], [31.174487776875022, 38.834155717114896], [30.650165052652024, 45.86488523954513], [1.979643833210143, 26.42946316300108], [22.966794144270185, 3.11747895749378], [32.066408456968745, 42.631641924032834], [29.6470509052142, 13.00487238686116], [41.99407605157044, 25.47479407607547], [25.54444422332665, 37.65151038510889], [7.396101789247828, 40.98133595596385], [34.16434530016286, 39.354847077740054], [9.580812951006761, 40.1182080567265], [9.566196302860014, 4.0776308681756355], [42.76134871435351, 43.06417480888342], [43.82685482082903, 23.59548596793951], [13.702419430685914, 0.35459143015831307], [32.28604477874739, 35.99546917543465], [41.77846082501371, 14.093891368227107], [10.76090835814868, 31.966569003329393], [40.25274165725048, 48.183543642248544], [7.526241521058874, 24.110619409966827], [44.735793109808675, 21.135845347271864], [29.475103104202404, 1.22453387466816], [33.67299435764694, 45.954430981691125], [41.34126647783605, 44.27601333549734], [33.017769026026166, 12.27761336215888], [38.42584994481272, 10.583737130375525], [41.56374173322306, 3.1358961285384126], [41.27439066967779, 8.225363323705064], [18.757349824832094, 15.836908327848215], [34.566851763887065, 8.928593908718597], [19.81280811084932, 0.2912297553990473], [13.124735637505076, 21.059440711447763], [5.296061835366222, 31.65799730182789], [19.021213494326616, 36.264696903811945], [32.69330055341972, 21.56133743887031], [43.36602528210996, 31.606755875008353], [40.51371760531495, 17.08973619700565], [27.18346448342278, 9.81484425573767], [49.80705950593139, 12.160773215316356], [12.843373361355138, 3.659503619548299], [12.89015594983683, 38.15642662720266], [34.89467853415407, 6.4336606158584715], [18.811925071404712, 21.046069730873146], [33.24921231809804, 22.796448152187445]], "features": [[0.6658894397639671, 1.5239375129901318, -1.5246860380991518, -2.466229231351318], [0.6168787551543194, 2.547897815483126, -1.0009248488718936, -1.2506957588019882], [0.5889689337804737, -0.8407215900583078, -0.5060254839367364, -0.34811746668377785], [0.5320020862917986, -0.40530236139311865, 0.2778828400801602, -0.17653325889357535], [-0.8446711036516033, -0.31982625774322104, -0.9503996651679186, 0.006514985869748843], [-1.1238662275656366, -1.092894369295243, 1.4569618153052555, -0.05318422030534141], [-0.05390202547204295, 0.511536419917619, -0.4208570025488712, -0.22853536747815809], [0.4251487353319089, 0.2824158422444015, -1.1592967269324297, 0.8333425966696618], [-0.590434943289043, -1.0560789503141859, -0.9004750699990517, -0.3905453443553229], [1.6273002546230673, -1.1755359049207805, 0.16007589253434076, -2.1378243580905774], [-0.0015669331451969059, 0.8995664174760071, -0.23666332206145513, -0.6293549238833419], [0.23151106405853766, 0.7001517511506504, 0.6636575710174066, 1.9724738539297917], [0.20916747233627678, -0.5924100997529326, -0.12597918998664273, -0.07249854561981205], [0.10873738347811868, -0.03002781322943489, 0.1739659388962034, -1.6708500606151127], [0.8296289560400428, -0.5747392689210323, -1.1731586964470246, 0.6377511596414357], [1.317326007386082, 0.4930281494994427, 0.16115931384552032, -0.9322203053719521], [2.8715673378134987, 0.8802586206615082, -1.1392946703429758, -0.7796379162397445], [0.08697924857190435, -1.5547311319959862, 0.16863040701051427, -0.4590715557127591], [1.2262706003162174, 0.9621546636282469, -2.7112854374347726, 0.04170258602731257], [-1.6174674995236882, 1.109637999248523, 0.16810586912782435, 0.5484054521869972], [-1.065124728803299, 1.8284302379955002, 2.020073367150445, -1.0647710426262125], [0.37281512186631627, -0.6733024283901868, -0.0235699368607321, -1.2656369792245639], [1.8671455145806186, -0.969179511082668, -0.2960838149974946, 0.5014829311105223], [-0.6475606784161285, -0.23931242973230216, -0.5636398464269645, -0.13346075483629405], [-1.1705426351003028, -0.43798807560230063, -0.20689292471224427, -0.33372600380413486], [0.05668995489379499, -0.2931022193567212, 0.7532114084393808, -0.3231959257858299], [-0.13664959629588416, -0.6647813359958524, -0.526514840115237, -1.2644927908197123], [0.5187849208779641, -1.142518017652492, -0.7458563981883249, 0.35924465201120453], [0.40257336594453236, -0.400114751005071, -2.0192658104888017, 0.42051328729557524], [0.2595634588920596, -1.4123812154717754, 0.770322082794496, -0.7010998004334262], [-1.1261881161533005, 0.09573071096425678, -0.17847043139921506, 0.20262400099114752], [-1.6057480583244386, 1.8122301162723733, -0.602658614543728, -1.539659308496411], [0.6188421885671495, -0.3548041301011767, 0.32485848577290377, -0.33960843062503854], [-0.059740360479920165, 0.24577284373863384, -0.7466528839828983, 0.6787395958595579], [-0.46990009907954344, -0.8696871441704723, 0.07703242182250279, 0.44504127849104197], [-0.2290793416186396, -0.8625197870795628, 0.6197855663086329, -1.7603287921227768], [-1.0308641360355328, 0.03952289053338441, -1.3610593983050674, 0.027994264249169242], [-0.05486311801846381, 0.8987397888581683, -0.9147903518132915, -0.6259065236416427], [0.3331816847010001, -2.4575635902058073, 3.1000422989145844, -0.698650730461769], [-0.7298350527255578, 0.8611275109037129, -0.03983184143568413, -1.779428618703591], [0.6269273800926122, 0.8553778339992086, -0.4499462734759413, -0.2816003582920249], [0.48598459725939197, -0.9087802499144495, 0.4383885642069085, 0.199298510444498], [-0.674932615775918, -1.3921018738118445, -0.22560583076108617, -0.8754222582601685], [1.0014102256801642, 0.14408536849992318, 0.7820845225598966, 0.13462193534445818], [0.26290111708503067, -0.7829989172303806, 0.6680474265721447, 1.7846982743070243], [-0.3096875555175417, -0.592774527714149, -0.15783670219035234, -0.48128028360112374], [-0.7014792986535402, 0.13819364396816675, -0.29091753305009044, 1.4388735938426587], [0.00020164295512421895, 0.3239119776314283, 0.9520218679998016, -0.30075585250454295], [1.4367365400889385, -0.6326942125201124, -0.8083277018861249, -0.36626701885025204], [-0.11471739196713679, -1.4013182000990516, -0.03509478412884679, -1.6674865904394212], [1.3921384005454986, -0.08099695140769417, -0.6419577246959741, -0.9083381182835725], [-0.38443047420819676, -0.22307946843042645, -1.0445109656113605, -0.9197950938228345], [-0.18717500506153661, -0.520783747795641, 0.9392131036783211, 1.137870374245525], [0.016021203599889625, 0.47359957205452774, -1.33518837362512, 0.6374177094326149], [-0.03058346951326358, 0.48466831595083715, 1.6003561315936594, -2.280857756344364], [0.26094817905342854, -1.0991190631678631, 0.592196691404488, -1.313313437428466], [-0.49539956700399346, 0.20273375576037383, 0.6135093864353722, 0.07479408933657207], [-0.7928309389878114, -0.553532217715408, 0.8845028912493791, -0.005499615686538553], [-1.6838143968410575, 0.8436627082696916, 0.41624847971347423, 0.8734155452519468], [-0.3366274663766816, 0.8281565184266096, -1.0610649200016748, 0.5699998108654594]], "harmonics": [[[0.1551671145199322, -0.16069060170177024, 0.8137081639982424, 0.25884614881315926], [-0.045144158186205055, -0.3926227643450717, -0.5809753669156655, -0.07846914467431425], [-0.2584455598074232, 0.32874626898082854, 0.024841344102704818, 0.5180415210319085], [-0.010445426732502384, -0.6362709993710539, 0.07837577611204, 0.2007803409258275], [-0.17720895510856385, 0.6858872502121178, -0.31897137639873496, -0.1463200039533478], [0.6668159764456859, -0.3986468978669548, -0.35402716527913647, -0.1366806229979087], [-0.371023235623551, -0.4780138581537659, -0.0665706867531999, -0.6274974576707005], [-0.19891035167310964, -0.13524521967328698, 0.2484600781902708, -0.018806128556303123], [0.4504863051190528, -0.2833962009897536, -0.17439050028206027, -0.8321865669340547], [0.12276565058371637, -0.7454573254179102, -0.014358143900577804, -0.012621170826229695], [0.3479525824897236, -0.3399027224870263, 0.33374969729380344, 0.13427980260869535], [0.3184123098721195, 0.1418308319539579, 0.04579625083171031, -1.2554291061815277], [0.012428863763940357, -0.3684714229918384, -0.588386272867151, -0.4893855926941531], [0.35540855981022723, -0.0025102410715428123, -0.37071699572180067, -0.24753495681467994], [-0.09657097039049771, 0.8319606883355058, -0.4769550652014146, -0.74203922143589], [-0.6795050084926751, 0.5019844889484986, -0.6432909150278437, 0.22177910561539127], [-0.7400815173669617, 0.6553307425304907, 0.5653974096248101, -0.8444829735149224], [0.24220932392552397, 0.16908404034710894, 1.1644438981667717, -0.8191304565912461], [0.22023971228893904, -0.5728551337792757, -0.3106060633812428, -0.5813477766875443], [-0.03505637343106485, 0.24806083068047433, -0.45340280942729055, 0.09397779473659171], [0.7082355780994476, -0.8186610881655539, 0.693187574281516, -0.6107981437943005], [0.228447833667563, 0.33359963779834556, -0.3963140349630853, -0.5724396279191619], [-0.25833304247167654, -0.8031084359739543, 0.3077886878844345, -0.3353619776860233], [0.23999382762313484, 0.5494300435679202, -0.08483323743387103, -1.038084292971181], [0.15966307336593957, 0.16490021353881504, -0.4882088268491992, -0.6301642447487469], [0.23434613261923332, 0.9122558779148154, 0.28613754168783456, -1.0477494535589968], [-0.3582704526965558, 0.2491088990403451, -0.2506732449980974, -0.13488261397415], [-0.12326423476793566, -0.4888579364185165, 0.1822135792919722, -0.47349361580127625], [-0.36208456206584977, -0.15277503679745946, 0.5868608465112822, -0.692521182086821], [0.2554663363779756, -0.4908852024430315, -0.31145440108164674, 0.14680868539570643], [-0.016453064194404246, -0.5688562648901866, -0.02816960698417632, -0.06084874972611491], [0.7180524910111004, 0.26905071198847363, 0.22304263803981483, -0.5822790504205692], [0.16139310251476222, -0.14223204249818847, 0.3586782996585884, 0.23126189324009797], [0.19413355230260515, -0.4489185978155396, -0.1207683271944463, -0.7405727190577677], [-0.14825789596556416, -0.3054963984884494, 0.364299358766752, -0.7393920128005894], [0.2822760704216784, -0.07758392974968303, -0.9294598705566761, -0.03693350296288109], [0.5388586719639775, -0.8638895224759893, 0.46235212286552463, -0.06406774764569027], [-0.4210942340431889, 0.08291434511644338, -0.29112061814508916, -0.07906828228422037], [-0.07782020666652269, 0.052091216666863345, 0.5671831713747312, -0.6415071827736525], [-0.027918742804293524, -0.6032744040439512, 0.060831389921239314, 0.01779680658067143], [0.011780692955695315, -0.3368005800216523, 0.0767469215359953, -0.6966133494730443], [0.2337041253128463, 0.10951953822256573, 0.1893782577285274, -0.28704896642000377], [0.24235646468901811, -0.2877707598584806, 0.4943574055463826, -0.06624138837034921], [-0.041083382078535555, -0.6247198019242739, 0.19308651617901798, -0.30732367329108623], [-0.06363879446073159, 0.0035310791556864628, 0.0076651992782393145, -0.19263571771150576], [0.09388022166811709, -0.10680716984975888, 0.28554154544190835, -0.1857450154348171], [-0.6237805356009098, 0.275002021136435, -0.09367839681237454, -0.15855367889764338], [-0.016964599447049325, -0.3070864784433458, -0.3992324170084969, 0.14031326468050173], [0.029277615891230166, 0.0336503710096666, -0.7437600361937026, -0.2927641288466816], [-0.17542156378174859, 0.16849386861766322, -0.2913052055365653, -0.1484164225918229], [-0.21707160245967067, 0.0023737254624814088, 0.01567101172022285, 0.06813014830852443], [0.30173459969285954, -0.8689584312629424, 0.22713673244355945, -0.02555848794149856], [0.24939240455574707, -0.15591525860950672, 0.034963465274056436, -0.2968977346567061], [0.4201676150713835, 0.049499229423912966, 0.026904007611630625, -1.037396475038074], [0.26697170823294375, -0.2973086508111939, 0.24247080216463882, 0.135565924918905], [-0.23238582208147585, -0.2941418022573118, -0.2908426602178277, 0.20437790925315363], [-0.20640018758691941, -0.2893065205601027, -0.4193595795431892, -0.6092551611351132], [0.14391617512479174, -0.26755510613969125, -0.047401015574925716, -0.2954985929937046], [0.3741984794845752, -0.31259985991190054, -0.21229880214224917, 0.3936159401471841], [0.48620348757587145, -0.3920949586806099, 0.18080791537939087, -0.21111102566378592]], [[0.04293453195357449, 0.3351335026576189, 0.3425031667985802, 0.7206766944724476], [0.2629929100108611, 0.07339073672056624, 0.1648468631461491, 0.26154521540857756], [0.343648343411197, 0.25084326683552677, 0.3427053406898025, 0.5034716132218032], [0.16045371302259218, 0.2947641790347152, 0.17691390453059488, 0.15664060826734627], [0.2724765642731457, 0.14173833470701522, 0.1348824449713638, 0.3760057207384725], [0.22730527110534798, 0.42433950091765466, 0.18299789665850208, 0.19642036645107183], [0.16922839356977948, 0.29445858796075586, 0.12452225906424574, 0.1928020347663888], [0.25040434413135243, 0.14016327859736064, 0.13167146909248123, 0.42880297900886943], [0.23841855245601862, 0.16535287597051246, 0.4108876832122192, 0.16617447017635026], [0.0590949450149996, 0.21655563914901227, 0.18408538360540866, 0.26705026618586003], [0.020683265391210567, 0.16258687937886931, 0.2315743219348093, 0.23763704436624342], [0.0720585594755721, 0.20159204335637726, 0.2709586523647256, 0.09918437039336339], [0.060746744501425295, 0.24390636610092922, 0.18985960030564258, 0.06378057669072816], [0.12358631644504388, 0.04626724828184501, 0.10659840086930736, 0.4463034725487998], [0.08475727622412542, 0.29236386842845746, 0.13292270485202853, 0.14681845142405475], [0.42934386553877896, 0.1868748596332418, 0.11075768431147644, 0.30827719056138564], [0.29438790695412903, 0.3509056935084629, 0.5697351008394638, 0.12022227246228438], [0.1640007808371733, 0.6539930473018708, 0.7105134378894951, 0.11669776753830528], [0.0964607131111133, 0.11398872616178223, 0.11541793798749614, 0.16278908868569544], [0.35433773099779386, 0.12731960076333626, 0.19094067458542216, 0.3900509048689214], [0.20478480169878502, 0.7631996254963044, 0.6336681459766266, 0.08041514730808194], [0.06128769965876673, 0.026876294756361968, 0.06484805306409654, 0.1934254154396012], [0.19723605360537502, 0.12003504208430077, 0.15727135100214973, 0.17559956730612025], [0.18558183146727686, 0.3852184164679323, 0.17162935996126216, 0.10587713800146391], [0.28048674115899697, 0.4518967002679805, 0.2687360640900018, 0.07006027834291707], [0.29105526367230244, 0.5141691111214896, 0.6041585957397645, 0.12018722430759614], [0.0506337164400208, 0.21377219616310678, 0.24661755927536885, 0.09899145387617798], [0.40973038949193663, 0.24198899084398406, 0.03806786888740725, 0.280299556405881], [0.15063735633568637, 0.13491007190347812, 0.2782802271610076, 0.1581150271625859], [0.33428128158026776, 0.2297246142997384, 0.19793608179132377, 0.08885601379702865], [0.4110279268232083, 0.5467503408199017, 0.1214550805030016, 0.37726400171105934], [0.34777917665669056, 0.1283757949986054, 0.22702849721618598, 0.12809104817427935], [0.15744861569602084, 0.06925800551643849, 0.12660201430204945, 0.23241695584048674], [0.34164541537506776, 0.024271145162135663, 0.25612750145711694, 0.026700701904843128], [0.09739330741914795, 0.203573381696378, 0.6341524497876038, 0.054436970034681356], [0.34306364860433186, 0.246579438731151, 0.5983403298542372, 0.19622579172603147], [0.09227404000862537, 0.2969560188580714, 0.14359291482766023, 0.18191221901736812], [0.24412231470545281, 0.2605514850212548, 0.2055175943091779, 0.22784108980180232], [0.14784680502683722, 0.3011289065747435, 0.22420444586967817, 0.1570494148511546], [0.12169936601019571, 0.2835642451201978, 0.8545128155097022, 0.3255609701417488], [0.1562622173767597, 0.1118220289045203, 0.180214377574193, 0.32498294555891216], [0.22396373564531677, 0.22497087936991203, 0.23757520935828333, 0.09987859597660749], [0.20111623508948526, 0.05729635189765572, 0.24622324356357345, 0.10220442310372611], [0.2657992769864692, 0.26299924853726353, 0.10071228779710514, 0.2360153850002199], [0.27297385358224635, 0.20253999823854282, 0.03462877058676678, 0.38785200447829127], [0.2584814928879197, 0.28514905123096956, 0.3227559969496276, 0.1787244236733833], [0.11424723388417733, 0.43169432238602595, 0.18126020527826783, 0.07143676926890628], [0.06080406645375174, 0.30827756072603013, 0.1759277483991779, 0.5727925588867595], [0.3169321873329791, 0.10257069588513242, 0.4003650439636406, 0.07633624037406672], [0.11760542043938467, 0.26158862895788915, 0.19299866660915146, 0.20128710683849385], [0.20452709518463016, 0.11610561573830741, 0.1199427470279892, 0.40431212745375156], [0.1217599819286925, 0.3552799344535554, 0.24267226491085653, 0.18469043876255387], [0.06095881067369934, 0.2702324039386879, 0.16117609321772458, 0.06607427488680008], [0.0981151044167475, 0.23338862637712546, 0.08858565261649992, 0.26328487606819445], [0.0353983713461176, 0.04402658029125561, 0.11901905935179619, 0.06668859270994475], [0.5566737685924754, 0.48505946533439276, 0.12691627500665448, 0.29665296277921066], [0.06431184851748518, 0.14022377805812158, 0.10175156787441007, 0.09116837868856158], [0.09503497319089274, 0.22601945466247578, 0.2927159584558768, 0.06321641909764882], [0.06331785328538336, 0.11864923729872055, 0.17533349606226709, 0.05943681013677633], [0.3004960064257786, 0.32945023267763707, 0.3250401889246147, 0.36181855075264985]]], "banksy": {"0.0": [[0.7077051121409879, 1.7402533891153225, -1.4533808783493085, -2.2757814074666176, 0.0, -0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0], [0.6514176169107676, 2.830604524924966, -0.9105455004786845, -0.985882799605296, -0.0, -0.0, -0.0, 0.0, 0.0, -0.0, -0.0, 0.0], [0.6193639137240261, -0.7777238532974697, -0.3976230287528498, -0.02808566050439697, -0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.5539389725741879, -0.3140732123765577, 0.41483344957357726, 0.15399589936855665, -0.0, -0.0, 0.0, 0.0, -0.0, 0.0, -0.0, -0.0], [-1.0271343429627608, -0.22305506795011762, -0.8581803047519933, 0.3482428546551691, -0.0, 0.0, -0.0, 0.0, 0.0, -0.0, -0.0, 0.0], [-1.3477826736436669, -1.0462468376278589, 1.6368517934679145, 0.284891310107267, 0.0, -0.0, -0.0, 0.0, 0.0, 0.0, -0.0, -0.0], [-0.11895664516590373, 0.6622109307905368, -0.3093529054070192, 0.09881235322693908, -0.0, -0.0, -0.0, -0.0, -0.0, 0.0, -0.0, -0.0], [0.4312206810344713, 0.4182347908023722, -1.0746849213431988, 1.2256549606955713, -0.0, -0.0, 0.0, 0.0, 0.0, -0.0, -0.0, 0.0], [-0.7351507320882421, -1.007044405850404, -0.8064375696258691, -0.07310923375759294, 0.0, -0.0, -0.0, -0.0, 0.0, -0.0, 0.0, -0.0], [1.811860401679858, -1.1342466282593655, 0.29273624152887795, -1.9272850489537823, 0.0, -0.0, -0.0, 0.0, -0.0, -0.0, -0.0, 0.0], [-0.0588511542268809, 1.075399750255436, -0.11845131092980124, -0.32652894710459685, 0.0, -0.0, 0.0, 0.0, -0.0, -0.0, -0.0, 0.0], [0.20883285713442895, 0.8630555730489754, 0.814657216871454, 2.434477141321723, 0.0, 0.0, 0.0, -0.0, -0.0, -0.0, 0.0, -0.0], [0.18317182377997587, -0.5133125134927183, -0.003736315059721768, 0.26439535347789883, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], [0.06783048152781326, 0.08553312864516639, 0.30713213171808135, -1.4317417259407867, 0.0, 0.0, -0.0, 0.0, -0.0, -0.0, -0.0, 0.0], [0.895755683456083, -0.494495953493905, -1.0890517121903558, 1.018097433050387, -0.0, 0.0, -0.0, -0.0, -0.0, 0.0, -0.0, -0.0], [1.4558630492289115, 0.6425026338739495, 0.2938591185746456, -0.6479233330051399, -0.0, 0.0, -0.0, 0.0, 0.0, -0.0, -0.0, 0.0], [3.240868750941213, 1.0548400878003434, -1.0539544354457135, -0.48600610425700136, -0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0, -0.0], [0.0428418300836148, -1.5380278544733328, 0.3016022919229985, -0.1458278109322585, 0.0, 0.0, 0.0, -0.0, -0.0, 0.0, 0.0, -0.0], [1.3512882849310492, 1.1420460500331515, -2.6831935230581205, 0.3855831973789523, 0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], [-1.9146708830668902, 1.2990918086578256, 0.30105865156625966, 0.9232856436044257, -0.0, 0.0, -0.0, 0.0, 0.0, -0.0, -0.0, 0.0], [-1.2803195917109123, 2.064488603846851, 2.22047058446727, -0.7885833932309381, 0.0, -0.0, 0.0, -0.0, 0.0, 0.0, 0.0, -0.0], [0.37111688852909436, -0.5994496832571884, 0.10240244963200718, -1.0017381091118365, 0.0, 0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], [2.087316438121228, -0.9145106405895629, -0.18003576277470137, 0.8734924491093788, -0.0, -0.0, 0.0, -0.0, 0.0, -0.0, -0.0, -0.0], [-0.8007581515539905, -0.13732093977507706, -0.4573355749980202, 0.19970353661203333, 0.0, 0.0, -0.0, -0.0, -0.0, 0.0, -0.0, -0.0], [-1.4013893124285934, -0.34887818042655183, -0.08759674356817578, -0.012813742163385572, 0.0, 0.0, -0.0, -0.0, 0.0, 0.0, 0.0, -0.0], [0.008055364907453743, -0.1945983147564654, 0.9074724009221163, -0.0016394443894248798, 0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0, -0.0], [-0.21399007583833357, -0.5903761061391292, -0.41885856057965765, -1.0005239203923322, -0.0, 0.0, -0.0, 0.0, -0.0, -0.0, 0.0, -0.0], [0.5387594022189965, -1.0990879499420882, -0.6461880382276735, 0.7225521728124179, -0.0, -0.0, 0.0, -0.0, 0.0, -0.0, -0.0, 0.0], [0.4052934570662046, -0.30854925127672356, -1.965972118697612, 0.7875691625898554, -0.0, -0.0, 0.0, -0.0, -0.0, -0.0, 0.0, -0.0], [0.24105030222756074, -1.3864483520388202, 0.9252062070349438, -0.4026631042241413, 0.0, -0.0, -0.0, 0.0, 0.0, -0.0, -0.0, -0.0], [-1.3504493022338235, 0.21944549747283817, -0.058139167835299134, 0.5563496253092214, -0.0, -0.0, -0.0, 0.0, 0.0, 0.0, -0.0, 0.0], [-1.9012114099773476, 2.0472381097817385, -0.497775317709692, -1.2925248533956948, 0.0, 0.0, 0.0, -0.0, 0.0, -0.0, -0.0, -0.0], [0.6536725690653794, -0.26030081152127776, 0.4635198412055327, -0.01905605003765254, 0.0, -0.0, 0.0, 0.0, -0.0, -0.0, -0.0, 0.0], [-0.12566182091534892, 0.3792159587803093, -0.6470135302193647, 1.0615935012460924, 0.0, -0.0, -0.0, -0.0, 0.0, -0.0, 0.0, -0.0], [-0.5967196017632026, -0.8085674560706059, 0.2066685169041176, 0.8135977520208909, -0.0, -0.0, 0.0, -0.0, -0.0, -0.0, 0.0, -0.0], [-0.32014323183732035, -0.8009353868138195, 0.7691874937536236, -1.5266946777199482, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0, 0.0, -0.0], [-1.2409721929271673, 0.1595933130678617, -1.2837953293066844, 0.3710362140361924, 0.0, -0.0, 0.0, 0.0, -0.0, 0.0, -0.0, -0.0], [-0.12006043493242773, 1.07451952526023, -0.8212741813733379, -0.3228695771476449, -0.0, 0.0, -0.0, 0.0, 0.0, 0.0, -0.0, 0.0], [0.32559891784233463, -2.499397542202634, 3.3397695230305677, -0.40006420257450576, -0.0, 0.0, 0.0, -0.0, -0.0, 0.0, -0.0, -0.0], [-0.8952481283497798, 1.0344685683157258, 0.08554832356003915, -1.5469630127953402, -0.0, -0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0], [0.6629582010260339, 1.028346097817503, -0.3395015412747783, 0.04250089877276911, -0.0, -0.0, 0.0, -0.0, -0.0, -0.0, -0.0, 0.0], [0.5010890845334804, -0.8501952536976175, 0.5811844263141179, 0.5528206845408665, 0.0, 0.0, 0.0, 0.0, 0.0, -0.0, -0.0, -0.0], [-0.832194108954956, -1.3648541523823068, -0.10699113100086706, -0.587650437561894, 0.0, -0.0, 0.0, 0.0, 0.0, -0.0, 0.0, -0.0], [1.0930419991344027, 0.27093534101202255, 0.937397008045137, 0.4841872605613439, -0.0, -0.0, 0.0, -0.0, 0.0, 0.0, -0.0, 0.0], [0.24488351576279835, -0.7162585975383682, 0.8192069409591998, 2.2352136375057623, -0.0, 0.0, 0.0, 0.0, 0.0, -0.0, -0.0, 0.0], [-0.41271966678183203, -0.5137005699832539, -0.036754005241449186, -0.16939524682153212, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.0], [-0.8626822830695079, 0.26466161290026097, -0.17468133661486523, 1.8682317452181616, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0, -0.0], [-0.05681999062237351, 0.4624214240544605, 1.1135230842484953, 0.02217349037503788, -0.0, -0.0, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0], [1.5930029370611867, -0.5562085398365509, -0.7109344044082183, -0.047345584316895194, -0.0, 0.0, -0.0, -0.0, 0.0, -0.0, 0.0, -0.0], [-0.1888015101944337, -1.374668040489866, 0.09045789369627943, -1.4281724819872588, -0.0, 0.0, -0.0, 0.0, -0.0, 0.0, -0.0, -0.0], [1.541783134954323, 0.031259288566992185, -0.5385056118747633, -0.6225800573375632, -0.0, 0.0, 0.0, 0.0, 0.0, -0.0, -0.0, 0.0], [-0.4985599628887105, -0.12003547690121212, -0.9557189242390227, -0.6347379593058248, 0.0, -0.0, 0.0, 0.0, -0.0, 0.0, -0.0, -0.0], [-0.2720171923243123, -0.4370421014265548, 1.1002478539268958, 1.5488134464313614, 0.0, -0.0, 0.0, -0.0, -0.0, 0.0, -0.0, -0.0], [-0.0386516371005145, 0.6218143596970572, -1.2569821408786546, 1.017743582687676, 0.0, 0.0, 0.0, -0.0, -0.0, -0.0, -0.0, 0.0], [-0.09217589077001337, 0.6336007711916665, 1.7854682039006111, -2.0790690890084638, 0.0, -0.0, 0.0, 0.0, -0.0, -0.0, -0.0, -0.0], [0.24264061728026864, -1.0528751239174292, 0.7405938949119218, -1.0523313658618896, -0.0, -0.0, -0.0, 0.0, 0.0, 0.0, -0.0, 0.0], [-0.6260050767693627, 0.3333863320388682, 0.7626827497153875, 0.4206992061229401, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], [-0.9675972635588012, -0.471913894098703, 1.043545220268485, 0.33549321166182516, 0.0, -0.0, -0.0, -0.0, -0.0, -0.0, 0.0, -0.0], [-1.9908685672256665, 1.0158713948292792, 0.5582380504098388, 1.2681795326275793, 0.0, -0.0, -0.0, 0.0, -0.0, -0.0, -0.0, -0.0], [-0.4436594529950591, 0.9993598253218275, -0.9728757359149264, 0.9462011237833362, 0.0, -0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], "0.2": [[0.6329906955085443, 1.5565299504545014, -1.2999433764749624, -2.0355207716102015, 0.11228364826995, -0.02401501331482695, 0.7482886610347734, 0.5020664400262728, -0.33515440366359756, 0.15619588049340857, 0.14588968529542776, 0.9275525117385136], [0.5826456292613571, 2.5317696540602883, -0.8144166542707624, -0.8818003831060979, -0.11933763970307064, -0.22778339995487398, -0.5236000231889762, 0.1931034908228331, 0.14532234781196962, -0.2996374204827288, -0.12010495791035854, 0.08953295982338699], [0.5539759255588949, -0.6956173614784865, -0.35564484868429025, -0.025120578432325062, -0.36597950215299846, 0.4059890032239585, 0.028877583650620483, 0.7394756775163065, 0.32142589347637945, 0.009401770263513584, 0.1461923887230889, 0.5311037532380483], [0.4954580792249103, -0.28091562111428453, 0.3710383170349, 0.13773811969772384, -0.07921526035936266, -0.44184516350292874, 0.07769857908060253, 0.4488812343770761, -0.07856233543790477, 0.08589142726688606, -0.10203766560709897, -0.1019418483286751], [-0.9186968851557263, -0.19950651786491908, -0.767579799350777, 0.31147787827501483, -0.27204506323348365, 0.7197619647621366, -0.28466416184587634, 0.13095569618210104, 0.16602901407156415, -0.1806079180152351, -0.16496897093668111, 0.2984494592629604], [-1.2054934708654612, -0.9357916200720309, 1.4640447517146813, 0.25481453423952877, 0.7039067096591572, -0.23307601635903435, -0.31663346542279774, 0.1397848587667454, 0.0674017480123555, 0.3115509464038944, -0.09292845145562384, -0.02933472673381629], [-0.106398057986513, 0.5922994626764195, -0.2766936502108629, 0.0883804555328626, -0.4961538349165574, -0.30280535991299645, -0.054486079195065186, -0.30977737480815837, -0.05940364654013024, 0.08535923075137576, -0.18048068595750513, -0.03593900641261515], [0.38569550243873285, 0.37408056911580323, -0.9612274154069629, 1.096259123630052, -0.29713853578341554, -0.001659491836946103, 0.23280781668351608, 0.2477516546449031, 0.11783639934265971, -0.1833509280201769, -0.1697765818442948, 0.39481648425614385], [-0.6575388042632181, -0.9007278991369561, -0.7212996901172651, -0.06539088658596008, 0.45376323833808574, -0.13182033756848155, -0.1528129022504795, -0.49726176134155303, 0.09166655160103859, -0.13948244791240177, 0.24827791847533842, -0.08454037827200582], [1.6205772095584947, -1.01450102561515, 0.2618312542145472, -1.7238161525918667, 0.07481761499219454, -0.5377728746412038, -0.006870587252400975, 0.2534167484543928, -0.29986966313790164, -0.050311217237900226, -0.09130021932151794, 0.0995809316920432], [-0.052638072562251906, 0.9618667778229807, -0.10594607330519976, -0.29205636893892467, 0.3352027970047905, -0.18146521040075297, 0.31058811523515445, 0.3879702622428095, -0.38373794939580474, -0.14429951841421143, -0.020197742530919365, 0.04589510074028128], [0.18678578579523403, 0.7719403718790178, 0.7286515661141438, 2.177462551065894, 0.3010451787223623, 0.24177091200708367, 0.04798751659011786, -0.8849295181226666, -0.271564831400134, -0.07637079233335803, 0.03877016744597504, -0.2068125725405211], [0.1638338598138554, -0.4591206695483985, -0.003341861783557624, 0.2364823933246669, -0.05276556257311939, -0.20656478237870773, -0.5303584362702323, -0.1832742190159471, -0.29626311446507525, -0.002679061652031496, -0.08265481423655968, -0.27143256199380505], [0.060669427057093696, 0.07650315599153061, 0.27470732983841967, -1.2805887301705892, 0.3438241943267784, 0.11495733323864991, -0.33185384051945327, 0.03824815832869034, -0.15905882504817756, -0.34687383301450364, -0.20731705577617043, 0.4267588720543586], [0.8011882397758341, -0.4422906266443785, -0.9740774637880687, 0.9106140272074824, -0.17880281267204037, 0.8480975456412088, -0.42873818410695813, -0.4146915658428166, -0.2438383788782267, 0.08171121046852906, -0.16790317795946424, -0.11986952232183691], [1.3021634976023875, 0.574671826025924, 0.2628355859764315, -0.5795202467230903, -0.8528534084496359, 0.5581907167978357, -0.5804290017624479, 0.4681149910236826, 0.508533998386361, -0.10200123302031282, -0.2010895980814749, 0.17482946129070887], [2.8987211333037552, 0.9434776566853658, -0.9426855051376117, -0.434697074639402, -0.9228984379520694, 0.692915967205449, 0.5218404154950281, -0.5085246187191436, 0.21387036801031828, 0.18366364944368738, 0.4861110902077801, -0.16841360825913945], [0.038318897738983275, -1.3756539335562104, 0.26976129076382416, -0.1304323593018068, 0.21293114742551222, 0.2657147335182818, 1.0681438837816453, -0.48530305554160547, -0.07081764679728503, 0.7114998571385256, 0.6968904589375683, -0.17484663272336864], [1.2086289849219722, 1.021477040523701, -2.3999212457380428, 0.3448760961284224, 0.18752753596227698, -0.38612995578121123, -0.27703537242440385, -0.2675067104871428, -0.2182850262351594, -0.22893473850513257, -0.19411206624997576, -0.09071947077432072], [-1.712533699630847, 1.161943037268819, 0.26927504404663205, 0.8258117846996559, -0.10767306553201057, 0.3351012858826867, -0.4072595855983614, 0.3510557568782675, 0.3447651649379472, -0.20571859897680372, -0.0810361834229213, 0.324085120175522], [-1.1451526559961505, 1.8465347427900771, 1.9860492675630015, -0.70533042927673, 0.7518004769582545, -0.602087424469332, 0.6383793010409471, -0.29448168746595943, 0.01823042321347232, 0.9016865652542679, 0.5818343895261622, -0.24107068081005786], [0.33193703613970676, -0.5361640963415163, 0.09159153537586655, -0.8959818030504672, 0.19701864257785348, 0.4102530221614076, -0.35519718962983354, -0.25934731786972914, -0.2950819898063008, -0.3806437915573943, -0.2698274685217334, -0.03480119466095057], [1.8669525784767198, -0.8179631834020563, -0.16102888157810336, 0.7812753976165386, -0.3658493975918679, -0.5884233478318456, 0.28691284169323084, -0.04219674266471803, 0.0017484424152460444, -0.21840488819259693, -0.13144733984906234, -0.06733742871700996], [-0.7162198641647207, -0.1228235824284908, -0.40905337368981054, 0.17862027328464983, 0.210369353972122, 0.5998749058635432, -0.07114070444943207, -0.6858531768478138, -0.023697454456857298, 0.24342034115625286, -0.10994991255992753, -0.19459674686146275], [-1.2534407062128103, -0.3120461309200826, -0.0783489092904234, -0.011460959409394142, 0.11748235608363171, 0.2620389533720906, -0.43900110883325005, -0.3122200105748685, 0.18351848119767636, 0.35954268019850655, 0.0354424128829557, -0.25997067579193145], [0.0072049374066531485, -0.17405402404094283, 0.811667990466718, -0.0014663636400338673, 0.20383888580021076, 0.9186424025901602, 0.26716796965772, -0.6947059522107765, 0.2065938551503441, 0.46799205222785184, 0.5376514243003744, -0.1684775791263672], [-0.19139854243393967, -0.5280484422474895, -0.37463848576553127, -0.8948957996447371, -0.4814077052210793, 0.3360220861561175, -0.22237933625166065, 0.14143173983440005, -0.31834395916374864, -0.05515867118682546, 0.0023256381023427225, -0.2071646891360078], [0.4818810587515309, -0.9830541477285581, -0.5779681518897242, 0.6462703102794967, -0.20966841594927974, -0.3123326299018725, 0.17239398770327824, -0.168718009605067, 0.46570981991460386, -0.006018231273221612, -0.30992390973217304, 0.12376390489181997], [0.3625054883343704, -0.2759748401045671, -1.7584189197108582, 0.7044232738134004, -0.48581798584408675, -0.01706064410827323, 0.5414141050779016, -0.3693356636010806, -0.09999542611996975, -0.1924995535396241, 0.04973234348815824, -0.0992506979321848], [0.2156019447110779, -1.2400771049805444, 0.8275295888539514, -0.36015282923050507, 0.22826032115312314, -0.31411372279730204, -0.2778090182713847, 0.3994460555164486, 0.3009737958142581, -0.027377030721082173, -0.07056235949684571, -0.2256641764090418], [-1.2078785759847952, 0.19627801988220978, -0.05200125257399926, 0.4976142325791826, -0.08616193244527191, -0.38261667391194354, -0.019466020710406994, 0.20924283965887167, 0.46854287052304466, 0.5247332936910855, -0.18507299734907115, 0.30074610870851903], [-1.7004951809230284, 1.8311054318400577, -0.4452237791681705, -1.1560693739202894, 0.7631518401731032, 0.3535423429622733, 0.2096282538703556, -0.26835970791900027, 0.33044517897781733, -0.2038792033281366, -0.02700394641587625, -0.15405129986388053], [0.5846625197828458, -0.232820123663975, 0.41458474954219166, -0.0170442493067314, 0.11948280056320439, -0.007797897129874757, 0.3333218799627747, 0.4768007224084294, -0.0851236825408223, -0.30683470251679157, -0.17736678714805304, 0.036367249902801775], [-0.11239534949725001, 0.3391810647942119, -0.5787064943730456, 0.9495180933033082, 0.15734080548837528, -0.2772431688377099, -0.10391189090137977, -0.4133483273104808, 0.31705268867166086, -0.38518074192857826, 0.016564331723316988, -0.33911178128082264], [-0.5337222372196497, -0.7232047184671798, 0.18484994104266855, 0.7277039519438916, -0.23856875650199913, -0.1512368839301929, 0.3384480331828828, -0.41226686289305353, -0.2162487943610317, -0.07292022898105385, 0.5825595099792822, -0.2884867728685125], [-0.2863448115698893, -0.7163783882003156, 0.6879822093903188, -1.365517232107575, 0.25926059909817123, 0.048999924629526966, -0.8414022248955452, 0.2311479394677279, 0.32014926741066313, 0.0019761788334916055, 0.5289400668845126, -0.029689869936423082], [-1.1099592726288519, 0.1427445987096577, -1.1482614502105897, 0.33186487867963516, 0.5559488075939621, -0.6418237205684058, 0.4278677462215592, 0.20629440799889812, -0.2274262328073985, 0.08970858560673368, -0.151927281596385, -0.0558154011504351], [-0.1073853175668395, 0.9610794806530706, -0.73456995908651, -0.28878332894749864, -0.5540512711784972, 0.19000871855984106, -0.2592655223088831, 0.19255471249433978, 0.10412017950192085, 0.02630893912586617, -0.05921099354085805, 0.028015251875612424], [0.2912245254783318, -2.2355291228643956, 2.9871806730713595, -0.3578283009283365, -0.15712117695802685, 0.16292847628645984, 0.5234689499346339, -0.32260954123792696, -0.10608833219125183, 0.0969758014768024, -0.031232237306014266, -0.1011956831759796], [-0.8007342686878257, 0.9252568157363391, 0.07651674673655774, -1.383645782115303, -0.09941977465869169, -0.41285538081048323, 0.06169888755695733, 0.2812780052366584, -0.1631788036790081, 0.06638638830738776, 0.9124925078627719, 0.20637629673938618], [0.592967841494073, 0.9197807116466339, -0.3036594099025419, 0.038013959504299644, -0.05351504689022257, -0.178739764485479, 0.07621313693003826, -0.3730838722613223, -0.08771407157952672, -0.23270811027133134, -0.09709605570306906, 0.20532127018600693], [0.44818770232000027, -0.7604377525662208, 0.5198271538810341, 0.4944578520005379, 0.20309652838225556, 0.21338321398857166, 0.1789278523597176, 0.0020554176548457995, 0.06010581991841011, -0.03565581037434466, -0.01121295630994804, -0.20554545268765362], [-0.7443370392392593, -1.2207626656398778, -0.09569577676300954, -0.5256105301583562, 0.21310128729179842, -0.13566368897254416, 0.4570551252755665, 0.20430346818156586, 0.010220453392876706, -0.327666300420415, 0.0017352516937936921, -0.20130028829405983], [0.9776464849307163, 0.2423319360039876, 0.8384333727575375, 0.4330702513818272, -0.11464213665163572, -0.43169664058715296, 0.18230961736719958, -0.016515140366287925, 0.1514497859026815, 0.030571796666614977, -0.2161299969120642, 0.042935202939231254], [0.21903047512590335, -0.6406411654257819, 0.732720963049771, 1.999235855078983, -0.14072311350405226, 0.12026504934774189, 0.013213711699317914, 0.08853295463002193, 0.16711479846155, -0.07471989893973548, -0.31507307532113055, 0.3200716259933783], [-0.3691476922300953, -0.45946775782517746, -0.03287378166610558, -0.1515117147833204, 0.041417196939340484, 0.02332529451474946, 0.26662444787357975, 0.09484447307757682, 0.13547209324353032, 0.0691463782474879, 0.11632337500805091, -0.06163385391958551], [-0.7716064911712542, 0.23672054299188752, -0.15623973722854467, 1.6709972720123507, -0.7884188211773395, 0.35877097813583175, -0.07920709218135162, 0.11975029766219626, -0.17944983260817665, 0.3243596004884322, -0.09553019757543203, -0.25745826624997475], [-0.050821344605011094, 0.41360229537521204, 0.9959653243579444, 0.0198325727108088, -0.08675342413947663, -0.15263387873826628, -0.3578586228636285, 0.39349659405047654, -0.29613795737864573, 0.10942540866136705, -0.10351418089492488, 0.6576302722711687], [1.424825142250253, -0.4974880418961711, -0.6358790623200409, -0.04234717798681024, -0.0332832358136755, 0.14672692267259485, -0.6720523238224893, -0.0031793685307045165, 0.26309368182554793, -0.24881959917365032, 0.23252297133884503, -0.2485156152504416], [-0.1688692044197493, -1.2295404740127094, 0.08090799976253221, -1.2773963013272418, -0.2699782904770841, 0.265196226986979, -0.25943385771205163, 0.1290354877070816, -0.17211754841550256, 0.02811515807725112, -0.07795486943170375, -0.02045181675110239], [1.3790127585282392, 0.027959157665630605, -0.4816540617668355, -0.5568525318570031, -0.3181385136756004, 0.11924823437844852, 0.020514652756752048, 0.3273806812900331, 0.017667745301145878, -0.2252481083894352, -0.18733732794035204, 0.3501151004867581], [-0.44592558715157166, -0.10736299442508644, -0.8548209927925705, -0.5677268899629277, 0.2817606289315577, -0.6462771062212249, 0.21336188392251113, 0.24156685096119768, -0.1630464545275504, 0.1912815283261395, -0.0035814259604296677, -0.05074451716154085], [-0.24329957323431853, -0.3909023391276537, 0.9840915973915192, 1.3853008602745012, 0.22123699244716064, -0.01981954535353455, 0.038108503133657295, -0.006965532593132544, -0.2958000879425151, 0.04316856544951074, -0.12560099220426155, -0.2672460402192149], [-0.03457107519936132, 0.5561676710672502, -1.1242790054031555, 0.9102975338215286, 0.4187055306832693, 0.16065123688736938, 0.030758640046722675, -0.6852231720385724, -0.2146728185690936, -0.020996037863180435, -0.23428651560482314, 0.09270823686914521], [-0.08244462305933813, 0.5667097579923427, 1.5969713102344887, -1.8595759251765942, 0.24156406093598462, -0.1440433834022991, 0.22734586618733274, 0.38914828218341285, -0.3516089008712722, -0.3507760271511224, -0.1887203127757409, -0.2661247702336873], [0.21702436573647632, -0.9417201395591546, 0.6624073170977571, -0.9412337875689546, -0.3358464500547373, -0.141261088729566, -0.25901203717441496, 0.4521764164866085, 0.7865468544522753, 0.4172966838883518, -0.17689626253239657, 0.15361259727337034], [-0.5599159623665078, 0.29818980048329013, 0.682164189452026, 0.37628480918843593, -0.30579908402728906, -0.1370129605736373, -0.3762136903079487, -0.29306839704552384, -0.2884790454765134, -0.1832455662967795, -0.21457394217226483, -0.22144358366245487], [-0.8654453024641038, -0.42209261869253467, 0.9333752200461295, 0.30007425090622647, 0.09927411047208554, -0.1179028441798069, -0.037004200825167, -0.005683992909339952, -0.2213979951271608, -0.033829683355245686, 0.07134613999439207, -0.27246227813160034], [-1.78068698023368, 0.9086229980943187, 0.4993032913373415, 1.1342942570516719, 0.3655511063327083, -0.15747776426916757, -0.18738356943439466, 0.6255084333127074, -0.29064934048785873, -0.22081831103413396, -0.10440392100029172, -0.2793609255827897], [-0.3968210783029299, 0.8938546013607688, -0.8701665116663636, 0.8463080132664931, 0.49506325950839825, -0.22731968630912028, 0.17111208540458087, 0.07161055074681283, 0.22720682817028465, 0.14629828616624876, 0.11974336527526319, 0.2725546418161067]], "0.5": [[0.5004230838752786, 1.2305449724263162, -1.0276954747276568, -1.6092204657179108, 0.1775360362631334, -0.037971070057061726, 1.1831482580737864, 0.7938367436076749, -0.5299256417062249, 0.24696737174731795, 0.23067184632936327, 1.4665892932518851], [0.4606218143019844, 2.0015396544317694, -0.6438528979673767, -0.697124413056083, -0.18868937602512165, -0.36015717851724854, -0.8278843280970726, 0.30532342756478736, 0.22977480700450537, -0.4737683604715062, -0.18990261263769515, 0.14156403934912487], [0.43795642341649865, -0.5499338105571726, -0.2811619399870737, -0.01985956099676229, -0.5786644018689862, 0.641924977584576, 0.0456594688290004, 1.1692137076238465, 0.5082189611700081, 0.014865504035172195, 0.2311504624728379, 0.8397487670481298], [0.39169400387071723, -0.22208329826050668, 0.2933315452564842, 0.10889154471842759, -0.12525032408941716, -0.6986185448993782, 0.12285224042670778, 0.7097435497697171, -0.12421795914297044, 0.13580627082302552, -0.16133571522253023, -0.16118421480302128], [-0.7262936590985573, -0.1577237511255543, -0.6068251129708724, 0.24624488402643133, -0.43014101301116975, 1.1380435909031026, -0.4500935598278853, 0.20705913625422784, 0.2625149210691444, -0.2855661921945501, -0.2608388457070167, 0.4718900288582963], [-0.9530262680991725, -0.7398082336816397, 1.1574290029585246, 0.2014485772779681, 1.1129742313988913, -0.3685255398266071, -0.5006414670841052, 0.2210192680539355, 0.10657152099788514, 0.4926052989086757, -0.1469327830160805, -0.0463822755087457], [-0.08411505046401248, 0.4682538397378441, -0.2187455371930639, 0.06987088503176907, -0.7844880940817497, -0.4787773125160572, -0.08615005551435988, -0.48980103599072305, -0.09392541219319625, 0.1349647942471167, -0.28536502064764174, -0.05682455855363052], [0.30491906774735594, 0.2957366567044945, -0.7599169955207074, 0.8666689341027699, -0.46981727684151875, -0.0026238869816032242, 0.3681014789054291, 0.39172976137666426, 0.18631570659798638, -0.289903271824673, -0.268440345992981, 0.6242596740147123], [-0.5198300678538509, -0.7120879283327984, -0.5702374740860506, -0.05169603495734643, 0.7174626758010942, -0.20842625432433187, -0.2416184134860928, -0.7862398795731868, 0.14493754415631818, -0.2205411145094939, 0.39256185755383444, -0.13367007479587414], [1.2811787765912095, -0.8020334823801746, 0.20699578148413264, -1.3627963273946668, 0.1182970362384478, -0.8502935738612046, -0.010863352290252625, 0.40068706117491804, -0.4741355683516019, -0.0795490191636451, -0.1443583219644548, 0.1574512778342508], [-0.041614050234482836, 0.7604224558919385, -0.08375772519889868, -0.23089083275136393, 0.5300021582971026, -0.2869216904740279, 0.4910829291609656, 0.6134348465500521, -0.6067429723665888, -0.22815757172715825, -0.03193543499567953, 0.07256652589108438], [0.1476671294143162, 0.6102724482437722, 0.576049642392365, 1.7214352952722314, 0.4759942216875617, 0.38227337695926783, 0.0758749258399446, -1.3991964229914389, -0.42938169981201807, -0.12075282524256832, 0.061301017197697115, -0.3269993889934212], [0.12952203871712825, -0.3629667591586123, -0.0026419737153786827, 0.1869557473584365, -0.08342967987559609, -0.3266075983468652, -0.8385703174495953, -0.28978198423946816, -0.4684331142024075, -0.004235968406216497, -0.13068873628282002, -0.4291725635176392], [0.04796339345946561, 0.0604810552810985, 0.21717521305813525, -1.0123942833204618, 0.5436337843724814, 0.18176350338655725, -0.5247069931578736, 0.0604756483127003, -0.2514940845512413, -0.5484556865193709, -0.32779704702643286, 0.674765023688077], [0.6333949180581869, -0.3496614419848479, -0.7700758507526209, 0.7199035988185457, -0.2827120700440324, 1.3409599611124134, -0.6778945908312957, -0.6556849372624918, -0.3855423291091448, 0.12919676772497304, -0.26547823436624485, -0.18953035628669987], [1.0294506345886878, 0.45431796934248725, 0.20778977545763366, -0.4581509824569241, -1.3484796404693709, 0.8825770169215853, -0.9177388327936109, 0.7401547892520565, 0.8040628512666461, -0.16127811024488226, -0.31795057185264314, 0.2764296498894406], [2.291640270726108, 0.7458845791510361, -0.7452583283653035, -0.34365821201818186, -1.4592305564700612, 1.0955963417338783, 0.8251021440464563, -0.8040480207105952, 0.3381587434655098, 0.2903977278103846, 0.7686091204620795, -0.2662852955331128], [0.03029374857056586, -1.0875499255518901, 0.21326502584015694, -0.10311583399578973, 0.3366737053288585, 0.42013188289122827, 1.6888837707640931, -0.7673315054753366, -0.11197253120637463, 1.1249800517210764, 1.1018805649413808, -0.27645680030838715], [0.9555051096126845, 0.8075485064057526, -1.8973043353902201, 0.2726484935782482, 0.2965070688199654, -0.6105250665443642, -0.4380313846470597, -0.42296524725931106, -0.3451389310063567, -0.3619776046056352, -0.30691812533571144, -0.1434400778859663], [-1.3538767651570334, 0.9185966272858455, 0.21288061405738024, 0.6528615395648754, -0.17024606486686147, 0.5298416551202588, -0.6439339447135651, 0.5550678887248236, 0.5451215895437685, -0.32526966491274206, -0.1281294562518056, 0.5124235677620189], [-0.9053226653847779, 1.4598138914624563, 1.5701098077020632, -0.5576126648846941, 1.1887009265945103, -0.9519838059338426, 1.0093663011978458, -0.46561643080114506, 0.028824830031689282, 1.4256916408887648, 0.9199609459581449, -0.3811662142236141], [0.2624192684917747, -0.42387493601128595, 0.07240946654490615, -0.7083358099259692, 0.31151382603032235, 0.6486669834987911, -0.5616160688605071, -0.410064114762016, -0.46656559214124926, -0.6018506792618686, -0.42663468790303216, -0.05502552021174754], [1.4759556078776712, -0.6466566754281335, -0.12730450871408394, 0.6176524340804871, -0.5784586884954116, -0.9303790037850665, 0.4536490348509653, -0.06671890833025589, 0.002764530194911706, -0.34532844940151103, -0.20783649314662533, -0.10646982326249065], [-0.5662215190542319, -0.09710056771386649, -0.32338508635894897, 0.14121172496530474, 0.3326231542250478, 0.9484855068539462, -0.11248333020454014, -1.0844290896506772, -0.03746896541588872, 0.38488135343449204, -0.1738460761128628, -0.30768447267072246], [-0.9909318859006118, -0.24669412718763864, -0.06194025138691619, -0.00906068397610592, 0.18575591505360764, 0.41431996417123285, -0.694121699626267, -0.4936631822492209, 0.2901681966597214, 0.5684868927344007, 0.05603937524111739, -0.4110497301778507], [0.005696003150992688, -0.1376017879717709, 0.6416798884316659, -0.0011592622451405716, 0.32229757741981, 1.452501173697135, 0.4224296509805757, -1.09842655653107, 0.32665356643499766, 0.7399604059482446, 0.8501015440113924, -0.26638644235528075], [-0.15131383373190926, -0.4174589481014872, -0.2961777285439123, -0.7074772488487676, -0.7611724158267718, 0.5312975681873324, -0.35161260355584933, 0.2236232156585348, -0.5033459951565386, -0.08721351682933572, 0.003677156708337388, -0.32755613421526225], [0.38096042673706315, -0.7771725425244713, -0.45692394375241996, 0.5109215411567349, -0.3315148738996494, -0.4938412490401649, 0.27257882803070954, -0.2667665963210887, 0.7363518798184955, -0.009515659154517703, -0.49003272804904613, 0.19568791578730316], [0.28658575186205215, -0.21817726790780326, -1.3901522167547657, 0.5568954955206974, -0.7681456817713768, -0.02697524686583786, 0.8560508646939518, -0.5839709590545805, -0.15810665106909902, -0.30436851887537014, 0.0786337394002116, -0.15692913241353398], [0.17044830331217495, -0.9803670314915636, 0.6542195829902937, -0.2847258115305159, 0.3609112571426905, -0.4966574041771156, -0.4392546261364545, 0.6315796689010218, 0.4758813553997539, -0.043286886325510796, -0.11156888654282264, -0.3568063918793046], [-0.9549118592581781, 0.15517139936389926, -0.04111059982888283, 0.3933985927667453, -0.1362339770643102, -0.6049700801598342, -0.030778481212447525, 0.33084197870172205, 0.7408313261430949, 0.8296761860929465, -0.2926261025086847, 0.4755213504757604], [-1.3443594804642198, 1.447615950130197, -0.3519803026598114, -0.913953088688244, 1.2066490077478969, 0.5589995265365922, 0.3314513720771656, -0.4243139546207829, 0.5224797036959469, -0.3223613250287466, -0.04269698824365473, -0.24357649203972476], [0.46221630626176163, -0.18406046897505693, 0.32775802293094386, -0.013474662204254275, 0.18891889549768753, -0.012329557945047033, 0.5270281673258043, 0.7538881364121606, -0.13459235982505374, -0.48514826256663024, -0.2804415143270641, 0.05750167096469536], [-0.08885632570549275, 0.268146175987715, -0.45750765473756, 0.7506599635946816, 0.24877765711439373, -0.43835993962489006, -0.16429912561164356, -0.6535610906609504, 0.5013043172413567, -0.6090242276639125, 0.02619050808213185, -0.5361828051221256], [-0.4219444768736967, -0.5717435312342813, 0.1461367097606682, 0.5753004876121031, -0.3772103245502108, -0.23912650972296362, 0.5351333272310783, -0.6518511452772017, -0.3419193657231182, -0.11529700554057473, 0.9211074620630613, -0.45613763854808326], [-0.22637545018314625, -0.5663468433083223, 0.5438976928370725, -1.0795361594171862, 0.40992700034500856, 0.07747568350294373, -1.3303737295015765, 0.3654769825863744, 0.5062004381260063, 0.0031246130888240562, 0.8363276785384313, -0.046943806216627755], [-0.8774998528827406, 0.11284951390231267, -0.9077803830083735, 0.26236222301077494, 0.8790322472258175, -1.014812406659811, 0.6765183076915151, 0.32618009891628824, -0.35959244767154463, 0.14184172809473827, -0.24021812428117945, -0.0882518980756787], [-0.0848955476929259, 0.7598000428288584, -0.5807285428625177, -0.2283032674399329, -0.8760319787178271, 0.30043016296950315, -0.4099347846246338, 0.30445573284049793, 0.16462845880582297, 0.041598085230228204, -0.09362080105531481, 0.04429600257511974], [0.2302332027533164, -1.7673409509724727, 2.361573677335076, -0.2828881105504217, -0.24843039391686553, 0.25761254038297277, 0.8276770830850463, -0.510090472606933, -0.1677403814464588, 0.15333220529350802, -0.049382503154943184, -0.16000442410643873], [-0.633036022400694, 0.731479739580389, 0.06049179970844457, -1.093868036592357, -0.15719646619107755, -0.6527816738086502, 0.09755450688930348, 0.4447395761283046, -0.2580083427435646, 0.10496609634185781, 1.4427773363427314, 0.3263095763836207], [0.46878223958874293, 0.7271504991734811, -0.24006384205868028, 0.030052673728748053, -0.08461471863190707, -0.2826123821080939, 0.12050355016260685, -0.5898973973105464, -0.13868812451917378, -0.36794382922551544, -0.15352234392013994, 0.32464143293330283], [0.3543234896521832, -0.6011788292222026, 0.41095944896672615, 0.39090325481903593, 0.32112380728048, 0.3373884853254945, 0.2829097751495205, 0.003249900666117276, 0.09503564578704596, -0.056376786300995047, -0.01772924062169638, -0.3249958965916819], [-0.588450097705546, -0.9650976264801466, -0.07565415425753134, -0.4155316093672571, 0.336942720077989, -0.21450312646695385, 0.7226676060621919, 0.3230321466627435, 0.016159955720543063, -0.5180859109047496, 0.0027436738330265673, -0.31828370232887987], [0.7728974097096366, 0.19158021689269086, 0.6628397810526971, 0.34237209530706414, -0.18126513382371912, -0.6825723212492459, 0.2882568151170702, -0.026112729717428666, 0.23946313729866686, 0.04833825481502334, -0.34173153046364074, 0.06788651654476338], [0.17315879459667752, -0.5064713114025463, 0.5792667831473378, 1.580534720480974, -0.22250277905160185, 0.19015573942570593, 0.020892712657329296, 0.13998289230760952, 0.26423169692925036, -0.11814253359358226, -0.49817427370428014, 0.5060776762663145], [-0.2918368751104857, -0.36324115653455347, -0.025989006341994633, -0.11978052772827433, 0.06548633831403529, 0.03688052888042013, 0.4215702675826749, 0.14996227920183125, 0.2142001870201318, 0.10933002360679189, 0.18392340507167412, -0.09745167967999328], [-0.6100084923679419, 0.18714402120154358, -0.12351835766710118, 1.3210393358717405, -1.2465996125326946, 0.5672667246378494, -0.12523740906599287, 0.18934184554783848, -0.28373509838889616, 0.5128575592428549, -0.1510465048321301, -0.4070772618939889], [-0.04017780067603635, 0.32698132471484914, 0.7873797238798703, 0.015679025406763927, -0.1371692075496896, -0.2413353524594344, -0.5658241642901368, 0.6221727443590839, -0.46823522347319363, 0.17301676263231827, -0.16367029087732474, 1.039804759326783], [1.1264231792460522, -0.3932988302722932, -0.5027065383358705, -0.033478383729716045, -0.052625416535851094, 0.23199563485639998, -1.0626080250440517, -0.005027023039044628, 0.4159876362841889, -0.3934183299394425, 0.36765109887040104, -0.3929376891547359], [-0.13350282815674516, -0.9720370933108077, 0.06396339004449104, -1.009870446717213, -0.42687315835306633, 0.41931205208093314, -0.41020094626706144, 0.20402302007251782, -0.2721417391386466, 0.0444539681498969, -0.12325747105260984, -0.03233716161093427], [1.0902053098452558, 0.02210365492078729, -0.38078096986365617, -0.44023058037490054, -0.5030211573177618, 0.18854801379474534, 0.03243651405939433, 0.5176343074070879, 0.027935158135679237, -0.35614853057754836, -0.2962063235307065, 0.5535805803784413], [-0.3525351305867207, -0.08487789969980829, -0.6757953322377253, -0.4488275153016596, 0.4455026711926286, -1.021853827640823, 0.33735475952979793, 0.3819507281159099, -0.2577990803610661, 0.302442651914308, -0.00566273165310691, -0.0802341264979858], [-0.19234520129184654, -0.30903543358273583, 0.7779927184976541, 1.0951764907645234, 0.3498063994092483, -0.031337452753088156, 0.06025483406101058, -0.011013474055218882, -0.4677010049882288, 0.06825549507125218, -0.19859260587125954, -0.4225530913768417], [-0.02733083469773535, 0.43968915038096024, -0.8888205956456809, 0.7196533888275475, 0.6620315729343242, 0.25401190874367324, 0.048633680138455794, -1.0834329645836458, -0.3394275292032122, -0.03319765074339247, -0.37043950718791135, 0.1465845931824482], [-0.06517819742538696, 0.4480234018746535, 1.2625166745710876, -1.4701238513932227, 0.38194631669870865, -0.22775258671407958, 0.359465376887916, 0.6152974596207534, -0.5559424861707912, -0.5546255971913057, -0.2983930145553573, -0.42078020786371617], [0.17157282587016776, -0.7444951398646408, 0.5236789651975773, -0.7441106448562439, -0.5310198631274756, -0.22335339257028491, -0.40953398943567715, 0.7149536901552974, 1.2436397732550701, 0.6598039905612405, -0.2796975495867392, 0.2428828423390106], [-0.4426524348408217, 0.23573973613959368, 0.5392981442177529, 0.2974792614893281, -0.4835108059597246, -0.21663651218777208, -0.5948460741551657, -0.46338182243920834, -0.45612542046853816, -0.28973668031260474, -0.3392711918928074, -0.3501330488017043], [-0.6841945865199754, -0.3336935146533432, 0.7378979017266551, 0.2372295250081303, 0.15696615088948193, -0.1864207651100584, -0.05850877880090496, -0.0089871818988806, -0.3500609669983442, -0.05348942596243176, 0.11280815232175591, -0.4308006876870717], [-1.4077566643364148, 0.71832955209722, 0.3947339109611548, 0.8967383472829479, 0.5779870486028796, -0.24899420796082541, -0.2962794377524983, 0.9890156724558486, -0.4595569581837143, -0.34914440596967733, -0.16507709350660343, -0.44170840704720854], [-0.3137146077503206, 0.7066541093304679, -0.6879270301172973, 0.6690652309935289, 0.7827637429567744, -0.35942398286590743, 0.27055196252986496, 0.11322622242950013, 0.3592455384803034, 0.23131790103222458, 0.18933088448167346, 0.4309467274951344]], "1.0": [[0.0, 0.0, -0.0, -0.0, 0.2510738702932849, -0.05369920225251563, 1.6732243128660516, 1.1226546891200673, -0.7494280295502087, 0.34926460658869496, 0.32621925353662795, 2.074070468947988], [0.0, 0.0, -0.0, -0.0, -0.26684707465044377, -0.5093391664451208, -1.1708052448710173, 0.43179253217236163, 0.3249506483574319, -0.6700096408020694, -0.2685628503223128, 0.20020178439185088], [0.0, -0.0, -0.0, -0.0, -0.8183550451856352, 0.9078190093261526, 0.06457224006872395, 1.6535178826341743, 0.7187301475417908, 0.021022997418052487, 0.3268961189779005, 1.18758409534555], [0.0, -0.0, 0.0, 0.0, -0.17713070701887934, -0.9879958211220579, 0.17373930457937037, 1.0037289538911578, -0.17567072251029578, 0.19205907005323622, -0.22816315656286565, -0.22794890261489087], [-0.0, -0.0, -0.0, 0.0, -0.6083112543332982, 1.609436680826946, -0.6365284166453815, 0.29282583870398765, 0.3712521617012866, -0.4038515819567746, -0.36888183319260615, 0.6673532787600338], [-0.0, -0.0, 0.0, 0.0, 1.5739832526160835, -0.5211738165036539, -0.7080139526367051, 0.3125684464276502, 0.15071489035793822, 0.6966490946135016, -0.2077943344985642, -0.0655944430781936], [-0.0, 0.0, -0.0, 0.0, -1.109433702170631, -0.67709336871675, -0.1218345769076028, -0.692683267962473, -0.1328305917751014, 0.19086904246716668, -0.40356708242677325, -0.08036206138240834], [0.0, 0.0, -0.0, 0.0, -0.6644219647464709, -0.0037107365555174836, 0.5205741037976517, 0.5539895413240549, 0.2634901991539987, -0.4099851387907865, -0.3796319779913998, 0.8828364974342132], [-0.0, -0.0, -0.0, -0.0, 1.0146454466143984, -0.2947592356200941, -0.3417000372711028, -1.1119111009709897, 0.20497264064291448, -0.31189223520020404, 0.5551663030230076, -0.18903803265975122], [0.0, -0.0, 0.0, -0.0, 0.1672972730369544, -1.2024967041532046, -0.015363100141712086, 0.5666570761809872, -0.6705289511663111, -0.11249930177470413, -0.20415349676355385, 0.22266973252617175], [-0.0, 0.0, -0.0, -0.0, 0.7495362403507745, -0.4057685460073855, 0.6944961386693435, 0.8675278796233421, -0.8580641403953939, -0.32266353229465944, -0.04516352529117435, 0.10262456508946986], [0.0, 0.0, 0.0, 0.0, 0.6731574839217754, 0.5406161942299592, 0.10730334916690246, -1.978762557818415, -0.607237423308969, -0.17077028315290832, 0.0866927299082496, -0.4624469708022116], [0.0, -0.0, -0.0, 0.0, -0.11798738478451368, -0.4618928951562412, -1.1859175159407294, -0.40981361224284235, -0.6624644631697096, -0.005990563969855312, -0.18482178330056484, -0.606941659925074], [0.0, 0.0, 0.0, -0.0, 0.7688142708237741, 0.2570524116337173, -0.7420477459958718, 0.08552548203712636, -0.3556663452289713, -0.775633470236341, -0.46357502961063257, 0.9542618479146812], [0.0, -0.0, -0.0, 0.0, -0.3998152437028431, 1.8964037636044735, -0.9586877242129784, -0.9272785309203678, -0.5452391906950639, 0.18271182113142342, -0.3754429195556065, -0.2680364003420558], [0.0, 0.0, 0.0, -0.0, -1.9070381961357794, 1.2481523871692946, -1.2978787040531787, 1.0467369412156582, 1.1371165892616717, -0.22808169082221566, -0.44965001087828915, 0.3909305599156932], [0.0, 0.0, -0.0, -0.0, -2.063663643589199, 1.5494072053663992, 1.1668706424536177, -1.137095615688167, 0.4782286812439681, 0.4106844051517764, 1.0869774423211287, -0.3765842764034558], [0.0, -0.0, 0.0, -0.0, 0.4761285201704747, 0.5941562067701199, 2.388442333886394, -1.085170621879386, -0.1583530722452996, 1.5909620465431322, 1.5582944390554285, -0.3909689564063915], [0.0, 0.0, -0.0, 0.0, 0.4193243180646878, -0.8634128292757763, -0.6194699249129377, -0.5981631890866073, -0.4881001571321415, -0.511913637708615, -0.4340477753878885, -0.20285490353418661], [-0.0, 0.0, 0.0, 0.0, -0.24076429387536522, 0.7493092545812781, -0.9106601178863306, 0.7849845362724456, 0.7709183450751771, -0.46000077154815183, -0.18120241477079363, 0.7246763592086558], [-0.0, 0.0, 0.0, -0.0, 1.6810769719954215, -1.3463084095111968, 1.42745951255636, -0.6584810713027331, 0.04076446556391427, 2.0162324543068433, 1.3010212466275903, -0.5390504296734435], [0.0, -0.0, 0.0, -0.0, 0.4405470776388148, 0.9173536455276351, -0.7942450614291913, -0.5799182325389604, -0.6598233881427886, -0.8511453931355942, -0.6033525618112806, -0.07781783696008822], [0.0, -0.0, -0.0, 0.0, -0.8180641225427646, -1.3157546053000102, 0.6415566176437, -0.09435478502737515, 0.00390963609523407, -0.488368176616888, -0.29392518736402035, -0.15057106804128073], [-0.0, -0.0, -0.0, 0.0, 0.47040017586438027, 1.3413610675071699, -0.15907545111615187, -1.5336143260158968, -0.05298911905923828, 0.5443044299315711, -0.24585547860415588, -0.43513155418254956], [-0.0, -0.0, -0.0, -0.0, 0.2626985343598365, 0.5859369124928924, -0.9816363215489305, -0.6981451675811091, 0.4103597990855214, 0.8039618737363283, 0.07925164449290324, -0.5813121032273177], [0.0, -0.0, 0.0, -0.0, 0.45579760510708794, 2.054146859205327, 0.5974057415652633, -1.5534097335170165, 0.4619579038499144, 1.0464620417111086, 1.2022251329352196, -0.37672731961115674], [-0.0, -0.0, -0.0, -0.0, -1.0764603537665138, 0.7513682265863698, -0.4972553126499965, 0.3162509844457834, -0.7118387329165591, -0.12333853832230073, 0.005200284887901941, -0.4632343274457256], [0.0, -0.0, -0.0, 0.0, -0.4688328307972906, -0.6983969920518704, 0.385484675416793, -0.3772649385053923, 1.0413588151182396, -0.013457174231238635, -0.6930109300136476, 0.27674450449892823], [0.0, -0.0, -0.0, 0.0, -1.0863220410394085, -0.03814875996603023, 1.2106387429314018, -0.8258596503270111, -0.22359657024331042, -0.43044208735295975, 0.11120490071989084, -0.22193130739066302], [0.0, -0.0, 0.0, -0.0, 0.5104055946643166, -0.7023796368402928, -0.6211998496172975, 0.8931885334789339, 0.6729978668868228, -0.06121690171443983, -0.15778223248772485, -0.5046004385371219], [-0.0, 0.0, -0.0, 0.0, -0.19266393802037268, -0.8555568921919762, -0.04352734555988879, 0.46788121328232596, 1.0476937088624103, 1.1733393147506288, -0.4138358028721615, 0.6724887430407901], [-0.0, 0.0, -0.0, -0.0, 1.7064593917811137, 0.7905447117881876, 0.4687430256586986, -0.6000705493288733, 0.7388978830314841, -0.45588775784021485, -0.06038265984666111, -0.3444691785178409], [0.0, -0.0, 0.0, -0.0, 0.26717166420137517, -0.017436628063950462, 0.7453303819847893, 1.0661588270262554, -0.1903423406563907, -0.6861032526834718, -0.3966041930137827, 0.08131964293738739], [-0.0, 0.0, -0.0, 0.0, 0.35182473670657916, -0.6199345718185707, -0.23235405172602708, -0.924274958252068, 0.7089513643189113, -0.8612903225761045, 0.03703897173519302, -0.7582769949149601], [-0.0, -0.0, 0.0, 0.0, -0.5334559568460651, -0.33817595317315696, 0.7567928090480306, -0.9218567302994534, -0.4835470042436401, -0.16305458893648667, 1.3026426652526422, -0.645076034743536], [-0.0, -0.0, 0.0, -0.0, 0.5797243234708316, 0.1095671623639885, -1.8814325712860052, 0.5168625055088462, 0.7158755248770009, 0.004418870207383468, 1.1827459455770555, -0.06638856742096938], [-0.0, 0.0, -0.0, 0.0, 1.2431393257900507, -1.4351614687627854, 0.9567413659310352, 0.46128831966361256, -0.5085405164240359, 0.20059449558201572, -0.33971972928626964, -0.12480703116379285], [-0.0, 0.0, -0.0, -0.0, -1.2388963053752897, 0.42487241101743056, -0.5797353321046509, 0.4305654265252719, 0.2328197991957752, 0.05882857630134066, -0.13239980657265957, 0.06264400760064787], [0.0, -0.0, 0.0, -0.0, -0.3513336323829217, 0.3643191484469867, 1.1705121561642755, -0.7213768643980264, -0.23722072239921832, 0.2168444842746547, -0.0698374057056528, -0.22628042661102224], [-0.0, 0.0, 0.0, -0.0, -0.22230937444454557, -0.9231726963688028, 0.13796290671347253, 0.62895674028471, -0.36487889751335495, 0.14844447703601624, 2.040395276540419, 0.46147142845393574], [0.0, 0.0, -0.0, 0.0, -0.11966328266562641, -0.39967426367183384, 0.1704177549540652, -0.8342408996851648, -0.19613462663510411, -0.520351153482214, -0.21711338089916857, 0.4591123173625124], [0.0, -0.0, 0.0, 0.0, 0.45413764345693886, 0.4771393717358303, 0.40009484094437475, 0.0045960535983884075, 0.13440069918092587, -0.0797288157898769, -0.025072932537779022, -0.4596136046755604], [-0.0, -0.0, -0.0, -0.0, 0.4765089644771734, -0.30335323062099734, 1.022006329580849, 0.4568364428929466, 0.02285362854734068, -0.7326841216759159, 0.0038801407453943454, -0.450121128515823], [0.0, 0.0, 0.0, 0.0, -0.2563476106388776, -0.9653030340111689, 0.4076566973850345, -0.03692897651697058, 0.3386520164561852, 0.06836061554085257, -0.4832813650721952, 0.09600603239986986], [0.0, -0.0, 0.0, 0.0, -0.31466644780047953, 0.2689208256589176, 0.029546757594759117, 0.1979657048016338, 0.3736800494062031, -0.167078773301163, -0.7045248142979593, 0.7157019133900826], [-0.0, -0.0, -0.0, -0.0, 0.09261166779386155, 0.05215694413018277, 0.5961903899086736, 0.21207868909161048, 0.3029248095467238, 0.15461600215929572, 0.260106973890202, -0.13781748707948505], [-0.0, 0.0, -0.0, 0.0, -1.7629580788927819, 0.8022362954658107, -0.17711244241759436, 0.267769805898505, -0.4012620242628414, 0.7252901158468085, -0.21361201568265165, -0.5756941847041834], [-0.0, 0.0, 0.0, 0.0, -0.19398655365674095, -0.34129972852822327, -0.8001962070575338, 0.879885133211505, -0.6621846034165874, 0.24468265223251098, -0.23146474511626206, 1.4705059928600284], [0.0, -0.0, -0.0, -0.0, -0.07442357779053396, 0.32809137322527726, -1.5027546805037875, -0.007109284160178926, 0.5882953570126261, -0.5563775378865327, 0.5199371702438929, -0.5556978091701709], [-0.0, -0.0, 0.0, -0.0, -0.6036898099559442, 0.5929967909193492, -0.5801117415091556, 0.28853212202287293, -0.3848665383776749, 0.0628674046588858, -0.17431238722641, -0.04573165251883385], [0.0, 0.0, -0.0, -0.0, -0.711379342839389, 0.2666471582670383, 0.04587215809890104, 0.7320454578847077, 0.03950627950251468, -0.5036700821620178, -0.4188989999977979, 0.7828811646375609], [-0.0, -0.0, -0.0, -0.0, 0.6300359196740569, -1.4451195418125111, 0.4770916762581544, 0.5401598998597984, -0.364582955813931, 0.4277185001772995, -0.00800831190390321, -0.11346818985861003], [-0.0, -0.0, 0.0, 0.0, 0.49470095424945876, -0.04431785069364336, 0.08521320352762148, -0.015575404377734754, -0.6614291043898797, 0.09652784683625477, -0.28085235661015, -0.5975803126478073], [-0.0, 0.0, -0.0, 0.0, 0.9362540291629142, 0.3592270863495797, 0.0687784100399192, -1.5322055924362812, -0.48002301524197244, -0.04694856792023089, -0.5238805751039498, 0.20730191971356096], [-0.0, 0.0, 0.0, -0.0, 0.5401536611737632, -0.32209079699660575, 0.508360811198447, 0.8701620122893814, -0.7862214038421497, -0.7843590415872215, -0.4219914481015787, -0.5950730767390374], [0.0, -0.0, 0.0, -0.0, -0.7509754923243807, -0.31586939697493904, -0.5791685221126944, 1.0110972050863134, 1.758772234043921, 0.9331037519595958, -0.39555206798808784, 0.343488209703555], [-0.0, 0.0, 0.0, 0.0, -0.6837875393421885, -0.3063702936411516, -0.8412393855946271, -0.6553208578506898, -0.6450587557697371, -0.40974954281504333, -0.47980192089729307, -0.495162906250411], [-0.0, -0.0, 0.0, 0.0, 0.22198365942140702, -0.2636387743266137, -0.08274390849812722, -0.012709794528910932, -0.4950609671864988, -0.07564547163962253, 0.15953481895967714, -0.6092441752067128], [-0.0, 0.0, 0.0, 0.0, 0.8173971230101897, -0.3521309858505462, -0.4190023991218583, 1.398679377386608, -0.6499116829463341, -0.49376475414901544, -0.23345426447417014, -0.6246700198603778], [-0.0, 0.0, -0.0, 0.0, 1.1069951014233976, -0.5083022712111213, 0.38261825473639244, 0.16012605937607183, 0.5080499127408706, 0.32713291285944934, 0.2677543046100763, 0.6094507066839214]]}}, {"name": "uniform_mid", "n_cells": 200, "n_genes": 8, "k": 12, "max_m": 1, "decay": "scaled_gaussian", "k_per_harmonic": [12, 24], "locations": [[13.08060671246582, 14.924557170706166], [40.711287029714015, 4.595797106754845], [30.0050262982827, 36.42802634058973], [9.395053668330172, 2.7573313666534096], [13.748468395301906, 32.87165074377963], [28.1132831390214, 7.5031131652668055], [21.63153954023936, 33.464864928726016], [21.139233663506392, 31.65921996370582], [48.37179762468383, 34.153241115481265], [19.581241654001307, 9.362628486004903], [17.298033278586654, 25.553298678478853], [44.56047047502896, 38.77819712363447], [15.907330030768719, 46.210844825341205], [23.545494270787877, 34.6879421101115], [5.360365422679402, 5.227177921647074], [10.095372376472517, 44.22248368441468], [33.99057307422918, 42.461816180721726], [32.221813460275875, 20.327119883776824], [25.828909706249835, 29.67217588779531], [43.10589924538141, 21.90930830795625], [44.612005498332145, 30.68584692012936], [41.46780629032907, 24.902802745862395], [34.625906591498676, 16.9512687324655], [26.141425196188194, 10.811169550950723], [5.035180100923842, 1.9302064960484422], [35.09747381929947, 22.8215310440778], [44.886707354658775, 41.75916023461399], [19.254756724040828, 48.683938485261145], [29.60310055391823, 38.29416571076491], [20.359717923980348, 9.808495598413597], [8.588850754091727, 9.060311311549341], [30.19027586312193, 5.631642755565913], [0.995537441871075, 41.64984820942102], [4.97055589663204, 22.529226777588107], [24.424928654198467, 31.013620419178118], [25.200724120079833, 46.8671571864484], [37.519829718163784, 28.723324894148288], [30.86360683526416, 25.32757458034901], [48.23809044376773, 11.331303167956836], [34.451356857428415, 27.75483394489326], [2.1005894534343037, 14.807499989186685], [46.35834677007956, 39.228242871499994], [0.6415546765194124, 14.831316483137241], [0.49026745232819136, 41.373347148903896], [5.518379615453151, 2.8727589387409713], [49.09416715975493, 22.293493970760693], [15.9196499531838, 2.4506694781546043], [19.479764214941103, 18.301952863106912], [26.174039402773207, 0.33927332407414634], [7.398144014510927, 10.494326287420314], [22.02522593743488, 15.115168315493316], [30.666383824519944, 14.27163027696477], [45.481650504220994, 48.093497909903824], [2.971743271795124, 10.452985957748956], [28.15115916279539, 38.53301147419897], [3.201211566219059, 9.240134221493983], [22.83600608453446, 33.434537927508664], [45.16639634944058, 43.348648177077514], [39.687770770912884, 2.636607168827554], [48.83182466460937, 30.73139745755784], [4.305790760072503, 12.746438769488266], [31.037704228314546, 19.282005844181977], [22.330173774527108, 40.22925327993748], [41.20154887073893, 27.339349009015386], [39.62255520272224, 20.300246454652722], [48.724091865920514, 30.257958271301792], [48.38489913434091, 2.199384602819854], [44.13463264213502, 27.968859377243827], [35.68195154793986, 9.629748768951002], [27.43456879954966, 14.46389620609596], [5.274023843335346, 0.15933853090585592], [45.342000993230194, 33.54521575179137], [10.251086583325364, 12.89093387813719], [23.279715576087423, 40.914362663473675], [5.881280143923984, 48.389241508186494], [47.19553832135435, 12.233004784631675], [32.03909297509654, 18.004876638304303], [34.8661672252792, 4.345805007387671], [23.498294010321345, 29.42454018450469], [31.32378679623414, 34.63977370857816], [44.569068650050305, 12.062510495371297], [7.659715866659317, 19.53034686064879], [28.441407384455903, 48.026438046027735], [35.52527928082092, 36.92212753348146], [48.63585269053118, 13.387158137929495], [12.973081276293897, 21.12704187844511], [14.771000370986654, 32.55516926142346], [47.58569604097679, 7.675574626801218], [25.897384111006737, 33.878904939911855], [24.658883329056607, 45.68719204470087], [36.84489931007292, 44.108839780528456], [5.588249405955359, 9.788175174835473], [3.2852112801805946, 41.465974923234235], [48.14093309029082, 0.6995510514216763], [39.46268219357879, 36.39155992639872], [45.40933971926886, 13.519273662970033], [35.73885916582928, 11.871144073460998], [3.801660002238333, 37.2602031351637], [2.1106485701531175, 34.9797231578812], [14.173123235118274, 24.371169754228884], [44.57665769356748, 12.170393950010643], [23.416219092835767, 17.752472352012227], [9.519044343849409, 23.682573417131252], [9.081516350571261, 39.9503745829285], [30.741082081393873, 14.156537641792589], [48.65524976320081, 17.263842223437166], [33.56283305994653, 36.66118632421271], [13.261319508831987, 0.5881900793905104], [44.63079383165688, 47.820825679581446], [8.511404170899556, 7.680260556192647], [21.633370972169907, 29.87847840748708], [49.449131367873804, 48.174805867797026], [49.39264199729848, 12.278470761871368], [29.94416008958946, 21.793457185686577], [11.57011478689402, 3.2688685358358116], [8.436418687802844, 17.922586439310333], [4.401086523757836, 7.536949568497764], [2.2325742584936528, 31.145313684608656], [24.635823993305106, 12.177650154994712], [26.317436976114887, 21.2223388827989], [32.95766118525437, 46.63336098739793], [17.66460532367915, 32.257576633744456], [10.94583691051576, 46.99496995079921], [30.884624024105957, 7.9373718800198], [12.852553045051025, 7.957568030676865], [8.956701723484473, 15.339942833421], [41.15352215815003, 22.852940081556124], [13.858498372949906, 20.953793038376812], [13.369911504909581, 36.68412080866468], [2.9390623505149427, 14.461428007363969], [16.162304408215398, 9.075975933974739], [36.90778916911227, 9.012368130435554], [15.02406715458639, 2.8238281063841075], [37.77928185839436, 18.193150831122516], [32.79641963820507, 10.86180510983784], [1.0900097356942418, 16.120907925485135], [38.95319263985068, 41.87228902324976], [17.441987823308224, 42.34703892707933], [2.517446293685577, 26.10572680367376], [12.8711208165673, 21.953884435029064], [11.082091081385387, 44.67833108996398], [15.108733275190417, 47.26459635178745], [5.454508946020814, 21.491550306483532], [22.17224665232701, 35.47173965111591], [17.251113489655673, 24.624748180392945], [3.522453026894079, 15.551572933277363], [36.249215893274275, 5.295569595576249], [23.126783587758315, 11.836347728415669], [8.274225006834085, 6.065775630428], [40.69329636919648, 34.33285097698607], [18.972805014608625, 19.582047141173263], [36.42287377408101, 30.197807480975907], [45.800763177614975, 45.97068431160378], [24.108735141280068, 32.95676284845942], [27.233385696774437, 15.514277085152672], [22.675671241778982, 36.05879321053935], [27.63410763405937, 31.62031832233041], [24.353664888418848, 47.648882147209015], [38.82307251678338, 6.539251685900882], [40.70547540177513, 45.87887882052015], [40.83290954542546, 17.15541238886913], [18.39544981636535, 12.160718515801783], [2.7852355011066923, 23.60306728078434], [42.52400892524642, 38.440579307952085], [33.10994507648143, 42.35953347166414], [32.95569374482221, 11.166670761236569], [40.15775384085413, 18.376000222985272], [44.50309851376899, 16.324126542735485], [4.595097529178882, 36.494909752903474], [5.382337605999343, 43.510721453844894], [20.596177554671836, 39.0060599521281], [2.6284227748227194, 27.191887875390265], [33.84470223684124, 6.475256438333654], [30.419891069825024, 7.15113076707623], [15.199456354038144, 18.264260276382927], [30.979268519704185, 6.505942246863578], [9.24128285001225, 39.062829315489715], [35.79378204173691, 22.710283480042413], [14.100150760774838, 34.61023211196624], [23.392220166045153, 15.575983654640108], [43.73416165855516, 10.09201589907533], [40.214142721053484, 30.89089528347202], [32.2990062883991, 34.10762256314034], [37.41355216796399, 44.04735475336908], [46.02919259910417, 12.774452333621749], [8.194310239889436, 44.81870417661992], [10.1914645381161, 11.098246895774682], [40.26284955007331, 48.30552942393611], [42.22726728137094, 25.836519578091266], [18.780018408700606, 49.4275866100189], [36.80344412723729, 31.45467605330098], [0.5564384297681302, 9.759588945205449], [0.6745885022196585, 45.35202074623896], [11.823280495096189, 8.551065524749735], [29.128386194976457, 10.155092814054111], [27.326604656193958, 47.48958505221131], [43.195434550331534, 12.256376688407483], [45.80888220323262, 19.96952200960282], [26.151854135272405, 16.24863381002996], [49.99790432390223, 15.353672807596602]], "features": [[0.5399169566568177, 1.7331927193612702, 0.33071151034490437, -0.9486769177776985, -0.5699415008227597, -0.9874045530855795, -1.250820892910365, 1.263717426531696], [0.8073369080982529, -1.2386443758091474, 1.7813206828903434, 0.24456072616609906, -0.9568919886003732, 0.3862219414396623, -0.06919425535493127, -0.772654754156563], [-1.942934292422628, 0.0367199044245328, 0.2919958479014126, -2.579077380532781, 0.5549073291632637, 0.617633315273623, -0.4697956074007749, 0.11212305491143672], [-0.2806581622889455, -0.837102565903231, -0.36005498048912127, 1.3516038346747636, -1.4506170874306672, 0.2371922807599949, 0.18411775561425542, -0.7076303040467823], [-0.4403392056116025, -1.4004134038437392, -0.8519621895254362, 0.014951829987135528, 0.3267159033813245, -0.8983768023366759, 3.056342448576572, -0.5703445497605464], [0.12733000408860684, -0.23058008113661133, -0.3997797846506893, 1.301068922967908, -0.4788113807596332, 1.3343888148654877, 1.1418162824452363, -1.0456651626015647], [1.0354934939748968, -0.650378085201944, 2.736458725862448, -0.385830367287836, -0.9409262342036953, -1.9110762706218807, -1.2930451619066796, -0.5806489121155585], [-0.9980278030069736, -1.2286868961543402, -0.695339730098914, -0.20654774379907875, 1.449347374642348, -1.7032948888086792, -0.5516409984891103, -0.9538936052004362], [-1.5151477943471543, -1.2661366565204208, -0.9057348401478296, 0.717043436255085, -0.1939005756185201, -0.5379851125064337, 0.6112916946490713, 0.28076949259843537], [-0.2233288441794942, 0.384285843261079, -0.8283509853404322, 0.6273813419491036, 0.4669249482525825, -0.4123042751157769, -1.219476167503311, 1.520064360242507], [0.09420101341934806, 3.051264990379793, -0.6534090705331795, 0.8528430151794992, -0.4342191613258609, 0.25366805322113894, 0.8333912121455666, -0.7993078114412265], [-0.10009046486167383, 0.1609415933976301, 0.11348010352709692, 0.5964510286999168, 1.0255631696971512, 0.8336283388549325, 0.26301255606830115, -0.34737294742823766], [-1.1296835823802003, -0.7354984590489994, -0.5285487871678283, 0.6827140633050368, -0.3636101787076367, -1.2423387669246577, 0.6263471527745221, -0.8032506973056567], [-0.7658286038917371, -0.2262714113895867, 0.47317784613006036, -2.413183502067809, -1.1214539869093503, 0.17558914927375346, -0.3641609994000157, -0.8645445152354747], [-0.5414528840700396, 1.385254014781392, -0.45572827030158114, 0.7126649634974352, 0.7918690820955161, -0.4502210163796867, 0.44343906735833705, -0.45023761606536944], [-0.6104175090232179, -1.1259943608376928, 0.8749562515109941, -0.39815933997704217, -0.5521424065645414, -1.1274449193384357, 1.8088449628587848, 0.7418056120443014], [-0.1328044743386139, -0.6947343725104065, -1.5297999957110904, 0.29181367179297224, 0.28842181160931923, -1.408400685933092, 1.1615503604811854, 0.7759563681434667], [-0.9620737434554694, -0.5556965398757097, -0.42732062653522446, 0.16067896055479877, -0.14556942539588308, -1.6389390914851827, 1.4740974764405594, 0.31631041981273356], [1.2607733727219834, 1.2548223468656416, -0.20790081666281907, 0.3419621356409416, 0.7366646118639338, 0.7696134282488314, -0.16391876009902318, -0.6181854716059797], [0.03528656963620903, -0.8015427671500807, -0.5559339779395361, -2.030179341239896, 0.08364267122819928, -1.0268913408658822, -0.5558396885780594, -0.052700338767042075], [0.313835120636449, 1.8891718089787175, 0.2043963634083679, -1.4132649523126866, 0.13074649659237508, -0.5957258433447797, 0.39938547889431975, -0.685527777486436], [-0.7084067849532787, -0.5112637703176611, -0.6275626738045664, -1.8247809921331866, -0.668271701024572, -0.014011094578567578, 1.2004887538923004, -0.2931780181939531], [-0.3717423549172949, 0.5798384134581572, 0.5394025169930706, 1.5995252792272336, 0.5851115504218798, -0.019450286235887595, 1.3383289912756622, 1.5294819254178111], [-0.47537841071405834, 0.15813988047309502, -1.6806406063719657, -0.3641274726191472, -0.883751559732829, -0.21407246588723866, -0.48163454666281014, -0.16604986483901601], [-0.1030345310149255, 0.49346811603417284, 0.2309384811096597, -0.5618043202363167, -1.2891630274820416, 1.2348517658732645, 1.417302420445751, -0.45444498347866086], [0.5614143189164458, -1.5261049084795155, -1.5622149607842444, -0.2698845204133896, 1.4716817014732062, -1.0465514932637046, -0.834124292834502, 1.607594753830773], [-1.8934479125719303, 0.6462222470218469, 0.4878139172904151, -0.2062707766030866, 0.18862497042534201, 2.6217416471404906, -1.126843200549746, -0.3139401962138989], [-0.23812341199355797, -0.689681094853643, -1.3418828847586879, 1.593300267091617, 0.22009507394198313, -1.757992137600337, -0.7028042433878099, 0.4054006969935171], [0.40342012908269265, -1.4403271207179613, -0.09142686767339213, 0.260881733967817, 0.39257185055724303, 0.394599594573365, -1.8230142215967522, 1.8469828118472453], [0.21113360860988503, 1.8059897222191725, 2.8630989884726206, -0.16055737016575133, -1.2337626990106572, 0.8641305338230617, -0.1808335583004662, -0.45140980633844907], [-1.0332863893232653, 1.687784568109996, -0.4426744608336864, -1.3995847794237768, -0.4475713869940921, -1.1572588411253146, 0.1579041657291662, -0.41936457209511757], [-1.0574242166772603, 0.6017661589705272, -0.6434339124687553, 0.7237612350644553, 1.2609835038667203, -0.36195277501923173, -0.6465143725591912, 0.1992960659293527], [0.8914495412790282, -0.0027930614170300176, 0.13995585012127032, -0.026890793244402588, 0.3112146214841731, 0.6287430128574454, -0.7060629239114831, -0.48253383612745443], [0.04358892769528479, -0.6657321368412378, 0.13612545006316243, 0.5361491154517042, -0.021721857920632182, -0.6035496713394204, -0.7772023247948056, 1.7512254375389424], [0.8785058405216716, -1.1199214963208952, -0.8410267720078337, 1.8738447102771199, 1.5112977055292913, 0.1281763193225619, 1.1578488998139589, -1.4869812979888828], [0.0013119551237214442, 0.7408091826893716, -1.8599673513879968, -0.7829942300567465, 0.7828548483383695, 1.1316298837875898, -0.5933074765515483, 0.28980943897870554], [1.6007125542072596, -0.38193308598320236, -1.3333640534167832, -0.06140760628961285, -0.3931576415089246, 1.3010482761373654, 0.16011555993879759, -0.8020945906620253], [2.4005445693384204, -0.5001170020373081, 0.4724457980298689, 0.676231542999496, 0.784322087164067, 0.17291589784186706, 0.5866738388147025, -0.06790212951201906], [-1.4191819757591058, -0.21981061925615197, -0.1984120606031994, -0.1777202571839889, 0.13609173374937553, -0.6247028845866823, 1.3232574876465875, 1.5667148999399918], [-2.2003616163374757, 0.009326022910595574, -0.7105945319425023, -2.6062438666560124, 0.41013590165116603, -0.6187996110686256, -0.3757345965787546, -0.6515779523373645], [1.0870054953546335, 1.2392980907422675, 0.2767953811830683, 0.6931088755728799, -0.11242830377589233, 0.14015923983728334, -0.7417626257805382, 0.034542802091417545], [-0.7136704942172495, 0.37302623967358406, 0.8273312048150304, 0.3110427594609149, 1.184129100789156, 2.6902452751419927, -2.1065611872332948, 0.01368401932219881], [-0.5686805406396525, -0.456695480826968, -1.3581751007544167, 0.052535240680992266, -0.2582727096422166, -0.6327706897865459, -0.25432262563549546, -0.592743762378631], [-2.342921928027927, 1.0774089665409339, -0.3034726649944876, -0.9496373472270576, 0.3064120818344737, -0.6624383829681653, -2.173997513558657, 0.8869023691567502], [-1.6767091476623874, -0.21840708812539103, 0.12015624637066263, 1.3496682963040667, 1.190060670481847, 0.16574807452757834, -0.7633915728919575, -0.4158971594271263], [1.087701697239807, 1.78644934919687, 0.5437886476464773, -0.6448445179128391, 1.0293720976482779, -0.37524007400830917, -0.4078493336446891, -0.27896865700025997], [0.5901489837909252, 0.2752748708141906, 0.9928014195750838, 1.296393290268744, 0.513245588103384, -2.332263505108117, -1.6965975324834899, 0.158588318728617], [-0.06470749582998864, 2.15919609624473, -0.03021406010653926, -0.15260993283604124, 0.9438880984894495, 1.0644334242541422, -0.2354101467042596, 0.4732020981752817], [-1.1335466735510225, -0.9431517751055659, 1.2330731451429207, -1.4071356100642098, 0.9223126265204882, 0.6778883836963349, 0.7697552393057158, 0.9128315094981287], [0.5638630194844192, -2.1414588260401195, -1.0043795138814626, -0.601311642921634, 0.9148204828660309, -1.1278052774245382, -0.7048950413848644, -0.3628120415362772], [1.316431753311868, -1.441052783072691, -1.3539295571708072, 0.6271611911698811, -2.125527883275941, 0.33197793247508833, -0.45404092214596675, -1.5769514157312279], [-0.42027139605492014, -1.002136967606976, 0.16778475442037846, 0.36382207550156404, 1.488961584822809, -0.012785236004645777, 0.10055350242187855, -0.5773107918296985], [-0.023635120294927363, 1.0496024638774737, -1.9257157098517275, 0.6591288765171397, -0.5351769370888788, 0.07389022981636481, 0.32504482003104374, 0.8505941707585264], [0.2384032404677032, -0.392510165412426, 0.31169434489336684, 0.011873143428439597, -0.20449984904689955, 0.20514768214965923, 0.8735804873101571, 0.13833204526399104], [0.15546925398579745, -1.2875104015183163, -0.12701123624878183, -1.858017514497396, 0.7200106451844424, -0.9392537106317062, 1.295381571439326, 2.9934371246052422], [-0.3973992333893161, 1.32963016728787, 0.40359895439285454, -0.5569872939709168, -0.8413112957218758, 0.5619416901201185, 1.3948218448617127, 0.35370546394195546], [-1.511898084178987, -1.042259556154732, -0.22797429875882258, 1.3571662770409831, 0.2834153216360066, 0.32726196006044633, 1.2105037494650055, -0.20459545512765878], [-0.08911600672401215, -0.18186611147551915, -1.7779605845691213, 0.466678824673757, 0.41083879461758455, 0.9754424102163893, -1.1889031941887371, -0.8158632329385489], [0.9344695067976221, 0.32306162042987774, 1.37502569046117, -0.8630322376337883, 0.20080300496543788, -0.6759974103338944, 0.3097533305949396, -0.48504479486914115], [0.5359671059623131, 1.0813637498384385, 0.6752704900364216, -1.8082730933080622, 0.9404036383030467, 0.4475421612681549, -1.0430206947590754, -0.8857661450196866], [0.00830672431640463, 0.5735293836763486, -0.45070090702216814, -1.6225116699945086, 0.28157907700644214, 0.16980863796344375, 2.441132835692758, -1.2885593639813275], [2.523750556565919, 1.7447023473132262, 0.3031228169389775, 1.6589841164428485, 0.09656039054564472, 0.9778372038418193, -0.7337658313823371, 0.07969794620159534], [-1.0145953036373696, -1.575470958380061, -0.2716605495854419, -0.6588938483984466, 0.5728123025961991, 1.2708039082075797, -0.1691529815213515, 0.058932245487839936], [0.1879194118872056, -1.677968206472629, 0.26908106282207145, 0.011350513858207402, -0.04632293555458984, -1.100374968013955, -1.981880044445124, -0.2502603399270847], [0.3161567504689509, 1.3409130348957778, 1.1311759870554547, 1.4553177109941065, 0.36995112234128474, 1.1561674790499608, -0.2060109159819667, 0.6284333888615184], [0.93181455440129, 2.689324816781176, 0.24263038529759048, -1.2725696489553424, 1.3777329642259921, -0.7912990295970187, -0.06067719796995602, -0.2942147207599775], [-0.9077565769370638, 1.334772560503884, 0.5960610883780224, -0.6120254324257658, 0.06933870156706443, -0.43323562118565484, 0.6151956063139694, -0.3785570909757764], [-0.7661634456406518, -0.6443074997008341, -0.4368536553707516, 0.2893671982226121, -0.9188751137092982, -0.08936968531863497, 0.443581034342539, 2.3372751683339277], [0.8562454750365031, -2.98376505481042, -0.5110760069421925, -0.39692524082441544, 0.32038533115964973, 1.5693859107607595, 0.7420753165903624, -2.30290996040382], [0.30697742860820487, 0.10806317664542026, 0.412981823340592, 1.358868943562005, -1.0908515170593922, 1.1030701453544765, -1.653863845908707, 0.05082243674418683], [0.38059724486327584, 2.2845322322902324, -0.7023309977826528, -1.6939352575353863, 0.6871254281866361, -0.6612309300503098, 1.5638256535648178, -0.7080566735693585], [-0.8772704091738562, 1.2444982173156964, 0.08543088159552167, 1.0007839014394773, -1.430215056158942, 1.6510887789103215, -0.5889053006974968, 0.8194419658785693], [-1.0049396051530344, -1.5506891029992798, -0.25682363961240373, 0.17446225208128271, 1.5766481244409924, 0.35004783701562814, 0.7155157207978142, 0.6589174098261333], [3.110154571856014, -0.8181433203148779, 1.2551571761141604, -0.1492557378373754, 0.26077995320951547, -0.5467523963143579, 1.162407533463749, -1.2548614661840334], [-1.3222780137924612, -0.2078272229951238, -1.158040158755948, 0.7032778558082995, 0.9218953645230186, -0.7529962764959367, 0.7838359722911195, -0.6620445153389045], [-0.044231737907907444, 0.0067614575142201615, 1.876453379846786, -0.00042766296619950705, -0.9119616386922705, -0.9175470838148942, 1.1999969427458774, -1.6690126598714072], [-0.47024369076662825, -0.3802131167857041, -2.4505131219590677, -0.4692601737924488, 1.0021567969835683, 0.23032237807167147, -0.9007649399878142, 0.6902670857262238], [0.5165442680842214, 2.0244995763351428, -0.7423377025697461, -0.3887201694897445, 0.041080771209926106, -0.13868723721106135, 0.08637654358075239, -0.10743859719654222], [-0.6948850752667467, -1.6044111752759957, -0.5609530522139604, -1.3925684660368427, -1.0520157329986903, -0.548196537445737, 0.5027747657286078, 0.8477512201139397], [-1.0444369171389865, 0.29739320051370927, 0.7919499652859392, -0.05768416565827316, -1.6552222467347484, -2.1715438685088877, 0.7768170398328225, 0.8974945881043015], [0.25732946643194116, -1.0743111971077481, 1.4313940393736775, 1.1916709870181188, -0.0688730681960228, -0.2466956135947305, -1.98196592379601, 0.7266574111651505], [-1.6390289021144402, 0.6551365344106433, 0.7035932666735636, 0.06791539106284909, 1.553694938956116, -0.3482723259857941, 0.56399111216743, 0.7713248055964985], [0.22324065571537574, -0.444035312432711, 1.2050538317792476, 0.3975518377326777, -0.21778551522794384, -0.19103199450364927, 0.1052061919813437, 2.2559609003757894], [0.08128785769926312, -0.2641072345895904, -1.089715027855544, -1.244672760274189, -1.9226665736524344, 0.2093179630577534, 0.003049942508909501, -1.0542199309744986], [-1.5129490838998232, -0.3528880178783862, -0.5512251103688909, -1.3634700197370142, 0.27403520232532497, 0.11465111352550032, -0.078996604649194, 0.7430425384537229], [-0.6816146057535568, 1.3307641684966505, -1.0441145070744942, 0.4848073495049074, 0.6054668765116848, -0.29052312994818347, 0.3210104390830905, -1.3148454096073832], [-1.5342612182390116, -0.23246248775706366, -0.7613859888773692, 0.5603119663175729, -0.001288298249294557, 0.5855029713682793, 0.28743282151436106, 0.1723198890895052], [0.0614949746797114, -0.4045534547442449, -0.4965536328928905, 2.003266274493833, -1.7932113018098277, -0.219007576057218, 0.9714456144687365, 0.3867476360702449], [1.3761785388259307, 0.5163381789360199, -1.2964743865148376, -0.3632682113949992, -1.4387404200659533, 0.9507840522094574, 1.4084936006324307, -0.47700963588611045], [0.5066640196955889, -0.4481562821350965, -1.4769049366749967, -0.485876861035575, -1.62258774580968, -0.6092422932873265, 0.17026507500942356, 0.6846247564755765], [1.2533356279614885, -0.3760601409401217, 0.19227996147605822, 0.37727537779314424, 0.5112543953088324, -2.8962733408654313, -0.8240494013103132, 0.749706494400599], [-1.1669542044699617, 0.19947242579849278, 0.7851218534039172, -1.9461561606143762, -0.24091523616271687, 0.18622880567979266, -0.04081464798584706, -1.58264879606989], [0.2934980777769006, -0.6152254242070134, 0.7675992443372474, 0.3742782073950901, -0.6071853809691887, 0.11740426495658238, -0.7503731244815276, -0.761508365116778], [-1.642658862092859, -0.30291845243940846, 0.7384740599002405, 0.04520355722546825, -0.09412033013341935, -0.7056782414352792, -0.603724108225289, 0.662619403467056], [-1.5775338901059979, 1.9779681702186593, -0.15055022224539763, 2.0843614195653837, 1.0848431065883672, -0.5098552718181245, 0.6407569302945383, 0.16089947055857004], [0.3645678019178869, 0.6942570195314478, -0.6491070121929123, -0.7220830970230391, -0.523938980569248, -1.4741832737018643, -0.3711738509403588, 0.119276179905453], [0.1385548840989347, 0.07986626391364925, -0.510336056135181, 0.6712254085984731, -2.1701290617494235, -0.517888321987753, -0.45176497808126764, 0.7712400436045705], [0.5371501630586578, 0.6712082840299992, -0.11748121995916948, 0.814926491005787, -1.1402305085623168, -0.06808546857700702, -2.254438505828045, 1.569383790963872], [1.4462136438155606, -0.7455211592438052, -0.9967437989058043, -2.2474440302142398, -1.6819181632931706, -0.028703766157090575, -0.30808309035032916, -1.626361552588918], [-0.6504944287861575, -0.8154922658122782, 0.3193076894096363, 0.560326452653939, -0.3684083977460223, -0.03318636476738891, -0.15313653106843897, -2.2367161507880575], [0.032360133264003034, -0.21129075694428245, 0.6040789090546708, -1.9820559740785837, 0.6191354276214243, -0.783751552538703, 0.12247712071368508, 1.0673183140586007], [-1.6195661910344623, -1.4549958974717094, 0.8518490665825724, -1.2833416756823892, -1.1015574235677301, 0.46058373114233336, -0.3448497368863164, 0.6372384965465728], [0.1593383506537057, -0.16602456014885195, 0.845187016172443, 2.049427522494406, -0.23850246927520743, 1.3414952099091395, 0.9955576089658156, -0.02773718629990384], [0.31954521548739623, -1.0751593286332306, -0.7539150890108762, 0.14041696092946923, -0.18407370417084615, 1.1646712675099478, -1.4364729599918158, -0.4296990196430913], [-0.7740306497797695, -0.2880188059727547, 1.0286770967018826, -1.342189589068026, 0.7153509917607139, -0.7247946002214214, -0.4585019017004502, 0.8650570298565159], [-0.41671936326101955, 0.534729153414651, -0.018141853512277074, -0.3049182568403338, -0.49183851541797907, -1.8627176414627138, -0.876948639404622, 0.037449908378366176], [0.07385676458979425, -1.619513444532029, 0.8761609484557591, 0.4477158366847986, -1.4274099589822364, -1.167767236473659, 0.38403680142607355, -1.8830577249975273], [-0.8650553338462186, -0.17453316505196453, -0.24704653428666615, -0.17608888723456156, 0.27312204711574956, -0.9158027070957443, -0.6034399074295281, 1.939218873522718], [-1.517597122164959, -0.5632059305698871, -0.0016974463198766796, -0.7589920981681996, 1.1117040816944241, -0.03721765667813209, 0.6493180251226368, -2.7252570089085597], [1.0811818780766191, 1.0428679113130017, -0.8627266613049547, 1.2021727544757466, 0.16170484441966038, 0.8256124984484982, 1.7120083043732381, 0.00024956514050236987], [-1.113092752679726, -0.1094527839791428, -1.3741918074068435, -0.8989146904788744, -0.8598698250972876, -0.8060720906259321, 1.0740089416857077, 0.7450111100757355], [-0.9882229105801391, 1.0429484234483721, -1.7688836941650388, -0.7438590494059165, -0.22452428697599458, 1.1061038445340234, 0.6458882071301031, 0.374927580768254], [1.2253469900949894, 0.64005790683393, 1.2918273345234845, -0.8612936244726466, -1.7644892690513163, -0.48962923752172666, 0.7604351589677972, 0.190609517712709], [0.8211829720676083, 0.642986522086851, 0.4487450659511165, 0.7522459470718337, -0.7828712084123571, 1.0279940179643716, -1.0725681432973655, -0.17987254359734187], [-1.4815757702249097, 0.4410418108235981, -1.618367776057049, 1.3422594103457097, -1.4104643220432878, 0.19496952020257627, -0.2044345409513169, -0.9422008298798137], [1.1864378401191804, -0.49308530909114906, 1.4037817434578443, -1.0909402817248004, -0.8669387630784687, -2.0656390309639527, 0.4900489944304141, 0.8544943963406814], [0.1617861974567053, -0.2248813795440279, -0.9848354931918467, 2.29046091153466, 0.6814740649734085, -1.9084560196760856, -0.372453170301025, -2.673896313451907], [1.5195968948113632, 1.9189127997287767, 1.4034454671990595, -0.11407287739630945, -0.6530067378313529, -1.465370108934465, 0.47370575664425096, -0.8059431559291648], [-0.4355261388695957, -0.6993252286929824, -0.36764630858117664, 0.8415088863531764, 1.6350250510400128, 0.09438501759353767, -0.03682010843052067, -1.171757738425589], [-1.2878035021494676, -1.1213030999124018, 0.8323620831956698, 0.19404745873255363, 0.9175069079598727, 0.37222176909180654, -0.4556331887894872, -1.2989039183108], [-0.42109231022528354, -1.4847571131226895, 1.9582524625539643, 0.22039304658590925, -0.41849899893206766, 1.9530941172435548, -0.43463098097507663, 0.5106956205746224], [-0.21289635494436412, 0.31127242094402363, -0.4179602733496858, 0.44844250887597487, 1.3871863715558308, -1.3169154489522603, -2.2828238498610873, 1.3138148469726194], [0.12269825211528251, 0.8338806773150593, -0.33744709801212847, 1.510595894019855, 1.7908690357587043, -1.2250918681203737, 0.6319369318787605, -0.662105913456444], [-1.67309531910787, -0.3540633392134089, 0.5225036358859587, -1.4346133341961858, -1.3523827409682347, 1.1883810144766447, -0.0263361978730111, 0.34551071439844333], [-1.2168606045522545, -0.7257820334452387, 0.054755006365977084, 0.11864000984641375, 0.07292966594135118, 1.5303194937352884, 0.08749566609872846, -1.6311364213588886], [-0.9704214114230296, -0.1487247456611953, 1.1973499339645064, -0.7907614975642802, -0.49480341748182494, -0.1292205515864588, -0.8196932739919245, -0.9411965272472832], [-0.3492226405611583, 0.890521033489323, 0.37275966263589294, -0.408492902004036, 0.28729822289490514, -1.4181429323255983, 0.8863457027290561, 0.6249907329461277], [0.17734121203402514, -1.7737292936485272, 1.9299778361695468, -3.0828737576907486, -1.1358387273821275, -1.0567415285258845, 0.5757168541786861, -1.6422926104237894], [0.11068214828034557, -0.28183939473679404, -0.42187448601569877, 0.7375885295628168, 1.3126822720464455, 0.2746837685331045, -0.40437834689438623, -2.4307315480688683], [1.3614318773273817, -0.42934055863495973, -1.9981865350326309, 0.037345026946905356, 1.3420746470599938, -0.26536868937972974, -1.3039762688636938, 2.161000240413595], [0.5023470913053416, 0.23221125371162984, 0.913076084603511, -2.3094070129501634, -0.1832851547593979, -0.27821472930164665, 2.1836330702953672, -0.6794202222743975], [-0.6668205114251169, -1.5139608082383191, -0.9376836824050933, -0.3125243285210926, 0.16240283229907798, -0.3036405852424689, 1.9285854583493631, 0.3973448528703307], [0.5460658098550843, 1.2855681145000768, 0.5424216022817685, -0.6276331821022818, -1.664378185841147, 0.2650532317912363, -0.9386477851402933, 1.237668895870092], [-0.8749958362367708, -2.3548189939949693, -0.05464346547257295, 0.9906517263228576, -0.3066585817826512, 0.0884125254698915, 0.05987963811807718, 1.6500389194711351], [0.2088261008660622, -0.13903889779773582, -0.7226745769809246, -1.7640983472754255, 1.329973113032888, 1.0666379081210042, -1.0667164859954257, 0.5185129065004865], [0.23180612641377937, -0.4866983114130598, -0.41823541155994254, 0.6644611365129848, -1.3245531857197235, -0.6299918170154711, -0.17970963543144847, -0.10879043238793193], [-0.3151904079214141, 0.11979362497919728, 0.4374641666896027, -1.0086864721210163, -0.015181480048060221, -0.6372158266137268, 1.4293962876207078, -1.5287869542628754], [-0.33954048633342804, 0.6087016803214623, -0.38980952252209833, -0.43824812581404293, -0.6462392075881798, 0.21919011856056295, -1.2790465350581819, -0.17945720872887802], [-0.1986071741280094, -1.5798396864360054, 0.18472351159204567, -0.5638644307623384, 0.22395548653559472, 0.7853543157792678, 0.2625899987697522, -1.2826182228561729], [0.24391235142068082, -1.7035983749555255, -0.8563261655296475, 1.6156924937053754, -0.07098630231025885, 1.5049612216677803, -0.256717830677933, -0.062023641502712556], [-1.201650441058573, 0.8865357775304754, -0.26894808135654324, 0.5681955268981652, 0.3781824340468032, 0.4806940716843077, 0.27238282363165517, -0.09466559437715953], [-0.05449324267216243, -0.7527654475494662, -2.2029943025532854, 0.4485415281363641, 2.0646840668097637, 1.0532708428608393, 2.328620959304359, 0.45770169686659234], [-1.0040872143682704, -1.02573385732244, 0.7311681936509822, 0.3249331096842568, -0.18598838639724263, 0.7347154940420287, -0.9006407765688911, 0.5169571200676139], [-0.2955908948808136, 0.1502323682315467, 1.194292192818525, -0.14624016497940007, 1.388548939394581, 1.3420273890101162, -0.7695750889673048, 2.352981513050235], [-1.252676585114954, -0.09802676814134233, 0.7502437844316818, -2.304017998813267, 1.0520702038286645, 1.1597456229821952, -0.10576595229953008, 0.28472094642858536], [0.2278144108956061, -0.20145912771666277, 1.0961337458568265, -0.36668709184325143, -0.03362827249372583, 0.3814434563088929, 0.8726042028857849, 1.128572524507197], [-1.4871729140968442, -2.048772006839225, -0.128721975939164, -0.04443484602139709, -1.0868302446934803, 0.31961912623393246, 0.6478271896171116, 0.39706607824220697], [1.682143027168207, -1.0410579560682058, 0.03228458446317422, 1.9649175767184803, 0.6971941230646822, -1.1249806927020527, 0.2128293992127909, 1.2037330689596615], [2.1198810049587045, 0.67922438183618, 1.1907978106322128, -1.120483124064358, -0.2465581741775179, 1.2169147759238805, -0.969035643335373, -0.05874466218300043], [-1.8914306561409466, 1.5040049663489807, -0.13083901599639094, 0.5762900073755931, -1.5235608235182379, -1.3311595622878374, 1.8426434462537435, -0.3469769693819539], [-0.5516457045887357, 0.5191802146010099, 0.5625277576156791, -1.9903050702771525, -0.9897410661708224, 0.051460202162739485, 0.005332191956390482, 0.35650227664969153], [-0.43564788127164483, -0.2843125390717779, 0.21810112379877555, -0.6991124708199106, -0.8472413240037294, -0.5568589448888037, 0.0055198848897066504, -0.15307723511227003], [-0.48668683929493295, -0.25657794323486954, -0.05268536995284352, 0.3217209124253818, 0.3637289019672475, -1.3082558535957383, 0.9818397234180367, -1.6262742693959116], [0.5478275181023375, -0.7214757183285921, 0.5800697746256748, 1.0653151699467611, -1.9119061641127033, 0.5997488312710689, 0.2668037423873017, -0.47981027313894586], [0.3774551187308959, -0.5120169528706975, 0.10783147992256022, -1.0740928644181922, 0.7793129349893242, 0.5820698191009133, 0.7364669863264871, -0.6747906366850223], [1.8421326337980346, 1.9803336207145503, -0.10246419293285813, -0.43502874872418273, -0.42615173850674803, 0.6784841885372175, 1.0226952036530934, -0.767873927843661], [-2.0599273587249622, 0.44345115558419174, -0.056522831077422606, 0.15756568094049453, 0.5055726832155281, -1.1373921400868434, 0.047883829218605796, -0.3184750803429427], [0.3603183497137797, 1.2102172676905494, -0.019945922735359584, -0.8869292863699431, 1.232068265709365, 0.689488638203813, -0.23200706153099368, -1.8462074789568177], [-0.9132794492732179, 0.11270916277492281, 0.5185713690940007, -0.5670554725487121, 0.4029021960093283, -0.677159438984247, -0.4651258761065286, 0.4961805666067411], [-0.31388672502040366, 0.09869418477964413, 0.8383035145153477, 1.093533081216933, -0.6380307120403675, -0.3001786587909276, -1.3799677844946532, -1.3606399504853186], [0.25123862532525026, -0.5735312186485532, -1.915181432659315, 0.480948871718484, -0.896124575555325, -0.3671487406618813, 0.3660071951582846, 0.34592453244355287], [-0.11143821613350585, -2.0554535826344744, 0.5136888331486261, -0.6518282447521478, -1.4771935234114164, -2.2712427586300974, 1.2708759345559086, 0.0880065930090965], [0.05815843154498825, 0.5575366935657581, -0.13230622363064912, -1.5361459326288505, 0.6286789972734814, 0.9516841819847679, 0.4662745777516499, 1.490363530216401], [1.8598578608418441, -0.8505295859151305, -0.49540515628831994, 0.8390634824413535, 0.12760483584028567, 0.16262097515722734, 0.8882540425003129, 0.6939328108335183], [-0.4903060927470714, 0.07781734039394417, -0.7599137268556589, -0.24196179753961192, -1.1594077664277862, -2.013274968790445, -0.5429627948817329, -0.6368897841502976], [0.8510331614257163, 1.5324455296529373, -0.0169457004533739, 0.4309151517744239, -0.6769775564096078, -0.9671727680408103, -0.3242279468835497, -0.3240925872451781], [0.2586045986886744, 0.0765277578138726, 1.6233525626229413, -0.2513558150684825, -1.6851268277406908, 0.0873126941656679, -0.6926111014516513, 0.17222131763072052], [1.0935962815599656, -0.6734892853870825, -0.10639679090194089, 0.48704251351089706, -0.9754443191582887, 0.18686831257308698, 0.5168661815975445, 0.7848259345974067], [1.070082881354981, 0.5282309857381402, 0.3658709793406684, -1.4156369146737278, -2.7028007138466235, -0.9879492344304982, 1.3991191896735782, 0.09468498107935691], [-2.2741165064364846, -0.4422345313559294, 0.3408857855378718, -1.8695947544464773, 0.5536808915472917, -1.1642537348025115, 1.023134185236802, 0.013324701319618664], [3.0779180598884333, -1.345718308399338, 0.2682102295200023, -1.487438948627223, 1.1355645620158368, 0.11330020024214665, 0.9099232146131632, 0.09291716366038108], [-1.179281134341193, -0.659371100969869, -1.2436387052072744, -1.0523303987982573, 0.1374389862438414, 1.0621952437664854, 0.8505673855364195, 0.5069001911765315], [-0.5695209311827873, 0.5032516981051063, -0.8595872639781154, 0.19980043281284782, 0.8304008244432648, -0.19202714643385252, -0.4742874472235408, -0.43718242591869644], [0.6066229193522177, -0.3147527320609897, -1.4238226114114105, -0.4187557272486758, -1.0670608045182126, 1.4905949393080429, 0.006730462872071412, -1.4736066225272548], [0.2592809171403295, 0.7117610093259316, 0.3727134655608511, -0.3644985637048473, 0.14317163942087088, 0.2727260822402397, 0.9947111608418681, 0.3574900108830691], [2.2550172958297754, -0.21901460247904656, 1.5186708114141412, 0.0133768007312945, -1.7032046059624482, -1.1735271511584124, -1.8161440905532293, -1.716374455356498], [1.1934501018123678, -0.6597829885852686, 0.5962311385159138, -0.8914885219643653, -0.016077272768655133, -1.052814657950716, 0.8584956758315142, -0.2565005560534657], [-0.45375745145314383, -0.1660937708647161, 2.163207395157522, 0.44248227678894053, 0.8287820434022026, -1.2402636722078264, -0.6501817981772822, 0.29037881908403756], [-1.8530495898974542, 1.3266454157602017, 0.2660742020968509, -0.0211778171230545, -0.20103489364557264, -0.23728641275809081, -0.5066237889386003, 1.3822635757136204], [0.6805401557091768, 1.2339898510126461, -0.3062189470423563, -0.8797315214435023, 1.3476430571510114, -1.2157063354626323, -0.6108135340422503, 0.7041091173290792], [1.0755915578585458, -1.3136657304657775, -0.27720141353075683, 0.022803754741584574, -0.13737456984449908, -0.8603000986563171, 0.6677959000704909, -0.5276079129609279], [-0.24426107197218783, -2.2445076385717355, -0.1144522336878665, -1.937191354525234, 0.6976375850343308, 0.48515504250198044, -0.5116328029609424, 0.15552125533470923], [0.1026095142153816, -0.1523240192613846, 0.35446086211583866, -0.1286255499433537, -0.47975285991933697, -0.7957232041869758, 1.6605874705937462, 0.1870459845176714], [-0.02598994653084163, 0.7125218538873577, -0.3924248697130791, -0.3861249031907432, 0.6560342769738297, 1.0165304464300695, 0.6614898752948306, -1.4792401833450552], [0.0513076618520871, -0.029162321707375743, 0.44514496675243975, -0.8853626635335725, -1.0486557040017712, -0.12242069149311686, -0.889270324834073, -1.0645312992174683], [-0.07595475220125252, 0.9115737141820348, 0.1272067552424915, 1.0997823761380872, -0.9956778080000945, 0.693340887939006, -0.01955942285311029, -0.8788992465769593], [-0.4236778333144685, -0.8595111562129613, -0.22317193509254887, -0.7493523562913721, 1.2371691844941637, -0.3646110040410735, -1.41681740362153, -0.20303127871324192], [0.372152318095305, -0.323951091996797, 0.8413278504439393, -0.9100593124042765, -0.8548151990581478, 1.595839241034145, -0.005458902144389882, 0.5255356021347263], [0.47978931945966474, 0.5602042747493572, 0.03311684497780412, -0.1974635447552798, 1.0603095948879966, -0.4933304041876052, 0.10525011757161282, 0.6674453923546563], [-0.39840699412720115, -1.520076730388698, 0.4448316568233554, 1.056332079325879, 0.2435823153548479, -1.6578943202712066, 0.623883898259348, 1.930115976451739], [-1.5274882278478432, -2.6728303058770386, -0.24654742206428282, 0.07010245847010442, 0.7635635920619931, 0.8002099425014837, 0.0883296853271507, 0.5287854330266938], [0.3270451794451357, 0.11966052442207985, -0.05755590295382803, -0.1516549223064091, 0.6882144344712035, 0.39634284265092423, -0.4195766914414386, 1.0707312589996594], [-0.7124344984337913, -0.22687944591855574, 0.1314546187606008, -1.8616051684228325, -0.369782753480152, 0.8361204085981057, 0.7959719259354391, -1.1674290792463986], [-0.8108590953878416, -1.051915311992821, -0.23047962547363077, -0.06270280989465797, -1.557223063000414, 0.31043284335306004, 0.06987689384224152, -0.07141950457114826], [-0.6565141364093262, -0.17939352168165654, -1.7364045817649236, 0.22595466474574277, 0.20623693933251896, -0.1030364122578392, -1.1511954106811673, 1.2426573478962246], [1.1027604713508332, -1.8268890541985032, 0.4038737513076619, 0.14909870191525054, -2.503643662205576, 0.5051746447136032, 0.6347241050204151, 0.7031766404538571], [0.15780874619456234, -0.6346285826845615, -0.4981792202714133, 0.5001122998139147, 1.1430184753975645, -0.4748714409028875, -0.2694265892778305, 0.68132606642732], [-2.0948127329176156, 0.4382167331214715, -0.22193936742494347, -2.1331627589927775, 0.7538305774560641, -0.8869838159517538, 0.7748289035759744, 1.3443962823073687], [-1.2076283597437611, -1.161861412326365, -0.006180501190029051, -1.698129029229008, 0.7161575580213789, 0.18854070888483476, 0.9625623592804492, -1.7751061393459788], [0.20514400733021307, 0.46065908011537315, -1.7401152983509345, 0.8798456334050504, -1.3299658785575685, 0.18907972163763118, -1.268200048869973, 0.7814422060139137]], "harmonics": [[[-0.2791934877390569, -0.6277303384152243, 0.35150088776337557, -0.5675006292737055, -0.01896450327421126, -0.24487823755056812, 0.29724241939431106, -0.25381979963649876], [-0.17130744029975875, -0.3819607339747015, 0.053573392476556854, -0.20950804342907606, 0.00046713892971399646, -0.2848408321129138, 0.3433150707160143, -0.07729507954459652], [-0.09853909248338621, -0.5569089986161612, 0.039588921162479904, -0.32174462805181203, -0.62470235227897, -0.6897951271279652, 0.36586668604987926, 0.49200487831813605], [-0.2905570898686919, 0.5968424276880707, -0.26607303112617037, 0.10570830354037866, -0.27199008906144717, 0.2529447436546212, 0.0726784852156358, -0.18848953981432318], [-0.5544727540370307, 0.08753046516656368, -0.10870646440006329, 0.17515739943771041, 0.31666070622904297, -0.2688949032274874, -0.44196917248537604, -0.04682841656699997], [-0.07225702300286953, -0.03279967776241533, -0.5113561482255656, -0.09256570345163657, -0.3116109409298191, 0.14917983412802457, -0.6357161075436507, -0.23897129220536945], [-0.28338907966016147, -0.3554945365274029, -0.066536792933949, -0.03378227547065681, 0.07198513803289877, 0.06925674126594127, 0.21939760810067518, -0.0673012967213651], [-0.10789512277265643, -0.43542532605481893, 0.15176379948033905, -0.039600891545801424, -0.3047247321830779, -0.33348928075148027, 0.1115278727058659, 0.04020120659652037], [-0.13125558237190302, 0.9770912283407102, 0.21221813341590537, -0.2759649827860487, 0.26616684439785426, 0.532373860890971, -0.27185874064894566, 0.0013862846652318165], [0.2825891493562813, -0.17427907669361642, 0.509302139725996, -0.12788638372872987, -0.4767529696539384, -0.3645751322266862, 0.27152054186604974, -0.24001533001611253], [-0.6599884725898415, -0.34955263178044815, 0.018701176564539696, -0.705025945855375, 0.10681796452049215, 0.06234951895798311, -0.053773601549229756, -0.33669091783643534], [-0.5332063593533334, 0.3069271957501728, -0.06856393873338561, 0.47010553348481454, 0.138299266113725, 0.8181227316048222, -0.23970198864101233, -0.133810584090842], [-0.22809457232497793, -0.2826360645665847, -0.6790769431147053, 0.5316381588244036, 0.6072759807417919, -0.28748199475016406, 0.5552993679289197, 0.29578750042711704], [0.3292047697751682, -0.10647975902032766, 0.3159213295965922, 0.23741179187592085, -0.21482736346058207, 0.2308882095893694, 0.3373452893841425, -0.06962635792007267], [-0.010813675911775768, 0.3370869692204157, -0.05897625930406071, 0.13945300829332388, -0.019019535844431664, 0.042506950766362864, 0.23435679371915702, -0.6950144027758484], [-0.4285671122516605, 0.1220284570942232, -0.29947213533964023, 0.393906682754155, 0.3359097860360711, -0.07450003276553858, 0.30038391077525134, -0.4484679126195976], [-0.034938725932894384, -0.3874079669053135, 0.1395908536040905, -0.2818276814096096, -0.29660005348775104, -0.5632720473833238, -0.14772348543636435, -0.21446714084102883], [0.5052538803021565, -0.005336777358531414, -0.08626713918899175, 0.5234093971266625, 0.5097417171055827, 0.15714019905100013, -0.42246289147991145, 0.43652202487903224], [-0.2753599983869789, -0.6016321818776358, -0.28909599441574746, 0.08918879713631156, -0.1737765748476267, -0.27100095506628147, 0.49699090485796926, -0.2791236003931499], [-0.23738689815072955, 0.16271685856818038, 0.10857914844346213, -0.3718459262889392, -0.04411122105277453, -0.3527994015872214, 0.2735579572378458, 0.5824049717035527], [-0.3354423925334992, 0.18154876398937642, -0.08003694390066038, -0.26863731369924954, -0.11238708431952084, 0.010486443472282421, -0.11790739887742309, 0.38221371601197596], [0.01336933805889897, -0.111702840295885, 0.1462560723799306, -0.40252356600102396, 0.18135836558350565, -0.505986794046188, -0.19041014585184374, 0.4385539242776851], [-0.04858020006847501, -0.30148893318421843, -0.1564531388581737, 0.29937813933178015, 0.14982920044397066, -0.23341412612854132, -0.2564041077896152, 0.5740778983167598], [-0.02687372454214489, -0.4058317070811361, -0.2619710306318765, 0.28280297288482353, 0.3578075361649209, 0.20346000779977738, -0.11850530670938646, -0.1353269856489079], [-0.2775863765824077, 0.6759318712673622, -0.2852585477785171, 0.27597990754518914, 0.1864045054259006, -0.13925539415491323, 0.21767855413462173, -0.5941902703314025], [0.024001333210087305, 0.005260031388376618, 0.32802964609506063, 0.3436805553376266, 0.2941482464160189, -0.23621762594982543, -0.00041985976756477554, 0.32319231769852214], [-0.19278612366115047, 0.08058192133738745, -0.31708864421415695, 0.3611408387787323, 0.47144582382746214, 0.5198349748672013, -0.13196839268881955, -0.6132478255920983], [-0.10148294691318016, -0.4121561236881528, -0.5523383178516126, 0.19328615847097763, 0.2885530951885005, -0.23481352687332757, 0.4632013767356307, 0.17968707855794763], [-0.3246843095157934, -0.40339943905192616, 0.012898381154270047, -0.9017493670693325, -0.4310953888490468, -0.6997909453379523, 0.5610761536179251, 0.2688643843685495], [0.23205133161867542, -0.5112953273685279, -0.23074946904803567, 0.1312390378501952, -0.10873795435535387, -0.5365320192521512, 0.11652806028885836, 0.12595554141358234], [0.11748566740363221, -0.3150589322709698, -0.22980331592445724, -0.1957986575580762, 0.27104217818859644, 0.10616601108048633, 0.04130748122423058, -0.46465670183838126], [0.14042758769589375, -0.049665528271830024, -0.25212773944549555, -0.19472021998229744, -0.6299331649867174, 0.3821603279185317, -0.3120621470986058, -0.5423545843678129], [-0.5197993802882526, 0.021381879793916276, 0.051124282168040734, -0.693634439165089, -0.47964534690137084, -0.21197359731683052, -0.40129377006106637, -0.1288913639588226], [-0.42791521257961296, -0.35226629943323307, 0.31493044820074695, -0.16820919395789663, 0.1692014360710981, 0.45976886166136427, 0.21422325370654569, 0.3947251352203502], [-0.16746089129013558, -0.3067625068768017, -0.12906610314559777, -0.1510973445787011, -0.4416853849323607, -0.12212739290457304, 0.2818602225650124, -0.15975785416200636], [0.43730925252285796, -0.572761599380411, 0.027322978621785683, -0.08709828714135558, -0.448124641821739, -0.11403967221089832, 0.13065449637679039, 0.35251318021264266], [-0.7080080119923263, -0.8608781160650055, -0.08996344960331004, -0.7640161488697612, 0.13820970082654016, -0.3759493153378284, -0.15818187769632575, 0.17468572917768982], [-0.13871324192541865, -0.03788183460946017, -0.14116896285084946, -0.07734090044845647, 0.30205608695571423, -0.18637662000298658, -0.3435315346806091, -0.03642113896256057], [0.09010206082394566, -0.053048807929161654, 0.44537626673656117, -0.3465594331124856, -0.6933720601301732, -0.4958700711798439, 0.06552818223105848, -0.06915477266973696], [0.2560664639067902, -0.838040757654532, -0.04250459167649441, -0.17372241424673887, 0.10379639257459546, -0.11139055019683346, -0.04973637662452044, 0.11647822831626163], [0.19595926165273247, -0.1993890615957857, -0.3856166360384036, -0.2797517006284312, -0.0243397993969821, -0.16304948025695898, 0.2086063249399605, 0.2800662466582349], [-0.48943992769674033, 0.19019559974943398, -0.22713934198305857, 0.47871777885893835, 0.1279521218493262, 0.5630793995849152, 0.05495426577324566, -0.24810536797595026], [0.46897271497603127, 0.08709691496517123, -0.1930566488813914, -0.01613706595452871, -0.01565325118266621, -0.022376562167589674, 0.05039701320791974, 0.3784976320682202], [0.1258150865255781, -0.17008144088311422, 0.12951179813219052, -0.5370534483114068, -0.500343207931401, 0.046103972388391826, -0.1651522972816792, -0.3879191511871264], [0.059424046270231005, 0.7407880278893676, -0.25695791237651605, -0.017924022057726054, -0.23448797942288171, 0.0730630324513706, 0.5754767590994657, -0.663351491731212], [-0.34092793292317297, 0.28012550680097187, -0.2707585554494643, -0.8632144474245432, 0.015322739693281493, -0.6101984420693117, -0.016072743082054104, 0.5386500086373027], [-0.2622726364394407, 0.30874247183512993, -0.025885370466996228, -0.05554504524683755, -0.7326112747865795, 0.15046381708804482, -0.1545201935584047, 0.2134907533962139], [-0.10038117641757592, -0.2682506768279499, 0.22061089899560365, -0.9502660069571429, -0.44311832747538593, -0.24240884395952117, 0.0889965241216581, -0.06830830068328672], [-0.002668141040269662, 0.29496106863843585, -0.23603330959175964, 0.15900657213406497, -0.29365339380006006, 0.0695391110446481, -0.47146028852307464, -0.30072172340057407], [-0.3054260600862348, 0.24682901795864862, -0.045640194886651726, -0.5550461196831986, 0.08411654346834499, -0.06354118137391539, 0.31207288504637426, -0.5562770081327517], [-0.05159820110392163, -0.10464330127811146, 0.17661675240495026, -0.3388294425236525, 0.23978322020156723, -0.21459763068574308, -0.05563704607419166, 0.10012606808111436], [-0.051551465103064006, 0.05177759337049699, -0.15148077186244613, -0.27033478783117043, 0.22499298221939873, 0.08225063610809417, -0.4398941206815161, 0.30557491725318925], [-0.6824297689687691, -0.00478217473008218, -0.23313643595322933, -0.15236510692646238, 0.2501612884510424, 0.33527915980011874, 0.06242257073162227, -1.0805370435613495], [-0.009301223632679972, 0.286130029414265, -0.23826256823667155, -0.3474745501902472, 0.1697684516472963, -0.14496089193218434, 0.30156647182103963, -0.2945026056072648], [0.02588304070579536, -0.3350409929605708, 0.19038599788278496, -0.6003976027330845, -0.2915544318484178, -0.04504578557288827, -0.0114395476117369, 0.13159209325579288], [0.11872056616170636, 0.0944736001388779, -0.2337717766120714, -0.10975536210304555, 0.2993083683507608, -0.24917427348986737, 0.19723492789713332, -0.5391874949875063], [0.2647833700010664, -0.27439295159522675, 0.5120054193204859, -0.30112627976264555, -0.42067325766280694, -0.12917357014924918, -0.08149205587239122, -0.3001875227175125], [-0.6313880791492767, 0.18073169606916265, 0.013623354379105918, 0.11059922506808782, 0.3086619610974325, 0.7305918595397195, -0.11673705096067385, -0.6601884632201077], [-0.15632197011292273, -0.5278004754376998, 0.18792650233243413, -0.06826242049031743, -0.2912697856133946, -0.10198783536040046, 0.18321773409916423, -0.22196254135946666], [-0.24496999545539852, 0.5810946153078967, -0.009578017760507755, -0.2067974478004186, 0.13064869515758679, -0.06110564753244086, -0.06279683436278738, 0.22711751841623443], [0.24981842598527165, -0.09177399972605418, -0.17052487934209354, -0.17613926082289758, 0.09850225006707461, -0.08902518738075142, -0.08702264615558633, 0.22112294798636395], [-0.3298660216640754, -0.35460891609318146, -0.1853460325600456, 0.058938267711665535, 0.45068679320126387, -0.1427390849612912, -0.045957554619095314, 0.1852922865485687], [1.2260535617549766, -0.2398730640970983, 0.26357548124325647, -0.6868782309842333, 0.06741262583270152, 0.06139127456217219, 0.38664098671524133, 0.041085144432115375], [-0.1715635104764702, -0.26338315440438836, -0.2944679879547798, -0.7997368564628611, -0.0021023228710889833, -0.15863901975580227, 0.33227560790919475, 0.3127250640037024], [-0.1741223827224022, -0.44398877868430897, 0.07220584082340462, -0.2122065818989022, -0.2124729226798526, -0.511965550959172, 0.07739065022715867, 0.6301092813977489], [-0.3051119122006751, 0.3115136094633313, 0.026676071236984452, -0.4252329099188285, -0.008465832557663634, 0.06959821176685105, -0.17173435011651095, 0.14136508556683966], [-0.12701187747337658, -0.34515464274712127, 0.6819112125298181, 0.04355537972250114, -0.5046431186583042, -0.48515845408264435, 0.13632072887372285, 0.12061795978462357], [0.08880244916812931, 0.27406028252943504, 0.00056075950616232, -0.8572303882721745, 0.19148244703379763, -0.3230948863903746, -0.1450374211611953, -0.10073079856509311], [-0.17430101575194773, -0.13573843115023307, -0.42339772501869705, -0.23599699328800483, -0.3559522713001708, -0.10647202578585625, -0.011084355581971194, 0.156737465197477], [-0.2665160942022586, -0.5503947399339945, -0.21713564705195376, -0.5262107445034557, 0.6223001023385838, -0.04952439067669422, 0.05990868752349525, -0.3353223884556465], [-0.38971372753939637, 0.33780161108633494, -0.15466235962654235, 0.4443921178332267, -0.22330837646112636, 0.18965843553629122, 0.19041173864420025, -0.4764287276348332], [-0.27078893876465426, 0.43297789879650855, -0.027826391070047092, -0.23719279401664606, 0.2716937142018233, -0.10186788084620246, 0.11895660437213512, -0.023823094781863504], [-0.2272387415451471, -0.0878332693506131, 0.08258985233686664, -0.7761020058420378, -0.04079012010015091, -0.3833699185623178, -0.25558034923732165, -0.3006431672918982], [0.3708105025947169, -0.4090137026384382, -0.20214054520403898, -0.7896560652522702, 0.2676101488021159, 0.4496110793827778, 0.05783292164938277, 0.38563362780782323], [-0.5512109246066783, 0.038021198490650734, 0.06062310530136239, -0.09759609841240689, 0.13991652644254576, -0.12569592510795535, 0.3876504066231458, -0.3189179576804268], [-0.2127254525821596, -0.09471276311656611, 0.16400250236853614, -0.5943769842465384, -0.37986598804767024, -0.46541412700958895, -0.05493802254190787, 0.41199010377203593], [0.14255463960525358, -0.03727156818382247, 0.2461095857472506, 0.4812260847669989, 0.32707114314710783, -0.07187824684909527, 0.09171603711294482, 0.34008871499524], [-0.2483075925994019, -0.6247675734294944, -0.018642689578300935, -0.23958375200037269, -0.1957218253117275, 0.09250335971604282, -0.04880021746885057, -0.3468983841971378], [-0.05797382294021865, -0.293666418331663, -0.2673432806286562, 0.26417147824167575, 0.12119234649498753, -0.23014861729336428, 0.30168623586721643, -0.41043723853879116], [-0.3497824041580586, -0.5454134658441011, 0.05976280773526992, -0.5919142773400695, -0.3242157314736487, -0.2165254009443166, 0.2930346094923574, 0.05321277332292259], [0.16126668018403675, -0.2402473836983718, 0.1364975216644283, -0.5555829673270258, -0.10990346088546005, -0.6793204659869001, 0.09782484577578728, 0.07937498616795675], [0.05079221705556121, -0.377892714850031, 0.5211942812379046, -0.11766120995358487, -0.20340728683468257, -0.14282460957367277, -0.1010760701525047, 0.41827462837448776], [0.37713920063043743, -0.4889514543478131, -0.26916552565977275, -0.19360178541909462, -0.3875895269636976, -0.029448907224335217, 0.05559373917597677, 0.22873214197861994], [-0.6940126430566347, -0.25331882543984047, 0.11615548135095209, 0.07987938239756669, -0.3983528732414687, -0.7984334746058582, 0.5111413263312719, -0.14885646206518696], [0.0886432844723356, 0.13354567115734617, 0.3290451157108178, -0.23331896889373688, -0.7866839070501068, -0.5960754102998375, 0.08861630034010427, 0.11323964867756686], [-0.09553612820415555, -0.34434621399684784, 0.5542958289470776, -0.35675346945650627, -0.24887020221647654, 0.10995019233766028, 0.24517352603469755, -0.369255045678525], [-0.5991549993229169, -0.06369942838228264, -0.10055322807061252, 0.08346123155039203, 0.44763817232167386, -0.4887424073941198, 0.04259628796899721, -0.06984665458596598], [-0.15066453488556336, -0.14968843555817296, 0.4472302147194265, -0.3934855407755458, -0.25324879364395886, -0.5867721743312106, 0.20959200728442037, 0.1495762237770526], [-0.17858668863338398, -0.22022196145509773, 0.25056992722995197, -0.08455580624089704, -0.13228185245403296, 0.07769445350108528, 0.22426516626839368, -0.22213232762092588], [0.5151332650984547, -0.39034359907731625, -0.06580690687892722, -0.24849345097063455, 0.09254883863082258, 0.24090956710424363, 0.05930442446601563, 0.20332913472538364], [-0.1687583424439642, -0.08903546857479692, -0.042080087408749745, -0.120152588992379, -0.16693862612242544, -0.04745903905290316, 0.29551203383496943, -0.6406702875109238], [0.1501686796996426, 0.10021964257277242, -0.3817620508608915, -0.12146803935784654, 0.20283535711184966, -0.35972400087442996, 0.4134133228175661, -0.4753194438949377], [-0.37096501277992405, 0.067007175224449, -0.005820042126840699, -0.6708736040227038, -0.33231996110625, -0.17544145051119397, -0.3084291747139535, -0.042068239448556866], [0.022105756158489233, -0.04102105673231833, 0.6890507067841543, -0.11232130058189707, -0.44241247520075005, -0.4332110858056354, 0.33536122267449414, -0.08830897098580509], [-0.3241329031396956, -0.3011485402444368, -0.09617842160136919, -0.06664559618707921, -0.49516919093487877, -0.0190372418806794, 0.5258195317705956, -0.28463019032488823], [0.05793554733755676, -0.3672773103033398, 0.502553751631251, -0.3130993378428532, -0.2403782879283059, -0.4216383814405854, -0.19158953273041346, 0.13642527950848557], [-0.18861630989845696, -0.6669106537662474, -0.18374583791364307, -0.26767560962564, 0.2801594884078049, 0.1835658766859852, 0.2313886303482482, -0.03518273745861808], [0.40182672713903334, -0.031022170025233962, 0.11001743718180478, -0.8925545920621969, -0.8875540054671527, -0.33267586098224283, -0.026008793080101875, -0.4375869903036838], [0.2765783596171425, 0.29754794767798015, 0.2413510415419719, -0.4162498871392301, -0.7079892548445381, -0.3105477710040038, -0.27982745167700535, 0.04158626486992701], [-0.2741862500698657, 0.1617763371985364, 0.1171904640689077, -0.22085225493778057, 0.014159794826153838, 0.4210506023173206, 0.40313685702184515, -0.43000813112657954], [0.2016127485233296, -0.39388646250103765, 0.2916840717960061, 0.03917560161523585, -0.24542094162201622, -0.5762794842795627, -0.30609448526511934, 0.016575053869363063], [0.07839530877711962, -0.1311249409817766, -0.14121457093398412, -0.3483987669967537, 0.20189703426527217, 0.045288995569189604, -0.12085847293886233, -0.4476651282057427], [-0.38312232748000763, -0.5254420085728184, 0.2093312411269512, -0.0397755565258255, 0.08015609555248016, 0.042550838664784846, -0.007134872170964674, -0.1316532770683683], [-0.040650674955224134, -0.037147049572936734, 0.2816567135251559, -0.15458830817353025, -0.22470372383937368, -0.43689298002046695, 0.3622749931694477, -0.18573061475492952], [0.022256123731510747, -0.093045972275694, -0.33926373804592996, 0.09004697710416405, 0.38480032330394026, 0.22155900109229637, -0.329250223418127, 0.010403527200136299], [-0.12199955551828896, 0.19661891737383774, -0.0710856472956156, -0.4792435707248272, -0.41442582436463093, -0.364893759608771, -0.06305831418146068, 0.40688452777167045], [-0.528147423109925, -0.31297774750064944, -0.14072193823715448, -0.5338117695925297, -0.4060044323152695, -0.546203900012147, 0.29583080605988893, 0.35661143671386253], [-0.06931998429136053, 0.33308664562995594, -0.007976576494773395, 0.2831729587473025, -0.6081691022740084, 0.032600287604783944, -0.13897609488672757, -0.2502500000720115], [-0.31725794050935374, 0.2972609247328224, -0.5527803585248651, 0.1753857587285712, -0.12466426313745027, 0.3191063760689116, -0.04354049632354251, -0.35204717818107617], [-0.15253414971385876, 0.009264279868511374, -0.12335301830964393, -0.42585720100369917, -0.03995311512029351, -0.1513609091198034, -0.2864303691182173, -0.6207394883225702], [-0.09636806870169179, -0.6586833041169579, -0.055565570667048654, 0.08598314319068233, 0.11632756807776724, -0.4216307988309753, 0.009421355888114184, -0.2818461060605108], [-0.46934213811186504, 0.09267373969850717, -0.30766005668894486, 0.12954086129279369, 0.238578751034405, 0.46928477854953426, -0.07258750839663328, -0.7651282961575998], [-0.382791572673091, -0.11104493988449014, 0.012752684735082625, -0.2330041801551178, -0.40657446827706506, -0.5037518695739374, 0.024585924311006, 0.24602999729879754], [0.2038923771096021, -0.2750819263097457, -0.09246119971929022, 0.21793278756977916, 0.6330168223021466, -0.15752639676037544, 0.05452948918586058, 0.028704592682946402], [-0.06154566679072196, 0.1568328869746954, 0.09595625758221989, 0.2379965360320894, -0.4551577689897272, 0.03545690228395799, -0.26352636942483665, 0.10616908007172804], [-0.49270680082056806, -0.1948709888863377, 0.4036718379232641, -0.03213244105380207, 0.27646934822434194, 0.017348518155556394, -0.09713589517422612, 0.2909646742654275], [-0.1261944440274521, 0.4935886197100912, 0.05408588821779198, -0.3955304191555036, 0.03293575549497454, 0.14873585360224914, 0.45626964605559295, -0.2842300084937299], [0.13327125448275728, -0.33825243924018694, -0.1854249345325818, -0.7149958366951887, -0.6225275109329268, 0.2043976170128023, -0.052654238401591585, 0.07825172237665763], [0.2989290297452244, -0.23449641268907068, -0.3177796859189916, 0.21265474205944096, -0.1654498766829181, -0.07257679445558186, -0.27090626545633073, 0.02498912714624828], [0.28491219869631773, -0.048780514354770356, -0.010292933029559349, -0.07272350161698099, -0.005035358805081098, 0.3173573283314347, -0.1761260552070161, -0.12165610994072672], [0.22372441793099387, -0.22234513367370304, -0.18102743094094761, -0.06697283500124505, -0.30923069747976406, -0.5760091475845823, 0.10006888595800792, 0.14497276149630467], [-0.643555647898849, -0.3260102953133599, -0.030164300409175365, -0.023775094469784958, 0.05247264114932021, -0.3584353496957697, 0.2834288398258998, -0.08359106438118262], [-0.6612807837600598, -0.21413657764657745, -0.3444064220760448, 0.30230373351169343, 0.15324507714988495, -0.19368603445189456, 0.7268275054540445, -0.07085055906086334], [0.35544571488994275, 0.005667684119810086, -0.4986346499296968, 0.06690041142673012, -0.2705920324936151, 0.21063248757789507, -0.525047152731486, -0.6219718617134322], [-0.07716230003217045, -0.06178277103810661, -0.11795762675343407, -0.3184770192575936, -0.3554281790493528, -0.03442020505705074, 0.12327023245145173, -0.16679406435712968], [-0.04349990920446434, -0.17560377561334461, 0.146508834290921, -0.6177177489186386, 0.43927915089785236, -0.5472511319717105, 0.05763486264814069, 0.4059219337210829], [-0.1483089431760626, -0.30636564743874917, 0.04730561057432891, -0.4584457202031915, 0.001090468803535526, -0.32980005693896025, -0.11605746949320395, 0.45431282662190564], [-0.21861956914537586, 0.29515049766823975, -0.023668187741155446, 0.16810882753920997, 0.08039591735103722, 0.314983152772054, 0.20140930465863643, -0.3031549751423721], [-0.29444553622090325, -0.1964142377772224, -0.09551524132884297, -0.14131083678353576, -0.006390849152886133, -0.3066422076701952, 0.2003161103517464, 0.2235560118359759], [0.1475579663766332, 0.08585835518567284, 0.03713075554525886, -0.2547961182080114, -0.224583731295309, -0.07492352751838294, 0.3633850493653753, -0.09287694548000601], [-0.23875880778644565, -0.16962738628227947, 0.27275754013503295, 0.07882439631805775, -0.40394334780149826, -0.2295405929703273, -0.29778215980530454, 0.13535317879961425], [0.01762905725828044, -0.5648859139346591, -0.19944324441977435, -0.2219108490730828, -0.30828421399509703, 0.21716730940674378, -0.11250153934276139, -0.37040939262922096], [-0.2764784925486439, 0.08381200689412692, 0.003175384918687414, 0.3409612279374747, -0.3421839513697938, -0.322659719354172, -0.28746626559253585, -0.03016218898270404], [0.07387713569783654, 0.11003544930092235, 0.09935143684516563, 0.39832270499994127, -0.0850664861423449, -0.24671216381279218, -0.022775205686208447, 0.6167094733309378], [0.06014005435631537, -0.24124593306520511, -0.2400691925915471, -0.07442036668358944, -0.392439366964001, -0.001959611020225425, -0.14286656843630244, -0.2705798397001523], [0.2498228831579356, 0.05493440070486033, -0.18511513554559808, -0.11525652489390577, 0.16012701399244836, -0.063717784910891, 0.07303401360817373, 0.48583938257509146], [0.03768270363614744, 0.08899689903327038, -0.2676581481622114, 0.27046843974321183, 0.07407882915948541, -0.2092617116740405, -0.09015658998116503, -0.2839868458510766], [0.2729451393043271, -0.7411278243314192, -0.34759997384263175, 0.1763209183469157, 0.5193291887369751, -0.298190520786525, 0.6488964866906513, -0.1341401105592288], [-0.045990122393624815, -0.034819903104003486, 0.15457826014596526, -0.36085388643050315, -0.14179641768495294, 0.13281145975370318, 0.24472223020906972, 0.5408231370597465], [-0.2805386621990511, 0.10438861202949563, 0.4838389173938056, -0.4260042923434307, -0.11413652538916837, -0.09591612827171626, 0.35780294927159184, -0.6312045804681328], [-0.320080531230591, -0.22509154402367654, -0.1868006095120421, 0.30620095782463813, 0.24947372652965233, -0.3776651801265483, 0.6625053909707392, -0.2731222365697122], [-0.5383050914667338, -0.2352676207153057, -0.3130282194458378, 0.729045088024462, 0.129660918815345, -0.8577030209713794, 0.2619506177190846, -0.0038938495070773367], [-0.12751419135681297, -0.29291265618318385, 0.26448753017629895, -0.0684136834023198, 0.1792011559389064, 0.05305067878014695, 0.17008628054349564, 0.7230232522990183], [0.47542989967793453, -0.2394217848115862, 0.31998077946058806, -0.30441831674184794, -0.3124109457660762, -0.048139847168343304, 0.2492263766454875, -0.5454206732906645], [-0.22573380456960532, 0.38684408325848857, -0.06601784306954835, -0.0791103703962678, -0.2714766900392532, 0.07327287223798558, 0.26392910501489947, -0.5649640886060427], [0.1710057764456315, 0.05880750518225579, -0.2521472191084647, -0.18296463281608985, -0.04058831296996259, -0.22067238681884166, 0.009589022763906545, 0.1062463730935009], [0.061692766678859146, -0.018119941960280186, -0.0757279217149009, -0.3240318419716248, 0.08501667577509697, -0.03407576117514032, 0.024374593755047705, -0.3616550975985554], [-0.02519164342062751, -0.17886265544935975, -0.1563842197295089, -0.01901913123352401, -0.1456637466620765, -0.06983000324867332, -0.27499319556496193, -0.31425809755130946], [-0.40003312839679567, 0.23687125302312811, -0.47988943676510587, 0.43693712755053526, -0.1514503848559715, -0.05428479454913788, 0.2979410745374716, -0.6920254047083123], [-0.27028638640612296, -0.181177879760399, -0.2175539921288615, 0.08051294435926516, 0.055764865126303485, 0.23886357965250524, 0.07321927303160239, 0.12475605138141192], [-0.13730365169783232, 0.22680639654622278, 0.10457258161749021, -0.4950388357096789, -0.06816701797164337, 0.23086394610632527, 0.1023332930401573, -0.24102846778969106], [-0.5146628367077741, -0.7677641793360467, -0.3140264061357008, -0.5000581788135826, -0.06642595526475309, -0.07667671205616454, 0.10411518158357258, -0.18780876342322114], [-0.5916226049670139, 0.24588386295160972, -0.5870087735754274, 0.011336613612398789, 0.15277352960405205, 0.7875824524782923, -0.20610266799590124, -0.5783850861344987], [-0.04317443792062515, -0.2884998703585928, -0.03535852946906517, -0.0934957117071492, -0.05020919257443677, -0.037123374169885696, 0.35904162532626654, -0.36021750554997545], [-0.16738868547259783, -0.3890424239898329, -0.05294060169967285, -0.10902672596973828, 0.22676178875121752, 0.10916950199512362, -0.3507668358680359, -0.26656952743957885], [0.17211628412967753, -0.5630156148233596, 0.5491645772744799, -0.38480472946717836, -0.012557737879784774, 0.20138881122284874, 0.042241916953090444, 0.07242339741581864], [0.14447765774555538, -0.18776686913574653, -0.12881864094192727, -0.047802775886113695, -0.440474368767727, 0.03155017837599807, 0.56458595542217, -0.3033302686581015], [0.30398523526514043, -0.6314921273176621, -0.4239997320422104, 0.0699583771243091, -0.44684894303372746, -0.07436256372329773, 0.0942845103841766, 0.6621908025236378], [0.06851465134537299, -0.8252048095282264, 0.045621114500576286, -0.15507029515598356, -0.24484785044211632, 0.04891080107073906, 0.4328438635203669, -0.29709409481042415], [-0.12405117116886424, -0.040990241115618914, -0.10995784422984699, -0.22182286033447504, 0.1425105198122728, 0.1612797396228516, 0.19756920534974975, -0.5746652962467964], [-0.027308547985735836, -0.20775414236737286, 0.41428849430734815, 0.044172235963130434, -0.2070467174166095, -0.20009729484548933, -0.07483028867935317, 0.7407057241775317], [0.33963177771088277, 0.4033657202207472, 0.286891335403802, -0.13210336737965836, -0.09073420944212333, -0.03440424957382497, -0.044299255126763984, 0.07164114657639206], [-0.24648800686166597, -0.4512584019719688, 0.23702643724967418, 0.03721855438418754, -0.037785121373829424, 0.12056744204529662, 0.0711482179304853, 0.29418869845465745], [-0.8767343391791919, 0.6186938997956785, 0.01261560124809987, 0.46534050374238023, 0.20164537418543893, 0.7192513594240694, -0.06396422672233264, -0.35040201117878544], [0.048506506480529614, -0.6707177094540571, -0.006813801674305592, -0.23925455191773606, -0.08731209138040222, -0.3820708232925568, 0.20050591762533454, 0.27416224865513406], [-0.08351626370409876, -0.585107529511741, -0.35944337028731255, -0.5239629653820682, 0.07675302407143711, 0.36728661845381, -0.28315338500035087, -0.010232255968165795], [-0.13192562821501191, -0.3316948074986556, -0.1570690296684804, 0.23196789843486382, -0.008316006029393955, -0.2217198060494412, 0.20162438028992416, 0.7631402903269814], [-0.18393859430311776, -0.032803022887893135, -0.023205736755795528, -0.46462705159235734, -0.295387666881105, -0.6653235175159415, -0.3031854044452607, 0.2764229278536884], [0.41740594284134264, -0.007298299913107162, 0.012095512117181809, -0.386853259513665, -0.5693214809201802, -0.18998161088584287, -0.711586827779449, -0.2009111812534303], [-0.22883138295725644, -0.02575188623764486, 0.05926769677280097, 0.11639287906991237, -0.16243088621508658, 0.03831500273930158, -0.1652209231309943, -0.32516056014616823], [0.37270736741494676, -0.21592946491569276, 0.3769312029645826, -0.3518702257648835, 0.01941175278468623, 0.27331214913747726, -0.03561050317856547, -0.13901846096523143], [0.2322768540552151, -0.1174187176645591, 0.3622459535633461, -0.30765788307122244, -0.24222837031675998, 0.03832359242773165, 0.07227503627820651, 0.1315417776011684], [0.00041510602459815966, -0.3143679850905583, -0.21254369194216644, -0.3268978950546926, -0.4410352392144601, 0.19794438414907464, -0.07494086739370114, -0.38575254293610195], [-0.10911903667320966, 0.019914418580706694, -0.14414961567345116, -0.031450873548245495, -0.2976812839190193, 0.1342775678778083, -0.47527595748597484, -0.3013863454374921], [-0.15923390794292078, 0.029348232010689344, 0.3383961273402047, -0.7770691401093986, -0.22492653431827994, -0.15588395818925418, -0.026421237845783062, -0.27303627847954975], [-0.38325801767164536, -0.003335415394798539, -0.6334399618876526, -0.11532303486230072, -0.11223568080573736, 0.5429555617798839, -0.10308822486971536, -0.2733673836712234], [-0.21334236286958183, -0.13725383680902342, -0.055727336465674265, 0.060902427074075234, -0.27729082932755167, -0.013260061259074888, -0.06270804021270102, -0.22772021134747564], [0.043689223595128536, -0.257978340565143, -0.3314339535520088, 0.121165892350934, 0.39843193705228486, -0.2596819217458142, 0.04494970720488372, 0.6469642683931005], [0.018965659118009716, -0.42827687451365976, -0.18698495908404472, 0.030467036246179396, 0.5016785726954911, -0.26276417230707666, 0.04824498071759372, -0.3178985184342495], [-0.06274708616172012, -0.8103885199068437, -0.13448626029180907, -0.12746374351510747, -0.3058630877206346, 0.21082356922201992, -0.06580658042469358, -0.49185708333675143], [0.002397565489842456, -0.30392817470694033, 0.4213836609251038, -0.15459997255610106, -0.1361277421178885, -0.5392458372932117, -0.21472364540596173, 0.2987991477320714], [-0.47666911907632514, -0.12926083377346237, -0.22327441867040534, -0.11182827203628344, -0.2650856474107411, -0.149164995502353, 0.14785195139834356, 0.03759297439320348], [-0.6542750588492873, -0.5443338130881873, 0.06286736615956245, -0.6263061992332859, -0.5807238894357167, -0.48975446968544445, 0.12155006727153815, 0.043338443876196224], [0.08201638377966684, -0.24973102543736123, 0.10170614986452191, 0.04374924604443198, -0.16555154991285936, -0.7727839984676975, -0.06992775385953462, -0.1784174402662861], [0.003820538975855727, -0.18606315181977004, 0.4161404847850338, -0.3554367511454682, -0.1822159131943157, -0.7026443010018238, 0.0033584909598757258, 0.26540204041812276], [-0.6346254483941682, -0.25260693520274224, -0.06384168337359104, -0.022416897320397724, 0.36581179733341834, -0.4390554133460917, 0.6351250052420357, -0.184687821839757], [-0.3422444173116023, -0.24503217769032015, -0.13184333340232937, -0.4914450387331398, 0.06473036665337478, -0.019343395701312067, 0.1657255445392704, -0.26634137728790686], [-0.33306580433436606, 0.025690677288368016, -0.1340572274071622, 0.14451200910822234, 0.14096199041507046, -0.13908368071634092, -0.046083146164072844, -0.8486903160047363], [-0.2074177125531536, -0.37441726494031585, -0.08514923488655667, -0.7377698013404221, -0.12026665562182053, -0.4154327127825438, 0.0032999787179776954, 0.2877942224623802], [-0.04775611574138659, -0.19396540585448582, -0.867969016670121, 0.3685835827288904, 0.29939459120300216, -0.2920411083118, 0.23719459380984018, -0.0725453933533165], [-0.363558332223278, -0.30463782223178615, -0.19971630319522748, -0.514930031410516, -0.4247956682547807, -0.33663636372346517, 0.19342477182016735, -0.30965317264873016], [0.05270831508906656, 0.1665248401766578, -0.22424447378792176, -0.07994169765970346, -0.020996670219889827, -0.17032678690753408, 0.39815083451725763, -0.3075643425220713], [-0.574901771927513, 0.09568846939283017, 0.006427741436196261, -0.12036580995057415, -0.0425942700748326, -0.23912285196054367, -0.32283639061032077, -0.0946180319343107], [-0.21804293327278845, -0.055914724794985333, -0.15038101589639147, -0.381612805963183, 0.14301467828680375, 0.22893571683332098, 0.11206081075669244, -0.5116490700260191], [-0.07253622829183205, -0.07220341083786595, -0.23607674847476245, -0.13592190415109576, -0.2855057720270309, 0.3805857273659953, -0.3195549150465849, -0.3916449800920856], [0.1903833083251704, -0.2895799653819776, -0.21645345763455687, -0.20066866046086368, 0.032183328132590894, -0.03729414430368958, 0.0105068040710144, 0.4316761348767018], [0.24932225194267368, -0.39043857231174184, 0.329880596598902, -0.3076704652426906, -0.32841812402633463, -0.5999193643714688, -0.15106630989764572, 0.15535132107398625], [0.2636678128540558, 0.26498634644609687, -0.1293294907902343, -0.35313593778268276, -0.2771169341012992, -0.5459726603240476, -0.16081470764797479, 0.2553264368495354], [0.0896679066164969, -0.35864032778119914, 0.05592133553124848, -0.0284764479901757, 0.1471507579775479, 0.14507418033723246, -0.3529120728024515, -0.1604220007379332], [-0.23403481990767738, 0.12501699646328895, 0.3126651299651863, -0.6342601267263259, -0.4517990236796932, -0.6918927610105687, 0.06632481389622467, 0.21288962451873916]], [[0.19518248145758352, 0.2234963959405151, 0.149175287147004, 0.027361099585780063, 0.2630973616720437, 0.05915133760602601, 0.12310086021134763, 0.02408510683633026], [0.009908671216158708, 0.22771616881840717, 0.2212419732791599, 0.1458987273434151, 0.062119101395227194, 0.17002985981653446, 0.05227107488349229, 0.11299533446337628], [0.2985336244549889, 0.26587986941451625, 0.10440417301503946, 0.17064019187476417, 0.3290002374907018, 0.38324886709627504, 0.23129292483181105, 0.3674322218016466], [0.17321620701481194, 0.20031274521833053, 0.08231103095217424, 0.10705889578681192, 0.311766290634914, 0.171901712955421, 0.3075944993012565, 0.30755490423976095], [0.21163566345107546, 0.06444737250540862, 0.0537302210306792, 0.06973882894241408, 0.15987447239826788, 0.08130826007344365, 0.13259336911404768, 0.13245965243713714], [0.027670459170162514, 0.07227595543495016, 0.1321561880132258, 0.173046843782863, 0.19114777531441826, 0.08213188434811748, 0.03865945993533933, 0.1867584005058349], [0.34521908249026156, 0.21968876805624735, 0.34415520686391354, 0.22267866085337185, 0.315540528652826, 0.4787511812726121, 0.25369557813001664, 0.24811926744530777], [0.27286418893254544, 0.15851757581223422, 0.46369255525523334, 0.05451051918826215, 0.21098934231088526, 0.18350268469018782, 0.3270806544887688, 0.24267640192240975], [0.28265279974423313, 0.28949065809437957, 0.09140039669064418, 0.5084251797366104, 0.2281372565231908, 0.43707539543433016, 0.1556448209311357, 0.12435929457257681], [0.15583413625346923, 0.15444288666192027, 0.0341818455771117, 0.35296189181663307, 0.08995540908642295, 0.14864001293364767, 0.19761181171235528, 0.025607147262768408], [0.029116269574852013, 0.14762474368340997, 0.2778174161825089, 0.45640715356036154, 0.055736971224135456, 0.39529647406457064, 0.04793578842434205, 0.3208778254223772], [0.19324583683520524, 0.1386670028114892, 0.06788682117314897, 0.06798083116472971, 0.19676920129058792, 0.469000153373763, 0.4469227516950875, 0.3188232287405641], [0.33643578783470174, 0.21666532416438425, 0.264571437823004, 0.33443496884975543, 0.2890361023373956, 0.18703031830182007, 0.4038269495482297, 0.2795797366195949], [0.38324466767719245, 0.23175670171695417, 0.31780271300670243, 0.367197699412527, 0.3019310673319058, 0.2632138713029889, 0.2548990684907051, 0.2871269819471418], [0.2053221917307908, 0.12044870503259046, 0.029534226705835994, 0.10916990820998437, 0.16134082182940743, 0.25451456390076893, 0.13170138513652438, 0.10083159191738351], [0.22094685960936464, 0.16071642592251717, 0.2693273060032802, 0.43109707121685553, 0.41629532027192295, 0.11544250896498415, 0.3077699486590736, 0.10471500847371087], [0.17041666668274028, 0.25108743291583696, 0.18438692930536973, 0.19749783639134735, 0.20512307403314906, 0.25530826709631355, 0.1897274207928599, 0.3831782480341386], [0.21366005595214504, 0.178027523796956, 0.15598502597079847, 0.05612892666242666, 0.04927318817318314, 0.32824353690371083, 0.11032487737361364, 0.3914567596151427], [0.060461467970402374, 0.1999466631861398, 0.111352453644664, 0.07705774479117289, 0.07362341544581659, 0.03822537453163937, 0.05895332451686455, 0.034310633520494974], [0.08265099778412696, 0.15608281721554726, 0.133030758102816, 0.33572908220327724, 0.17548195260770316, 0.11709760831228988, 0.0573493493996132, 0.07993457525869838], [0.22404170770966372, 0.5357430996840384, 0.1159201233139418, 0.39315949738723466, 0.1894929938220016, 0.3419915411987917, 0.10525390652985366, 0.14515823146043244], [0.05034598535394921, 0.31398386838534165, 0.12353573414680898, 0.15011481208752794, 0.02549816959759696, 0.13030075322664555, 0.17701501375625298, 0.15643110332995286], [0.06772579061329345, 0.19985824135190064, 0.16437347305284822, 0.2586466893826866, 0.3365593207451965, 0.10509086554308104, 0.08521138556596243, 0.2616224847502537], [0.19997151916389735, 0.15264115978343928, 0.18892334318895976, 0.27567553341520673, 0.24518254634380418, 0.24191016705045224, 0.1298645836989626, 0.012340513647166514], [0.08565995732432263, 0.27823158663626374, 0.08866945556608018, 0.24477743859191278, 0.19245275449279617, 0.11196248571247079, 0.20871521198225948, 0.08099743266610192], [0.21369922364696636, 0.12650261816814282, 0.261886163213167, 0.4333772505994765, 0.029788883888332993, 0.16806628936349108, 0.0761203716871266, 0.28465637529365806], [0.15297396377451483, 0.11435340882411087, 0.2952269444100243, 0.12259911487472885, 0.13979798780977581, 0.3745401326494268, 0.19181825794282775, 0.3534282668074057], [0.38655607513422957, 0.14665809228453838, 0.12195173262983645, 0.4526648799344511, 0.2718638650689628, 0.3535679701036778, 0.30751148167821735, 0.2876474845950082], [0.39124124020429923, 0.19862866323228287, 0.143261032674834, 0.13720496442196628, 0.32752740759229726, 0.38262092300461087, 0.10228945725082887, 0.33031104383397525], [0.10282244715037366, 0.17735763368840796, 0.2616551486968633, 0.33174500987934014, 0.14691103118403145, 0.18879981502290644, 0.132710910509131, 0.16779433362617016], [0.24178613742079627, 0.43831514701379953, 0.010475616981349944, 0.3739716043852854, 0.28146156080043766, 0.31418851997879876, 0.20513300298811507, 0.1446468432235207], [0.1156042189072009, 0.05568604801832214, 0.13544618967688574, 0.1450009234453143, 0.14721514791032017, 0.19134922742568136, 0.17361249571745108, 0.1055014786233333], [0.4311863390757802, 0.22859418017828753, 0.07572545883197684, 0.2767554924051464, 0.3182144824197832, 0.09631685436133502, 0.4438910813730885, 0.1921464611279097], [0.08898389876693595, 0.05415892946018469, 0.24161065910109827, 0.29338113605426924, 0.04219938415509925, 0.28248050547675374, 0.1898860140084413, 0.23687175038660066], [0.15141318065628304, 0.27158038968851334, 0.23498437493172608, 0.10499484209730887, 0.12786924214078885, 0.23397126125217282, 0.10486034670140093, 0.10200871762366412], [0.1378723596801674, 0.20191462068363472, 0.33631060465028045, 0.2515251256381265, 0.3581252914219651, 0.11632968764764506, 0.037811587806566745, 0.3457967028518941], [0.25767243000527335, 0.1370134604776137, 0.03402430480493626, 0.07365824692812371, 0.24133073022910856, 0.15898717888961353, 0.17385603234223523, 0.16964256793174895], [0.22586919674948275, 0.11953626634633127, 0.08856776393733247, 0.32840355284175154, 0.1892597754257833, 0.17950768442071144, 0.23979243329071684, 0.2743457407581702], [0.08057940380241375, 0.24646244559884062, 0.09753248335777404, 0.30149799610276734, 0.24962968218481382, 0.08222658463771101, 0.15046964558032588, 0.12409345448033825], [0.38191194450889715, 0.2754603741017149, 0.15703805292306292, 0.3040701572024647, 0.32766860874659987, 0.09090350816195836, 0.18545560195373847, 0.1940792752757403], [0.09327153088204959, 0.14788159859831707, 0.22809144599337497, 0.22396026250388648, 0.27596174687643515, 0.07468575634187721, 0.14865376697234775, 0.2907767308344234], [0.12011162770361362, 0.11967488837431532, 0.15271940817965712, 0.11340921965313094, 0.0841813306202621, 0.18573128629721958, 0.16409204241899952, 0.31237805125982604], [0.04410551892319574, 0.15905846382214991, 0.08510186596129245, 0.0958474122773911, 0.14748212564528912, 0.04688284702704678, 0.1400187763635339, 0.21296229838396408], [0.3832890780895068, 0.07467278858591332, 0.033616993651291956, 0.18925743555845434, 0.38234997874933635, 0.1275424645095109, 0.18280229462772465, 0.14286918591501385], [0.03442357005421141, 0.25217009210519936, 0.021482118791391447, 0.2243469994316022, 0.2605081327176479, 0.10058230368567152, 0.32876310566081157, 0.09501236171297103], [0.13198297380803933, 0.224823836158356, 0.044978305932734365, 0.1730898823064414, 0.29218424852815555, 0.07040297975612667, 0.09564570601376177, 0.09806062501915122], [0.11202672495775119, 0.13950211960229725, 0.26912022866622615, 0.14845998430541082, 0.1097244103520746, 0.060992779516879134, 0.11870135946287436, 0.20119752449796788], [0.2707599369715499, 0.3080607970503211, 0.1428870607403559, 0.3048813499442584, 0.06568952852378473, 0.22027087051524283, 0.17439711956486748, 0.10328073031271587], [0.06838472451947845, 0.1311912643608351, 0.19729324979765825, 0.10250474548727856, 0.009689997725573565, 0.1964009290564316, 0.11066072821180871, 0.255937372288113], [0.12537966991089328, 0.31159412825069327, 0.10342685459513276, 0.18198186268078084, 0.14048659406028238, 0.028982624764477223, 0.22601998798497533, 0.2496430347423161], [0.25870338083900674, 0.21195148513602616, 0.2005032086489492, 0.4555352829532344, 0.2827191854916956, 0.22887077858313634, 0.15468963416427997, 0.16771357229496645], [0.07007992865448065, 0.087443416121404, 0.04315888727514032, 0.23066125167952575, 0.1310269951105094, 0.13058956091567936, 0.15229132038066956, 0.25164462596434384], [0.13002711809798817, 0.19325207878209827, 0.3281324274149771, 0.15464188242099908, 0.09734261043133877, 0.20398757797837302, 0.07921986703713546, 0.18709650427014965], [0.22813084140080506, 0.2020358834509949, 0.13078716951874997, 0.2536930953818488, 0.04428034009130398, 0.06770233927864, 0.118880994099337, 0.42276604531447337], [0.4748772633767214, 0.20999088146138456, 0.17894055264041905, 0.022438717967167805, 0.1374852426153227, 0.32510941713285363, 0.23127859379332175, 0.19669333099920566], [0.16192217742242596, 0.16195588512154976, 0.036721146748883375, 0.3470774416369575, 0.07229198104489923, 0.1494838214801632, 0.09290548923331483, 0.4893709940518312], [0.23660718564356162, 0.275652354892051, 0.4188052550549623, 0.3541352317389572, 0.28283495035823264, 0.5123947421520151, 0.3609609459874512, 0.22689966846279458], [0.17025123881278362, 0.11418850537262565, 0.2661712534560169, 0.1389176657750018, 0.13588175736868505, 0.5305282876605527, 0.2665621675427802, 0.2971084408192242], [0.09024809987445415, 0.18781103314224032, 0.30356463888641333, 0.10407665601389723, 0.03880811516681524, 0.1511971621531571, 0.08189243808636106, 0.08919200691657389], [0.32484925777591817, 0.30973338606060213, 0.08013451191853752, 0.49729809986237433, 0.22340179909899419, 0.43078178606830886, 0.05060320460990019, 0.04546505518532527], [0.28548033162338005, 0.16191163019419527, 0.14365538463849994, 0.25462134575573814, 0.0826257756134036, 0.09612734392856095, 0.203863268556056, 0.4952085512610336], [0.16135837241336315, 0.014490282240447714, 0.26663260741164085, 0.2501729789487185, 0.1459388453281621, 0.3113293459805471, 0.14691426834077334, 0.4263946920655312], [0.1036728066953045, 0.07668435164947988, 0.2332153459578085, 0.09765913228431072, 0.1341961348823603, 0.14835868829702664, 0.14010907528608632, 0.12739258857814117], [0.11652235317134017, 0.37176653112323915, 0.11108064441068088, 0.07079746265954477, 0.10190085191404322, 0.22610059070350433, 0.08172267544759051, 0.21717085682258525], [0.061698351182171145, 0.1867468707945934, 0.04093590060814535, 0.5234423904690494, 0.3725318600901126, 0.20363526023388548, 0.06751705690909117, 0.18433808047105413], [0.12349663921319395, 0.10383117357024145, 0.06812777161402647, 0.24165909200021005, 0.14633493614599172, 0.3699303007974183, 0.15253293481448607, 0.19652597436765648], [0.26936840584790533, 0.08151565906070689, 0.15880257175532822, 0.04813020826323013, 0.14965861830318805, 0.059627149871920686, 0.13509394018730886, 0.10995739918728091], [0.11273261301684252, 0.6181835529571841, 0.09299004959443842, 0.1829681702161706, 0.1634894075595036, 0.1888940383607986, 0.028919315699561677, 0.15140834932411434], [0.12040734511822421, 0.30684380464090677, 0.07759037477349454, 0.13692195555513864, 0.046089729645424515, 0.1758841387456815, 0.3607883782698443, 0.2638140727646356], [0.0722617813095267, 0.15881573798406093, 0.2207845347636605, 0.23597703878632195, 0.15368054241163823, 0.06740508569322987, 0.17809430839985774, 0.2787672132964782], [0.02817650525833545, 0.0638571085509729, 0.021095188695768558, 0.07228727531554761, 0.1694332935362257, 0.07590052391509908, 0.176364757726802, 0.1500286485525843], [0.20668691739773049, 0.20583085247902413, 0.05882856794881194, 0.4972729719105726, 0.21240114501599008, 0.4041398517434417, 0.18420277578308286, 0.07323807753772274], [0.05305117498625407, 0.1445264263961114, 0.31648742328137114, 0.11502749056573787, 0.17967350066606852, 0.20589415545412476, 0.026910232236056684, 0.22759379673113228], [0.0849221401277533, 0.06488372843316109, 0.3174198740113642, 0.13136767290354606, 0.18651571851366266, 0.1754387230269535, 0.11011825368732922, 0.261202026833091], [0.04898715280063575, 0.023142788868453463, 0.18303210787640573, 0.47732112629859086, 0.2620854888901267, 0.14718718149099042, 0.28843676582157496, 0.08526798294144469], [0.25590489532969657, 0.2363511310814568, 0.15349096236072107, 0.1950119353926013, 0.20875656999156358, 0.08777934043981195, 0.42300511867580837, 0.22671297500407478], [0.27296116553076116, 0.13608177503871183, 0.029330246360762882, 0.3358273777053808, 0.08218299225451593, 0.2083474895238953, 0.16319626734770978, 0.38261114819265984], [0.08899473715406801, 0.32096263185496005, 0.32459069597118534, 0.06581003978599696, 0.019657639548290848, 0.12118619370814619, 0.2583262845035526, 0.14171379759467248], [0.2799823838646451, 0.21518335709123745, 0.08111912909332628, 0.21269638814324598, 0.1090116422179133, 0.23818964879781657, 0.12543575131609555, 0.1899554236900544], [0.10385958813418834, 0.19507978252815186, 0.01617560283566926, 0.2071928277280883, 0.24360503913397707, 0.27207266804422947, 0.20703450259766482, 0.29495681026048637], [0.15629396229827316, 0.3334507025602371, 0.1790858329932062, 0.3106623805854487, 0.2665468367126321, 0.06582848809347973, 0.20809542907607048, 0.19001973113477796], [0.14776301604718206, 0.11071415082372013, 0.13030324154258754, 0.34002489384456536, 0.06697588336162376, 0.3897363992728469, 0.11395835837217261, 0.32929455392151086], [0.18124110095172158, 0.09614358523257381, 0.3020288031753393, 0.11682418012462971, 0.03078441150771362, 0.08515514831483313, 0.05926847967311307, 0.06724506491000534], [0.21852472550738952, 0.343253893480831, 0.15338533731693593, 0.31927972816231376, 0.2598659372906415, 0.21199632948359615, 0.1489308854242209, 0.10827799044315643], [0.03168212904309916, 0.2244227585976305, 0.36883999816699414, 0.07243261675166321, 0.24025256068668951, 0.05639071130425788, 0.3918985504718514, 0.16083990178795057], [0.06912796346841664, 0.22150044195021493, 0.21199224052389223, 0.7301269508297424, 0.1636194352415113, 0.3929304911282704, 0.05623452114993391, 0.4327006437478157], [0.10194348896760419, 0.06044335033303673, 0.12061689275893507, 0.12425402222672892, 0.06415142981490969, 0.07849049125160376, 0.4181706123253008, 0.20248549438948615], [0.2068169047964877, 0.22524836399198075, 0.12798074556103226, 0.07042642146537464, 0.13640900836777314, 0.04136429748977433, 0.07528745663245115, 0.11506625911972904], [0.2583206807453707, 0.07485140658789412, 0.18953430399770668, 0.41655171919612405, 0.10160774667957505, 0.22347163258467515, 0.07887445235836171, 0.35053343384065017], [0.17501111721529758, 0.20958676011606106, 0.23972347114995007, 0.22486519122753537, 0.2736458534287117, 0.13348713654905422, 0.14814744611427624, 0.2637024603715845], [0.06603993238096464, 0.39050299326983196, 0.22024121810794745, 0.07166211331597272, 0.25361331064672304, 0.4488042462198853, 0.1627020803660305, 0.5276322284998383], [0.05743511676454066, 0.31954671558934483, 0.07937580734150564, 0.3699255254583981, 0.1049274563593062, 0.07001409239619552, 0.22509103954165122, 0.2504324717095], [0.5192344150963755, 0.1951576625071583, 0.023477429410443177, 0.21112226378833454, 0.4241713680856355, 0.12791116773797054, 0.5202247158306836, 0.15385215733518856], [0.09439317912660332, 0.1607274195560525, 0.05204941915175312, 0.033454241663858506, 0.08469921428083124, 0.07293724348206813, 0.03541553790624047, 0.08753228330742917], [0.2239216678968951, 0.2984708647240514, 0.03371333157265368, 0.2823041421987989, 0.3053972477732538, 0.39261086171279536, 0.09599407086075223, 0.19622143468772452], [0.20127057407555413, 0.27123997814403367, 0.2552661138312453, 0.16366730569836435, 0.2869099602449173, 0.04834228406558528, 0.1403988331833296, 0.23979208516411202], [0.045275869727304435, 0.3675952283078738, 0.11077427258566643, 0.27242416831696226, 0.08628983749121501, 0.11475817914676116, 0.3070900863527521, 0.38726770170616015], [0.4248278770516904, 0.0986522717606085, 0.05965506327332383, 0.3148639937129477, 0.36787330393189405, 0.0900604109984951, 0.3756808592021503, 0.10817332814330043], [0.1449350944757061, 0.062086555540722836, 0.05500958973794731, 0.08558445326635923, 0.15319294723184443, 0.0855576617753458, 0.33744315647192974, 0.016134834024406356], [0.24247319639956724, 0.3172177859601775, 0.26161985967274165, 0.43337996802249595, 0.12034305106661175, 0.0580778018003899, 0.0598415316602589, 0.15657585408364283], [0.16585112840767896, 0.3954094746024088, 0.2610822941600293, 0.3498045881896429, 0.27156220992867713, 0.07613044270765426, 0.08948047248981313, 0.1292930342344044], [0.214866314975416, 0.3245955685350643, 0.16069973653158423, 0.1555367359545528, 0.22136709577094907, 0.21489708300849564, 0.06444448501400346, 0.16684719558495292], [0.044632754690026345, 0.11561646917491862, 0.18249582396334138, 0.03215663638185362, 0.0856336968796674, 0.15200858569276846, 0.1323008515432876, 0.5624341478802422], [0.3797995987035117, 0.0766465057434539, 0.13303252892022713, 0.3018146343877849, 0.3811797643109644, 0.0856154224293485, 0.24838209157737717, 0.06316394240390172], [0.05770577519355867, 0.0836648214392278, 0.12169310567398572, 0.18779199958818737, 0.34400292941661603, 0.0735043439716168, 0.15673636360883533, 0.23015331617329365], [0.04147082796319151, 0.22704242054422735, 0.09675244493802054, 0.2201880923570693, 0.3073465241961268, 0.07012424424641524, 0.09066313379025337, 0.07672108199472541], [0.1898827642101883, 0.1111400294851312, 0.22439846870680213, 0.24199516855187303, 0.11103503475854919, 0.09540366949206666, 0.16983921899955115, 0.40043748286124503], [0.1422474852083939, 0.08216396729453936, 0.3042211256237689, 0.06858499496350191, 0.07699807821918428, 0.23798138411173428, 0.29605971362485844, 0.30159654380758827], [0.19710351134386966, 0.25079564625112, 0.5350685786615293, 0.09762499775154952, 0.18560714191269612, 0.11078080148846514, 0.1651087722307726, 0.2585431721801495], [0.2649782851624395, 0.2796264794436403, 0.10385934002806861, 0.36549251733872606, 0.2742627369753127, 0.3479067107996459, 0.10177765848134188, 0.13161820783641223], [0.1937229586070877, 0.21365054847144138, 0.16006152357415296, 0.07351156990291358, 0.18436962852519387, 0.20483747509784753, 0.26681449499862314, 0.11047586176266318], [0.03797336723122684, 0.08814128488882855, 0.03716621151911129, 0.04813318141466321, 0.08636350952820362, 0.15776123471876524, 0.11027131538715755, 0.08572546740484205], [0.044389036319058627, 0.1678514058937079, 0.2995086908804114, 0.21741287669375875, 0.09331170894573368, 0.0568614499899928, 0.33282017788086476, 0.10283652096545579], [0.16327931487580977, 0.12450955545904256, 0.1336659643138197, 0.20593410384399757, 0.07548830028835915, 0.24539185554743942, 0.06967848704631145, 0.3629520652856663], [0.044126492538451766, 0.09737464446499318, 0.1946571595482327, 0.1719651382317766, 0.08102609498440322, 0.32205574152451105, 0.3309500440435119, 0.4895868731916028], [0.10726349794880637, 0.006381184646478293, 0.11437056107614078, 0.3494581574434372, 0.08070887667522988, 0.15488230638651837, 0.11573760814426488, 0.3056384743121214], [0.057352236361948514, 0.2174477893457511, 0.06628155991956923, 0.32192020013484746, 0.018143362621908056, 0.0775510957710856, 0.13451244084931377, 0.22078840846224562], [0.32993955642146083, 0.23930970067569787, 0.04215524401562652, 0.2750374904484889, 0.4485534417746352, 0.3298430913254604, 0.31253053336680403, 0.2394564868784445], [0.3181293406720303, 0.14065317395881294, 0.24285952467046484, 0.30232829680893325, 0.15218171940795647, 0.27481943941978776, 0.13838220983035485, 0.20567711067913289], [0.3450928774797774, 0.11865524267436403, 0.03330682738542421, 0.4338667519091799, 0.14527658810173705, 0.05117080033335501, 0.05410799768005169, 0.1371089388997358], [0.15577729775418328, 0.1583053733783768, 0.16436359448802845, 0.08880995894196723, 0.16212298681974627, 0.3662933116468107, 0.049580375289024765, 0.42637514671112703], [0.37950942447153435, 0.1401954313401411, 0.25948368045586223, 0.14452395303910098, 0.11406008817026822, 0.13345672944296805, 0.2345588837170572, 0.05331276947668586], [0.15528633014835727, 0.20836295111838296, 0.32978270436451385, 0.2368519113979907, 0.2863494920474046, 0.1130220503694608, 0.16024811719490942, 0.1561742735537963], [0.1431468375670839, 0.08679906780443342, 0.1314519429430379, 0.2028112777690079, 0.2123103902273101, 0.13236629309766348, 0.04520442836925874, 0.32685488187606027], [0.10762810441107949, 0.24061712839895694, 0.2825530108051349, 0.358684903608256, 0.21064900891846636, 0.18839888467466193, 0.13743586510444297, 0.19321137186760295], [0.14507469424712785, 0.09847690101288965, 0.30994517373402475, 0.08537455311551878, 0.15104547721654626, 0.1625433903114054, 0.09475723780897007, 0.21444711365347277], [0.03660598047084835, 0.1850278562175453, 0.21396193840604324, 0.49067870319617307, 0.12998389912264335, 0.12595016087419503, 0.06555525408209291, 0.16366253736157405], [0.10983257004948484, 0.31279086950302354, 0.16184020593288373, 0.5650314324626198, 0.09601010598211054, 0.3073456659551304, 0.01463502710006926, 0.3499854137254493], [0.2799645385056681, 0.03745427378171688, 0.09182009512770913, 0.059056976930457195, 0.2535697136455005, 0.11002520591926401, 0.1357575355742021, 0.19470473286124015], [0.14104923029556213, 0.13834259653075073, 0.26236718100004525, 0.3561787998448897, 0.21001352179695643, 0.040659772228917285, 0.28715797244185487, 0.34486253472963657], [0.2540232825186208, 0.1823684119004562, 0.22436362490227899, 0.2312272372443313, 0.09343724460815728, 0.27541276439755297, 0.1589029602874244, 0.23851774755733424], [0.1461191715346688, 0.11432666216344023, 0.2763659633404007, 0.0973648254317604, 0.02970497456499018, 0.2485294083375879, 0.043923852424224585, 0.2285773492708159], [0.18258508816009503, 0.10299845111792516, 0.3806866513088021, 0.18872772990114445, 0.1493347473335805, 0.3943152456547757, 0.2552931526136754, 0.30831172250602173], [0.05683415514427887, 0.08408749045687383, 0.2111150637510005, 0.21518386051268718, 0.3947727680550777, 0.09432975085152703, 0.03385400575234149, 0.08732094259106289], [0.1461058160339481, 0.22183329237412044, 0.11452169583765516, 0.13258910789364278, 0.2077644559852653, 0.2281398525099274, 0.22939217771327675, 0.22760099318958552], [0.15309071282634948, 0.14346228736363464, 0.287175057483887, 0.05877613393435061, 0.05279643658940791, 0.08642128739269331, 0.03424932852325968, 0.25231342942354934], [0.18694508959203693, 0.18880705748092189, 0.10708376056542775, 0.2103785494884237, 0.20352795841783528, 0.5735337893442317, 0.24301277667313803, 0.164991129163048], [0.5082708427432382, 0.1290092461792423, 0.3688139630323312, 0.4686641956697061, 0.02306376245909487, 0.25652354060873667, 0.259192227217632, 0.08155849692837608], [0.19671690453721613, 0.17875998787367597, 0.15042170487441922, 0.25495491307692897, 0.329991671885509, 0.07853653728240123, 0.16623816262165508, 0.31056245854335124], [0.0965186634664026, 0.16922176078724027, 0.06715201307432767, 0.5485292158860915, 0.1067380875415444, 0.2870478601307532, 0.057908766215078976, 0.3526483638731929], [0.15015038829365368, 0.16482285512059025, 0.37541313641523366, 0.3792057834109713, 0.41640018281231306, 0.15369954397270058, 0.21923026733991877, 0.06579151391822725], [0.25123063270440105, 0.24787863864371806, 0.14293285753740684, 0.2058895760505295, 0.1541866035168179, 0.1959316352133651, 0.17481684787188007, 0.28384939083671396], [0.11453944520854195, 0.1305846708701308, 0.23275418577082801, 0.17676817649961585, 0.013359954693519959, 0.286478430101185, 0.09315942784398264, 0.24782390536217538], [0.5597986521483315, 0.2263879618590886, 0.0775925506102797, 0.3091508179763524, 0.2957141320784885, 0.3962016706152593, 0.26742413342975746, 0.09552175490926448], [0.1095561421577995, 0.1782872156320721, 0.2793278366355384, 0.3806578481410173, 0.13644694174722058, 0.23895321289278443, 0.08718496512456764, 0.26113534978037756], [0.2723756524540301, 0.13203491255748584, 0.4025180325152433, 0.30895910115579717, 0.18794487975842877, 0.07771209071850232, 0.21790575377431284, 0.1944251984589719], [0.13179802991028614, 0.48666955233187775, 0.43542329367261273, 0.05934656507231489, 0.026237257438982618, 0.16635344726652768, 0.17444856867508435, 0.10363407072996401], [0.14983509901905634, 0.21788595613910336, 0.3544895997517486, 0.18554534655499685, 0.3393824995039801, 0.19292090683275545, 0.1280661210695005, 0.17909362724703398], [0.17746308016341045, 0.18988160134673482, 0.05009239079650595, 0.33169155066978045, 0.3280521460727077, 0.17892818658859266, 0.10945875353252056, 0.12943874022059676], [0.11088092264596511, 0.4765605634624447, 0.07939353463899006, 0.47870151733397914, 0.14534610926413116, 0.2721088469515338, 0.23225906582083633, 0.178249663670312], [0.23880841967222302, 0.10377297291897467, 0.08095734916954966, 0.09109848338799043, 0.09251308171860671, 0.14539134841906193, 0.20049665151638058, 0.24697725184709968], [0.35655623108671575, 0.10828134373416831, 0.1292193462532625, 0.2171782096640761, 0.2235184509238996, 0.21526993073544834, 0.2482511414592315, 0.07911337303597779], [0.14864109753380159, 0.16972964511417513, 0.349013901168176, 0.17297898232258194, 0.12715020196589324, 0.362788561842569, 0.291688275951929, 0.1935955295908465], [0.17051488476272408, 0.2654944329352909, 0.39042541972360784, 0.32829274771969097, 0.20911459184012166, 0.2988811388610325, 0.23186974607391989, 0.14806557737425102], [0.10713508348886928, 0.1638997828131735, 0.10402549730814323, 0.29915271308439156, 0.14667354255310566, 0.05376284639613403, 0.22101720715649742, 0.2757563107110336], [0.42744455112625196, 0.16835962833500603, 0.1501597934261089, 0.2654100590637092, 0.34715097698330927, 0.1234113897117147, 0.24066385536512136, 0.13924673281702601], [0.22844976732697506, 0.0012225140986668575, 0.15185789996966872, 0.2978836795830877, 0.22546404895777705, 0.1975024774677225, 0.030688950946974037, 0.2357517895287644], [0.18239443989807255, 0.1159579868055716, 0.2151413995773434, 0.39966720124044147, 0.31692480349910146, 0.3463505904399382, 0.10249781527945617, 0.23431678895178085], [0.2076080086104866, 0.17727515660717075, 0.47295264498219447, 0.08486397949628886, 0.06975878578423735, 0.20273006588924275, 0.022532892732793207, 0.08527941338171714], [0.2909721075054363, 0.16550253254315436, 0.24898388663679216, 0.1574309098860135, 0.17989928158494836, 0.36840271080932757, 0.04986619598633974, 0.23299101334441766], [0.12034176940018618, 0.2035143752079676, 0.17676837160665404, 0.3775413446188007, 0.012334368949291977, 0.2088216882458295, 0.015766861860806097, 0.20250636854857312], [0.17676155662639864, 0.07395733666081511, 0.1909270040525495, 0.372219782665695, 0.021660654197884068, 0.019481149506142242, 0.11857808188310978, 0.03514869729939047], [0.10164860408505204, 0.09497226288578939, 0.18073508778264133, 0.26957419747679584, 0.0972143692330714, 0.1869729778856131, 0.20562948061530628, 0.36327964742054436], [0.1681491978437388, 0.12772918079693477, 0.07349294630694476, 0.07155403424588784, 0.27638430533170893, 0.6272929188626026, 0.40912726049409726, 0.25735186670396926], [0.17047771343183885, 0.23328640061828093, 0.18422358955025803, 0.2606889330514339, 0.11599008258069046, 0.36457707233537423, 0.17663323271938408, 0.39262001037070837], [0.07694858156158628, 0.21259724193031196, 0.12455897806265727, 0.21121763139061983, 0.21624963577087317, 0.16348017761596537, 0.2684034389925269, 0.20641250230194275], [0.12238716302750612, 0.23077398156913986, 0.2705291638943485, 0.4547805921627973, 0.28148053715910304, 0.14690565326290483, 0.020796127568564363, 0.19562123014277466], [0.22355525783231397, 0.22624614114750688, 0.11951886023854728, 0.23526871755040948, 0.04598593615234296, 0.1405745670129902, 0.08843611843962121, 0.15111760131612237], [0.2801215179137672, 0.14886354377438502, 0.06242162042248263, 0.2695843696056397, 0.27856148362065203, 0.02090824077625566, 0.41296044710237173, 0.14587632456546756], [0.3232703049419347, 0.08577064149970852, 0.14314290187593107, 0.39252135005633043, 0.28841816356101846, 0.09189376341166297, 0.5267605960609265, 0.12910002161958595], [0.33306920095617876, 0.18295754904829137, 0.18799439993571532, 0.1973412940635248, 0.034777913998352616, 0.16929635239547058, 0.1798953608603995, 0.13607625402321655], [0.4061719973528439, 0.3092974990959047, 0.038394381354573334, 0.21999716228112276, 0.43961715410469104, 0.29435214621797967, 0.13276553955307976, 0.28545935850798937], [0.13280915427648432, 0.3622244954286742, 0.08717086099030125, 0.06976781656509828, 0.10430814271387089, 0.14051789844588758, 0.36084296287441514, 0.15547225232620426], [0.1759477421619427, 0.12918614064731498, 0.20099365328128396, 0.3033639621393432, 0.12324481586243671, 0.23399824401851585, 0.10193515907098695, 0.19536567829520524], [0.13173243613819705, 0.21265183853751946, 0.09240739124888807, 0.14512509898590445, 0.10263859878834278, 0.2864023820650135, 0.12311257684312964, 0.384580126439956], [0.09375599744230498, 0.1455152732278406, 0.10772908564135014, 0.22766747585990338, 0.2255274020025124, 0.22768576747380834, 0.0754467521243039, 0.051764968740373146], [0.22655280681118303, 0.12418218168157845, 0.13879251848530055, 0.26870773958827726, 0.42005818340143547, 0.12332315207310228, 0.19266667028333334, 0.08758179013027384], [0.19842644276753155, 0.16614923363842957, 0.2820574886686469, 0.44969528856975677, 0.2664884573863774, 0.07827934179958275, 0.1251801479256869, 0.23275143538954665], [0.3433201641711185, 0.05251985217551107, 0.16824756196814325, 0.09122585570089155, 0.12008704970957709, 0.14205461940508607, 0.3196288149626309, 0.24055226567856097], [0.3762214001360041, 0.07666683060999857, 0.17815635752253622, 0.4112134298775203, 0.39671000266030615, 0.22772150156344176, 0.032660034786078415, 0.09190318873366385], [0.08137784253245778, 0.23396581757484639, 0.11438517228560378, 0.11483977359592841, 0.20239011131252768, 0.13440271367308482, 0.240015439142889, 0.11432331520739492], [0.26812534382599335, 0.5573203858968002, 0.09549792300773606, 0.35844861519409743, 0.15503916196385173, 0.07633528645995723, 0.29879441837291026, 0.1848196908115645], [0.0888744866373409, 0.20100083057045817, 0.13641968397021068, 0.06344913031104488, 0.21075937370926479, 0.20622303644619508, 0.051315273414079085, 0.2658435981576197], [0.22349623527799775, 0.31678487670592415, 0.2019678958673691, 0.0742441035255719, 0.1218201065495535, 0.5829535775370313, 0.21545620159981163, 0.4977196346637498], [0.2616578768257626, 0.2847112258847984, 0.256072872101417, 0.13813003845661526, 0.309962478449558, 0.058782823606154846, 0.3734820001477155, 0.15486658179020846], [0.2326337055128978, 0.09697897200265321, 0.2159564301445382, 0.4965089034160767, 0.3751156888849683, 0.12525799757363085, 0.37760760294178297, 0.11350583869879781], [0.10965528327640246, 0.18141948201016037, 0.228003636781324, 0.14768080666397182, 0.3009797329520104, 0.19990235543150975, 0.050916622011004914, 0.3223232542106539], [0.2656929957194562, 0.20407246024918674, 0.28818894224384434, 0.05426827138601508, 0.14636472820235455, 0.22162934391263542, 0.08848081396676141, 0.30097338567444043], [0.03478316363187555, 0.38724577110023073, 0.05662004507521541, 0.10271239159088766, 0.03480849589797866, 0.13113001968091476, 0.2024512047846834, 0.15276470366638958], [0.2988269337586808, 0.06206117215230561, 0.09637451942471553, 0.2533111846054788, 0.26447928961602013, 0.1134577975770178, 0.3320852873392151, 0.16167794475565325], [0.2011980998863142, 0.19870261620132448, 0.12493674967851508, 0.2798064802646096, 0.2527019319646686, 0.19444977253480286, 0.23459146890739782, 0.09403558321311474], [0.15405402631702272, 0.15909999236859945, 0.11102886331091069, 0.13108034236034927, 0.047914001538025705, 0.029101154399771043, 0.1359872012171972, 0.27957206874829665], [0.21232123035484246, 0.10962455363593102, 0.12417496759624427, 0.26216798798852664, 0.24638265244453272, 0.08792841963396389, 0.46095587457428644, 0.09554886607372144], [0.10143892834941236, 0.2096291363009372, 0.2268509204842033, 0.3294114934575612, 0.3123380436823163, 0.19658628120633323, 0.04151814444343321, 0.10007854339104656], [0.03943021555868212, 0.08611514212732535, 0.14243595525608518, 0.27589358919000084, 0.3461524161651923, 0.17841209423771756, 0.10179562892768285, 0.20258713002187792], [0.1351791220754441, 0.21639716593101546, 0.5071050610648307, 0.1994004173715851, 0.18724593227694622, 0.07325980302591574, 0.03677094583716713, 0.31678777729775465], [0.05920510379629723, 0.2803522690268441, 0.21752548371538027, 0.16504096861496137, 0.08730234175811477, 0.15071842465460406, 0.16928312985748095, 0.12814599248446673], [0.03461116640758226, 0.2569615228975417, 0.012291020843562865, 0.18828707382393606, 0.2377058493899556, 0.10699204209550155, 0.12672650698982962, 0.08064367997885002], [0.1312645183221791, 0.05688432732379395, 0.13955034793408042, 0.16042126278284496, 0.2050391679788234, 0.16839089448590153, 0.012671783677856003, 0.014877564606600002], [0.01118676898035418, 0.18919537994365443, 0.12974313924637515, 0.07777301113421141, 0.17773832208091195, 0.14830435719758062, 0.21058156989293672, 0.02311358705976227]]], "banksy": {"0.2": [[0.5785114042734981, 1.546029544833812, 0.35508726289369974, -0.67627399780628, -0.47821847737158196, -0.8223678067806073, -1.2203885127219138, 1.1380949881441356, -0.22264730077064632, -0.575874187104538, 0.5275552354839921, -0.4613519570959276, 0.06924465189685626, -0.16244863738018445, 0.3540063289213949, -0.20049408291564935, 0.033076412137026334, 0.08749743199462315, -0.06291668348222705, -0.4023213618432177, 0.1833075522250422, -0.2868177903795278, -0.12301917912446185, -0.42748078646495], [0.8140011977918727, -0.9603941950670484, 1.7635019781535828, 0.34177864572787714, -0.8383159671065787, 0.45407545829266166, -0.11609744410523189, -0.6626043143923502, -0.08828556212257653, -0.2911928058165917, 0.11549214732587511, -0.061155157066472926, 0.09286725972757622, -0.20852944368292559, 0.4187012676040092, -0.01585782758857925, -0.4046289722810626, 0.09835816094325174, 0.11199445600723798, -0.17190601850046092, -0.3060464167057609, -0.04987317377189991, -0.29048624865509687, -0.22092629079264064], [-1.6078854028121654, 0.11523788254384189, 0.3174977386245499, -2.0673074684242287, 0.5685698141632951, 0.6691146197888901, -0.4904800799395048, 0.11977662696878479, 0.002340445254850598, -0.49383997101603283, 0.09615024526212124, -0.18662345945122713, -0.66713714770075, -0.6754816181955, 0.45036810963206997, 0.5796021868666746, 0.27724126045952124, 0.19658278578562144, -0.17157946526567666, -0.12381316264839798, 0.34377184225021723, 0.4057704885546985, 0.132785747074186, 0.37017649172460526], [-0.14408638353281752, -0.6217370302626518, -0.31558662288624023, 1.2862913912347567, -1.2977782867667889, 0.31558955442513087, 0.1206357018784383, -0.6051052564741034, -0.23679957880550284, 0.8425805780218505, -0.32661035919717707, 0.2912224573372488, -0.23835282861782012, 0.41159027628896316, 0.03867500903331345, -0.1321618146257965, -0.01881843790507013, 0.02782802470199595, -0.22520114347122042, -0.24740350645245124, 0.30180959079771463, -0.045873070636531614, 0.31319009275764415, 0.2310706828508943], [-0.2847013814720652, -1.096828905066971, -0.7931855274440175, 0.14587974418017868, 0.3562140678892363, -0.7396387146285693, 2.804877893693262, -0.4837078202216265, -0.565481260410992, 0.25263116858547785, -0.10895688818882666, 0.3688589979864826, 0.47725662633497384, -0.19014221761980662, -0.6839901231648392, 0.016008817273209484, 0.07194670006373284, -0.3218583279143457, -0.294568867994215, -0.31994685136490825, -0.0680257535815351, -0.23946900366608398, -0.10057547636480567, -0.1757071693262072], [0.215187666665456, -0.11020079664028412, -0.3541559355590628, 1.2431757547854319, -0.39341246598120355, 1.3351601087225267, 1.0156543955960564, -0.9040187555904028, 0.03507224546894664, 0.11324960682734851, -0.6658610839673845, 0.06957366832668553, -0.28651900190277974, 0.29193911876822637, -0.9560483990391213, -0.1849632676969504, -0.36266713097046843, -0.30170934840526753, -0.10422328688444822, -0.11913507404310805, 0.008120367309923228, -0.2377089392811996, -0.32266899855890185, -0.04956138360159724], [1.0149157032666623, -0.4642550902158917, 2.6908575335206515, -0.19606167669945854, -0.8234581797111191, -1.6806903185310567, -1.259849271010135, -0.49281964088079605, -0.22787250865023412, -0.2605363148974315, -0.05063207652882317, 0.13528715151865295, 0.17981007330568144, 0.19977992335993194, 0.24469711512693948, -0.005404817743426745, 0.3875346490903052, 0.0776974698675312, 0.41031390010127294, -0.022659951439774166, 0.3109993327688656, 0.6098565348558169, 0.18575367123484082, 0.09299097806666852], [-0.7758015104650549, -0.9519961360223761, -0.6411188090119043, -0.043100403889442286, 1.4009388775680747, -1.4876093416569574, -0.5669688214029418, -0.8228680794163418, -0.009311594340145692, -0.35312224561860683, 0.25129915734530583, 0.12878257118389863, -0.27814759371413567, -0.2646258949567603, 0.09322708427612904, 0.10703756222786905, 0.21659777216235926, -0.07974316915533271, 0.7004398229213269, -0.3495478842766435, 0.05643180928456344, -0.021082085464926063, 0.3592623671626395, 0.08034621971771554], [-1.2311769576915186, -0.9835809656847032, -0.84539407117066, 0.7448938797063075, -0.12827346507456816, -0.4047445151459209, 0.5198517914867975, 0.2689053204356157, -0.038404809281945965, 1.2830327407264341, 0.3349134592413069, -0.13544679192718678, 0.415872380815273, 0.7337995614400021, -0.4451220823376185, 0.06643904530358449, 0.23972315428013286, 0.25735154835547797, -0.20314058534264426, 0.5327787181453624, 0.0981845832767295, 0.5207964274481314, -0.0460735593200819, -0.1945257617214258], [-0.09360223225175465, 0.4083722275241123, -0.7702611119304903, 0.6683955119282684, 0.4866930999386761, -0.28795551968357075, -1.191095249338091, 1.364774447389356, 0.4769991656076599, -0.05062969306902985, 0.7458099190147448, 0.030088986853726293, -0.4872784302608897, -0.3004709424636223, 0.3178878238700328, -0.1860552803719747, -0.05988320553014289, -0.09023048581716782, -0.3420142107630111, 0.23058668392888387, -0.23826889872792711, -0.09558273923074705, 0.05315149029172413, -0.42394481202121603], [0.1860143042064308, 2.657681201768399, -0.6004078035456245, 0.8607560644240878, -0.3519147891801291, 0.33089967612031235, 0.7274152516529095, -0.6861727672115875, -0.6968909814635023, -0.2536536507262653, 0.06726043589625814, -0.615090313126877, 0.22215555245338395, 0.19181521594419026, -0.13888824736404326, -0.287173234318565, -0.3592514350436903, -0.10777882430963809, 0.2493072105745737, 0.43166524398406686, -0.3215860115114635, 0.4315159220005245, -0.30073642399488026, 0.26202223183692014], [0.014921385162214952, 0.2200054657867914, 0.1441745541025781, 0.6420062278418226, 1.006563800625904, 0.8698281283289208, 0.1943669641339499, -0.28654110746996764, -0.5389960027497978, 0.5067641581176165, -0.053435818954336585, 0.6985789533364476, 0.2604266586076201, 1.063296144602272, -0.3999677654119657, -0.07497029139481673, 0.028501130947446857, -0.13083399775550894, -0.2602097598526896, -0.32336407566071723, 0.021807753740179125, 0.5890188331895143, 0.6426121575460205, 0.2572490331538386], [-0.8917374835777102, -0.5360449356640863, -0.4791793818786776, 0.7156045683440246, -0.28620582072890605, -1.0592655818225114, 0.5339218940161913, -0.6896593360683967, -0.15900849592955418, -0.17614243517600997, -0.8978354729838075, 0.7673657403594679, 0.8305510410522704, -0.211574964256203, 0.7163683372524553, 0.37436837108703225, 0.3667843047288463, 0.06991581773811258, 0.21715824837218914, 0.19457375371210756, 0.24646475975671162, -0.013543621053816093, 0.540718192158439, 0.16607932253888946], [-0.5713270830334354, -0.10656689888764981, 0.4934096225937134, -1.9257692741051147, -0.991457943583151, 0.2583448065941615, -0.3917590876695668, -0.7438595143279121, 0.5350544559468873, 0.027904035499846443, 0.47834520000407854, 0.4384526421754226, -0.16886139628115843, 0.3861569207948643, 0.4103185367184496, -0.007836718459157307, 0.4773692747196916, 0.10875756723571949, 0.3463544623036017, 0.2582584752159172, 0.2778621969252691, 0.14925871791853765, 0.18859915499537966, 0.18361293474474136], [-0.3737420051567019, 1.252580812194128, -0.40847702491833615, 0.741158231750352, 0.7890872578398327, -0.3231896748289045, 0.3629848495359337, -0.37750106991058885, 0.11159404916336035, 0.5416990150556238, -0.04017511339201764, 0.32894536947020686, 0.0691777500462257, 0.1689347810925319, 0.26570271321097333, -0.6619621387876675, 0.05703125916715405, -0.17772372376864481, -0.3532943230633997, -0.24330008662292138, -0.06445539769837029, 0.13066851653348024, -0.10268444707667031, -0.24918485872269355], [-0.43447219825844124, -0.8653860695262875, 0.8835013365590975, -0.20658057316740971, -0.46165457742988036, -0.9525004032719365, 1.6390271183164318, 0.6765849315613726, -0.40867784294033477, 0.292591097788209, -0.3728046119655152, 0.6133969204281828, 0.5006572971898439, 0.034014208410749106, 0.3584175921422323, -0.40408652407045886, 0.09394420035017623, -0.0740838325660197, 0.2287010896948544, 0.38246709970252035, 0.5563231658028038, -0.1665249712642084, 0.31360491809798163, -0.2401629816036467], [-0.013886545193609282, -0.5016648297014331, -1.4513067904690848, 0.3820941574403787, 0.32057745092054085, -1.2135787222200545, 1.0340969098639874, 0.70678336153014, 0.08154861008438247, -0.2975024786437663, 0.2344627734965455, -0.14200065175964838, -0.2682706056265544, -0.5295880496124277, -0.27081210681108436, -0.1593331194348594, -0.02543229161513646, 0.1585104420953587, 0.02254455781754396, -0.07160684217673133, 0.042148266076610715, 0.13236464032390668, 0.03450995641991984, 0.40675735080122705], [-0.7441403946272365, -0.38440142888235723, -0.3808956858067195, 0.270211968579935, -0.08329632608416862, -1.4278066774033176, 1.3261883181872427, 0.30033303460948363, 0.7543067609417604, 0.14506060493245795, -0.07792108991932897, 0.7581668791822977, 0.7119808432400235, 0.3011182033129622, -0.6565995212052791, 0.5215698257983581, 0.07672928372593056, -0.029529031334305386, -0.04638894728090789, -0.3464019978532155, -0.3373244196653331, 0.2882254797106152, -0.15322619438372695, 0.4259898264136449], [1.213296982763731, 1.1425757821639893, -0.16785822892813954, 0.4248800823135358, 0.7377137829885284, 0.8103422332671292, -0.20462238188460039, -0.5260120293523258, -0.21787305695822132, -0.5456440076276949, -0.3584533864495658, 0.27275544471637014, -0.11895688124486671, -0.19257070275471438, 0.6344919456223597, -0.22696062547590953, -0.28519907926006627, 0.026885813393558694, -0.15471547792773344, -0.30572022527081655, -0.27803502018591686, -0.33153604779273854, -0.2746870088466865, -0.40372504358133954], [0.13413429253579956, -0.5917461791739982, -0.5057680085005489, -1.5989958099972357, 0.13000926007822405, -0.8590609286171697, -0.5708927139572839, -0.02597146999167408, -0.17058119771691768, 0.33972154079141537, 0.19157052890785717, -0.24263126526796996, 0.03867435598060081, -0.2868923655815866, 0.3207487502280363, 0.6741562794334892, -0.23277679321479672, -0.08600968015939642, -0.1021006410525987, 0.1970892720189683, -0.03002372104838188, -0.1629880655364215, -0.27847938251043247, -0.29773239765259657], [0.3794239218484961, 1.677581066880775, 0.23244629586227167, -1.0726536118029033, 0.17384424622328273, -0.45840012479873904, 0.32181449780624277, -0.5855606935798795, -0.2926999241136541, 0.3615350309493794, -0.06930411582008894, -0.12725525434745463, -0.044327066407075955, 0.1320119833990024, -0.22894453817004193, 0.46476598111791445, 0.1012557122993925, 0.891148934716062, -0.14362940821169629, 0.3087234348013114, 0.00409120569855297, 0.3176046195284548, -0.1652157920219087, -0.14620607978998112], [-0.5207614755969668, -0.3469271848765798, -0.57531321144047, -1.423752987792503, -0.5697249087529582, 0.08215866335499039, 1.0704868478558514, -0.2386182512265637, 0.14171167678966315, 0.021854003415977794, 0.2436814279526509, -0.2769255320508054, 0.312772631719101, -0.4635325121294011, -0.3307524575163654, 0.5236950935567393, -0.30909668897316955, 0.32039146205452584, -0.12514576146481537, -0.16371072530745748, -0.3952132663761269, -0.13477327652789284, 0.00445325720437181, -0.12001716512928975], [-0.2242950500860132, 0.5732997079493068, 0.5577079895984102, 1.4978142871947313, 0.5966779690776235, 0.07710429116131161, 1.199305662700239, 1.3731021014417848, 0.06455946064306514, -0.19798020755443682, -0.1749952446270205, 0.5077242833822911, 0.27444333893442896, -0.1492293881383141, -0.42342078023074986, 0.6654465664416165, -0.2680372735477512, 0.02665823584315467, -0.02602957020371319, 0.04725527969585419, 0.3621771532871944, -0.18864617321534013, -0.21260351508633513, 0.12436138746519602], [-0.3155568772200418, 0.21764252341762394, -1.597759839115383, -0.17754508915971556, -0.7702512258405582, -0.10374848900853231, -0.5015441796080834, -0.12620285916320537, 0.0915927968423588, -0.3188431802886383, -0.32093688824184413, 0.4891950488832656, 0.5272778966348266, 0.3545295035127642, -0.22978411673600352, -0.07655637353168492, 0.044390410524080284, -0.09486771815949606, 0.0335547674464354, 0.08035622003613072, 0.13968748122103597, 0.10373323709677763, -0.10702730584200895, -0.45476559483637985], [0.012328842882565699, 0.500455686910072, 0.25821637222202826, -0.3462000409235713, -1.1475285686983696, 1.2426652447127116, 1.2731104075483932, -0.3812215114086984, -0.220645797755814, 0.9341919556562096, -0.35314581955159685, 0.48156760344645244, 0.3189071097680941, -0.04065509917368388, 0.24228322993180756, -0.5565050093190509, -0.22566819113809936, 0.22837327704602292, -0.20976877999974525, 0.020296007409783715, 0.011297809185635154, -0.17396169353389118, 0.07940391921579214, -0.2952631881857316], [0.5974419641379449, -1.2028361191349761, -1.4827788883075086, -0.09713840142697942, 1.4217232809497684, -0.8773301373274952, -0.8309640370358485, 1.442174796981572, 0.15495280840693992, 0.15733516654141405, 0.49509219505383534, 0.5572495691568077, 0.44988873823334524, -0.15246209946872627, -0.06396924543921002, 0.40303247454110125, 0.07682181656096104, -0.16214233786319757, 0.2106408896998698, 0.38689934898292533, -0.38476597687910463, -0.054069274503609835, -0.23409793930778244, 0.17787326986101595], [-1.5643077366350597, 0.6292873045305785, 0.5076199684166776, -0.042864099589554366, 0.22770615826439705, 2.5314335200754186, -1.1045249615541994, -0.2569775864375853, -0.11503520499860932, 0.24458248795333548, -0.3971699799299918, 0.5767682682501191, 0.6654253921390659, 0.7193409912585277, -0.24868890074412273, -0.5764382834644038, -0.0666403013807191, -0.1934116202259938, 0.291561414058616, -0.2171961791716553, -0.11690918705351837, 0.3871601418120854, 0.039453446912657494, 0.33764277835490475], [-0.10663031673441321, -0.49740293556739534, -1.2688557007313372, 1.492503199254402, 0.2569923476761954, -1.538436793745583, -0.7082386742814227, 0.3791127397653449, -0.0013258434720256665, -0.3261689179836007, -0.7225434635486015, 0.38912498013385405, 0.4430868394635882, -0.15084303498398632, 0.5870448943396953, 0.25293298727984465, 0.4851924034827837, -0.11026676362171817, -0.12899024946831025, 0.4243909524472079, 0.20465276252300696, 0.34234315728914055, 0.3129938092593191, 0.18482215627971627], [0.4583124080202837, -1.130491816026596, -0.05477220492810904, 0.35570348728983436, 0.4174998447811832, 0.46186039762096925, -1.7551327054371733, 1.6538580605783733, -0.2793017621354565, -0.3160258204129358, 0.059234597950675115, -0.8350057157739047, -0.431773542175029, -0.6870077807937072, 0.7244800648220984, 0.3462081036287294, 0.4962610050049568, 0.02349358336901396, -0.07727101340189216, -0.18880509440049412, 0.3401857073351697, 0.40442858780526475, -0.17222481557368907, 0.28393729969331677], [0.2889850532046322, 1.6074259573266758, 2.813814159454268, -0.0038620998582480958, -1.0959728274777898, 0.8981723117675761, -0.2204301336630726, -0.37853760057388885, 0.41405915418009737, -0.4410044588055184, -0.2777543915375009, 0.3197630433080017, -0.03989090166288195, -0.4987541643170158, 0.10024831747637428, 0.19673241771577438, -0.18512217874112652, -0.03125317505123974, 0.21008020050415474, 0.18934496829205982, -0.09958992077280376, -0.009762251012012562, -0.10029756626113907, -0.09361833154527259], [-0.806850193132966, 1.5077326716754007, -0.39580291690030917, -1.060981891383886, -0.3643404175159913, -0.9802050084334988, 0.09613774942336209, -0.3502010167711763, 0.27137859261846325, -0.2136986935441372, -0.27644576851968633, -0.04582955376382714, 0.4217992138113692, 0.24233994559387953, -0.005375965273866531, -0.42101920872833176, 0.14317654513523853, 0.6403916981086131, -0.39955096844156746, 0.27142570042191355, 0.22802180996285698, 0.25819026161522657, 0.07093428966773076, -0.14739412690432596], [-0.8281059444295154, 0.5917933938932725, -0.5907227969491711, 0.7506254059209901, 1.2256467945611824, -0.24116635724332186, -0.6556328852495941, 0.19686095449427313, 0.29995055694154277, 0.09371344965874248, -0.30732264642775814, -0.044623977771687744, -0.6734961283743496, 0.5605885676904735, -0.501575462824271, -0.5022874077069684, -0.15492551838704774, -0.3444079705701755, -0.09623821124412084, -0.1736511841271793, -0.09884943905690749, -0.004314220750539744, -0.0035915183423244697, -0.23833586958906486], [0.8880707147193165, 0.08191296181378899, 0.16988018991852527, 0.11018023921612183, 0.3417885202412726, 0.6794383131031867, -0.7112840793894288, -0.40605959250870527, -0.5222988944586068, 0.17600952655209068, 0.11210478639768864, -0.6023558468132502, -0.49079462784715405, -0.12450634735427761, -0.6268739687816905, -0.0698250268458474, 0.5906304403524407, 0.10061796109587058, -0.24118481062113548, 0.08245546165392174, 0.317510036398182, -0.20739601470062663, 0.635444199288656, -0.037043946922513254], [0.1414453423453181, -0.4772045750967858, 0.1661612062602977, 0.5905575306740003, 0.031956657349862354, -0.4656704217758677, -0.7777675205419726, 1.5691828529886644, -0.4078659643384266, -0.25679696316927403, 0.4769747133775342, -0.014987532213936918, 0.29799372753367415, 0.6500788485395782, 0.2374313179425558, 0.47785231593979516, -0.2178154511041656, -0.3483384239884733, 0.16143075227989934, 0.1147726546176574, -0.35454814359905706, 0.19043103115477478, 0.03488492778172647, 0.06686096720478846], [0.8766725022737463, -0.8602642639539567, -0.7825681928505265, 1.7318595533414605, 1.4585900741559483, 0.21428640519431097, 1.0306377038629189, -1.2942606105549768, -0.08349505375754654, -0.20408872632975877, -0.1371162751134606, 0.004141655470168279, -0.4446475608390022, -0.02090482728533862, 0.33240674105034484, -0.10210987150238329, -0.07032761786581054, 0.2112546194016931, 0.14534827399693098, -0.25141564714179526, -0.14595401523266974, 0.08676799483745114, -0.16614630890616697, -0.24645018338676247], [0.10421627440257057, 0.7090611728313793, -1.7718704343745095, -0.5349159882947193, 0.7806985800881238, 1.1467462472839491, -0.6059082952796084, 0.2768990581699517, 0.6696882348495984, -0.5122024544193259, 0.07918523786116752, 0.07568564549694158, -0.4524756197659167, -0.011578888997361236, 0.12008457369986024, 0.4337006679519085, -0.10231751564447696, 0.0319508852780414, 0.391274474457197, 0.033412269789369474, 0.41468727716818704, -0.16462909270599263, -0.3246736730060289, 0.3199132787675912], [1.5126471517592717, -0.23785071563124147, -1.260584660091423, 0.0807310067472996, -0.3137027939047014, 1.3041783925987886, 0.09820441142747757, -0.6886370276482624, -0.7566947184279836, -0.8459353752512488, -0.08303345151136225, -0.6810349483313923, 0.2603177761141999, -0.31358649550857676, -0.2854977180482698, 0.24770181953930148, 0.18070756904847188, -0.13508983701818403, -0.34239657378615224, -0.3123282237783368, 0.13030884742889462, -0.07347110551184573, -0.0030157102315529504, -0.08932454988412929], [2.216978579079389, -0.3375260892759986, 0.4926988678734888, 0.7100737782559685, 0.7820639977181929, 0.25586068605653434, 0.49684513484724513, -0.03941393117405665, -0.04769260995347891, 0.107362811206579, -0.15385572288040558, 0.08659334326932769, 0.45950212108059413, -0.09499051219761083, -0.5457645867750796, 0.026894322510280923, 0.10557311577725859, -0.18007213197459881, -0.2100155930504825, 0.1828497904726146, 0.003523351505468018, -0.02961930068322863, 0.15288163988926726, 0.15391980608772846], [-1.1466695352560972, -0.1011179182527012, -0.15864547616412028, -0.018505220269573134, 0.17881854278853299, -0.48532705819904504, 1.1852205648197078, 1.4060260393590613, 0.23727493345371756, 0.08979450806169212, 0.6573941364705028, -0.21436371433724952, -0.7506173580399154, -0.4518669345579745, 0.028634596774003457, -0.007343463267226496, -0.23767088935791816, 0.14660678398524868, -0.1882575606892148, 0.13055033745406233, 0.15051563532673415, -0.23750656714128443, -0.05830953386519267, -0.19514335620574264], [-1.8345756965914282, 0.09213410102562031, -0.6559298882477972, -2.0904855110829232, 0.4338450127245658, -0.47984143765077997, -0.40257521146878084, -0.5555399404744689, 0.4439677012506535, -0.8194822638013548, -0.017393173701641746, -0.021150713253696517, 0.21848229579493206, -0.008524190478925367, -0.1332192005117525, 0.18681961003682446, 0.47422074495209277, 0.22124081066271098, -0.04383317353829493, 0.1355501454823741, 0.3405295124073223, -0.21896419954115381, 0.024409841344855767, -0.0325536710320036], [1.0602771301282217, 1.1294827481766416, 0.3027394140460779, 0.7244732678541596, -0.05245508132724361, 0.22542154145433996, -0.7446472930081015, 0.05117487112649224, 0.36910993797342917, -0.07971524741307387, -0.4919509463835523, -0.1396799308888792, 0.06271002600422043, -0.06809202324798398, 0.22954406049775442, 0.3579247057271791, -0.20768601262204198, -0.1071177385852039, 0.12861862927848255, -0.020168753582029342, 0.2146305318794235, -0.2536211277779066, -0.062602923541497, 0.192091959721545], [-0.5253966937287177, 0.39887596752404925, 0.8372615789103615, 0.3985001295721305, 1.154125815786198, 2.595090558538282, -2.020121976780598, 0.03273011140108807, -0.4844891041157512, 0.37155088768457994, -0.2727612300113869, 0.7082065075821902, 0.2478478694059333, 0.7692060708639465, 0.013786767156022655, -0.19451706585777312, -0.14427686223109967, -0.17971535062266122, -0.05431484147199291, -0.2350596449995519, -0.2523279726319499, -0.016319619814935318, -0.026101291697064998, 0.24227572333804626], [-0.39771865756803687, -0.3009047240736222, -1.2846740184332117, 0.17794535223747268, -0.1881784002096802, -0.4928240711442185, -0.2891094593652537, -0.5035147331824583, 0.709122044575735, 0.2521289760117825, -0.2256215064397247, 0.15501257786384687, 0.07327006615502014, 0.0941177021592222, 0.007387500632021631, 0.4608791383941367, -0.32383965644634777, -0.0783510472954017, -0.21842758195797432, -0.26919656804034403, -0.0981993855931982, -0.3130352465526136, -0.0830191448527581, 0.011314997612606365], [-1.9601141920662197, 0.9929467500260722, -0.26065014014893484, -0.677093421954362, 0.3373192598918622, -0.5203927932843855, -2.0831447036679, 0.8048893897593754, 0.28175208633444, -0.04576746137281248, 0.2205224464398913, -0.42731531814632107, -0.5159565492594563, 0.1730825011904574, -0.29528553912498107, -0.3407554700981691, 0.4774741933618294, -0.29554044881257147, -0.34338514786710905, -0.08762466557265032, 0.4736710044301764, -0.14066767022601406, 0.01813646919788481, -0.15152394547117362], [-1.37344775509343, -0.09993419127400978, 0.15065650527179308, 1.2846400186310254, 1.159645755478725, 0.24919998183218753, -0.7648606602085362, -0.34713489377456974, 0.19906840469913417, 1.0093165435571845, -0.3140032516279527, 0.15301495516837837, -0.19276236232992505, 0.2041689518694288, 0.7447013080519606, -0.6288442767398355, -0.3467130520228347, 0.16129695889132445, -0.3728373802816115, -0.019417008134877872, 0.17700314167059233, -0.1982808566459823, 0.3632402864250826, -0.2627039801123665], [1.060890204946697, 1.5909457623290393, 0.5619665390907386, -0.4170487048031066, 1.010108402421497, -0.25351358800308144, -0.4325880904829617, -0.22605336400524823, -0.29953163925824194, 0.47571905858922925, -0.3330909011170751, -0.7919278640500986, 0.1109268775017554, -0.5836988031231243, -0.08594892963767452, 0.6283907202057466, -0.11623106286298128, 0.0909139590965937, -0.3158104086374103, -0.11905141507021584, 0.2541300556504113, -0.26277331375491825, -0.18793303133648062, -0.2556223146314773], [0.6227456868468795, 0.31643324146912744, 0.9979186944284781, 1.239186574378882, 0.529799250880599, -2.0720788152858507, -1.636989785943859, 0.16086438535659153, -0.20157400117367044, 0.5088668400357528, 0.005592847134655605, 0.11095874034874904, -0.79831958359996, 0.2934196775438685, -0.28035600330032107, 0.288289983938341, -0.16337727075483688, -0.1286845983996968, 0.22819849779101484, -0.16692740611002307, -0.19013414416382543, -0.28288267527451283, -0.13342118012353735, -0.016016694157593155], [0.04607959914896517, 1.9053174004278641, 0.004660080880649395, 0.0029185356873184594, 0.9305566910736258, 1.0843038959241766, -0.27143477185789366, 0.43906736740012997, 4.630615152804888e-05, -0.15947946311679298, 0.34652148118512993, -0.8892420457958617, -0.4463895566715007, -0.15960118342979746, 0.061588700695514934, -0.00645809481720957, 0.21162652224689688, 0.30514683297743095, -0.07817867074965326, 0.13712695495336935, -0.2973529257593702, 0.05749060399728973, -0.0017363855644618622, -0.2434950684749215], [-0.8951393185464777, -0.7111780887831233, 1.2312015388743176, -1.067424147990009, 0.9104784807049238, 0.7251066791887653, 0.6679441512085577, 0.8278177057965305, 0.12173853265803868, 0.49290347911871774, -0.2850624637571726, 0.35080412852739146, -0.26468841810568416, 0.20010552351730004, -0.7254013701629476, -0.24955120968478475, -0.266480556393087, -0.15007483638660438, 0.053869145433279315, -0.256255936897972, -0.43370395505290266, 0.006481138731630591, -0.15243212229369313, 0.11115384578187429], [0.5995982878827971, -1.7218207128468501, -0.9411694272747916, -0.3799071021304324, 0.9035062653752598, -0.9528352662451344, -0.7101926329017239, -0.30019340848634946, -0.2553174570460557, 0.43715086193509334, -0.021730021969949574, -0.44742916907980873, 0.19455794844817048, 0.04665084308896237, 0.3748311792061208, -0.5168495845380469, -0.13183122603209577, 0.31424081826133665, -0.17395148884057016, -0.1017670409038996, -0.11523252709411867, -0.3512875718599751, 0.12031862921589694, 0.09653096434221568], [1.2623097078129666, -1.131103833877777, -1.2805519666975669, 0.668207682551697, -1.9258526555956184, 0.40366917959218046, -0.47575651357530674, -1.3738183308008949, 0.0608008294206873, 0.030031252687346834, 0.2856732406171585, -0.20572242504738864, 0.38379840574917773, -0.12753211619459015, -0.14150488490979862, 0.1697160472567563, 0.18314316817825396, 0.057783475672338165, 0.061659951290010284, 0.42997048790456777, 0.23108395028213727, 0.07586839150188142, -0.04833196414171651, -0.09380595468472269], [-0.26702968456464826, -0.7609257304113999, 0.19689962359248073, 0.4435306584796131, 1.437804001387267, 0.08329779318893818, 0.04254059507983609, -0.48986784703508585, 0.06085903463333281, 0.2112176791058287, -0.16811797102143247, -0.12915284592501414, 0.36581824802966145, 0.21476316350980001, -0.6810763479562758, 0.3846055321551836, -0.2624756731523775, -0.26267177834608385, -0.32022627132914805, -0.007143263272758584, -0.13826532817513715, -0.1341561017515053, -0.05400243990691994, 0.10118102178152757], [0.08224789991308713, 0.9694949671162435, -1.8357063436718495, 0.6954820371118501, -0.445866451653249, 0.16384102312463902, 0.2523393158759912, 0.7727832020241154, -0.7248394666528023, 0.14570301570856783, -0.2810558020143635, 0.002724434961048341, 0.3964147885399373, 0.5065299648652611, 0.02427371586604055, -1.0652000348816517, -0.12085172983322773, 0.00965548637360508, 0.3714254377393085, -0.15491093333459702, -0.2202820961133235, 0.0226936168951943, -0.2267696183071302, -0.04877590757272135], [0.31299866902090023, -0.24677134019148603, 0.33662325744592064, 0.14325305451311926, -0.13813718633899996, 0.2858120914530903, 0.7649742031930093, 0.14295240549080285, 0.11347766361272543, 0.48267425467793307, -0.28814574816716376, -0.21538671576424398, 0.29868303554222386, -0.04723409988208328, 0.3600781372194304, -0.24304631552493702, 0.1109162025321226, 0.0322629878688608, -0.10754599530497698, 0.037626404172738784, -0.3494813067921839, -0.2685445146130811, -0.13299645928024587, 0.4987269444043117], [0.23996706742569643, -1.001607412006533, -0.0893215165437712, -1.4521098952589249, 0.7222155428135173, -0.7776236068086249, 1.1591690826350556, 2.667631230802852, 0.1572962948609477, -0.2368444387270889, 0.30471746413785605, -0.4981271977843232, -0.26213675754530025, 0.06797785552980919, -0.07944302454522026, 0.20262797627868182, 0.6938493075620346, 0.052737330843660925, 0.009325801694799261, -0.41188956623681006, -0.12254039830229953, 0.28152794449186236, 0.13275186334846206, -0.026480748084548946], [-0.2468884765717161, 1.2056681021774998, 0.4258546002976681, -0.34209022562537517, -0.7307561663516605, 0.6173631428542922, 1.2521011495934657, 0.3334002855375788, 0.2729165407417601, 0.2606735839968002, -0.281934540761396, 0.05035749833349431, 0.4561617817334196, -0.16740238981183944, 0.21357641345950337, -0.4989747865445527, -0.04550033945350219, -0.07089374845649252, -0.3358511403444958, 0.21914839522527038, -0.28127687683032465, -0.09377954156398187, -0.19441188866995965, 0.6534622539733538], [-1.2283152655388903, -0.7947648020771377, -0.1873478255097657, 1.291037184484054, 0.31591839368009766, 0.39928685932467445, 1.0798463780252574, -0.16028750155168914, 0.4548237728767633, -0.16659422113977562, 0.7495488211150292, -0.1635743871142979, -0.41910359306886813, -0.029029763424811478, -0.17781033349041825, -0.24899246180141574, 0.1309413831574967, 0.2217349252483815, 0.5914950490179258, 0.23286744090179093, 0.23136582154933114, 0.6817519793022259, 0.4393675532205263, 0.043694022213769855], [0.02458548414542029, -0.06911582256085194, -1.692249031639327, 0.5312865099074892, 0.434499127400098, 1.0016089413835754, -1.1625232281096376, -0.7008122011157328, -0.661271930808641, 0.36058859973929536, 0.060237307370194185, 0.29668997600098407, 0.4675327328318429, 0.9623644307004292, -0.22730114269486656, -0.6255359030487229, -0.025823111393271807, -0.19383604394288562, 0.2210411183966301, -0.18547591802191704, -0.1264446607259236, 0.7205029105249565, 0.2161749130024905, 0.20680166407794257], [0.9259540616518656, 0.35673620554616353, 1.3690250529390995, -0.6032032281505652, 0.23903908019190445, -0.5329925278053121, 0.23804862990679984, -0.40827995364785863, -0.06962259432875705, -0.460122804873537, 0.30131573939669704, 0.09674209710401073, -0.2617907195568545, 0.0023180655317951594, 0.19389355459970184, -0.16717294313309522, -0.21482880322864034, -0.004348518960713757, 0.3117976108348337, -0.25320043198745124, -0.36280540951848034, -0.09011817558626758, -0.2204506997948894, -0.27622571413206454], [0.5750331689381627, 0.9962821827653493, 0.6896239158096065, -1.409668693583877, 0.9273140401251501, 0.5110573102916246, -1.0261885043758083, -0.7626251281550478, -0.1800252190929541, 0.8243394737532538, 0.02814752309516124, -0.05812500577380525, 0.25112603257296395, 0.04945925341421457, -0.15155861637571497, 0.30254291612941664, 0.33941137713134556, 0.30945169402298367, -0.23048371499942674, 0.5111497216982046, 0.08665440642057745, 0.5073471423333921, -0.29442969343306485, -0.37781131011121577], [0.11037586251114291, 0.5679787224731633, -0.40359589459344114, -1.2511798049447431, 0.3142095779464797, 0.2529732629029669, 2.229932763613753, -1.1188023905086861, 0.4361863684629578, 0.04493810233781854, -0.19445784855346032, -0.023852485033854648, 0.21204632651644015, 0.017265274972586918, -0.18557635495837363, 0.296272887569737, 0.24640313741700304, -0.0710076505039597, -0.07631389222667635, 0.03943075214775531, -0.256115531621902, -0.20780099373481276, 0.067932181113613, 0.6670239523008279], [2.325473672044751, 1.555736673391797, 0.3283010530012599, 1.5485436844074754, 0.14203053527037926, 1.0038343048332494, -0.7371738759820885, 0.09110413222926865, -0.28575508830637514, -0.2595104775117022, -0.21495696414926793, 0.23893864081140231, 0.6401891082325248, -0.04467213768245484, -0.1279130014778295, 0.2587957617013469, -0.04683231663855121, -0.45043643676766987, 0.22216085832664687, 0.03078394535278857, -0.10195705742953867, 0.25208027860567644, -0.06671572350176672, 0.507156945312438], [-0.7903908381555953, -1.2444710524955351, -0.22976335664195807, -0.42903538500327576, 0.5852322456387073, 1.2760737950941259, -0.2095140319068081, 0.07274168201189107, 1.6519937252497914, -0.12660892972327772, 0.4059457327982523, -0.5948031404131104, 0.1742513736665628, 0.19071026580575115, 0.47953925713854495, 0.10796211813041465, -0.1831132226397621, -0.29036314618784287, 0.141054710767863, -0.2656749176131155, -0.13054891584618342, -0.0961839229121087, -0.08280564574540333, -0.18747887262590635], [0.2685426502969497, -1.330916415302001, 0.29524948519173166, 0.14280715472252478, 0.009062807669912564, -0.9273456343506096, -1.9036010148879803, -0.2006675101712055, -0.08860447300100338, -0.15384128418028867, -0.36588338294964734, -0.7209668168638614, 0.08974362314455374, -0.06300632803010663, 0.40319972061490084, 0.39208423723607233, -0.15275644597196206, 0.46911080219110085, -0.1553751788990333, -0.31788906215467017, -0.20918341530160708, 0.0699485695924197, -0.22085207968753057, 0.021092237970636914], [0.3814683472061969, 1.2151839828671165, 1.1322683047477742, 1.3747785308200502, 0.39644891525961184, 1.1695478227766907, -0.24395967365090504, 0.5763334720549629, -0.09179130329187267, -0.3630415174858775, 0.14126265970626894, -0.06417182976608439, -0.1659991558878791, -0.4704266075267501, 0.04529180267851066, 0.7240526627859946, -0.2822769693246034, -0.0070874291223674965, -0.32562162321588467, 0.5619694133905909, 0.44976525797428, 0.021940722725724983, -0.25443926757043617, -0.05518422359978944], [0.9236161127133387, 2.3524237416587326, 0.2695681892512801, -0.9526144676787083, 1.334294254459078, -0.640136628437504, -0.10813781447079694, -0.23953497440972318, -0.25492621594400156, 0.5120767214591746, 0.07829050119217743, -0.3023121102259693, 0.08200764837847994, 0.20017367246913895, -0.3045280179565515, 0.21285005000701007, -0.13627984547989327, -0.22049344390060502, -0.2596249554383853, 0.014234515255933675, -0.10099263165784075, 0.3773090469469676, -0.05343117654645283, -0.026869547726048708], [-0.6963087416074215, 1.2100051556645395, 0.612718510140027, -0.38904794828317385, 0.11669793542321943, -0.3074059858956743, 0.5235001983923274, -0.31411625609396415, -0.03311968129729013, -0.24855934463521354, 0.9845452781502902, 0.22174224403700957, -0.5211838534544782, -0.43951538536426243, 0.12804106314499447, 0.19114956742738173, 0.20833905995197838, -0.27792846740791566, -0.0395505567542212, -0.36195003505555595, -0.09289993022412187, -0.28580099152009153, -0.09466322761445634, -0.22798396239675783], [-0.5716219444074211, -0.45913520674724306, -0.39015142356645893, 0.3800068625094128, -0.8029373291457623, 0.012131646550238299, 0.36311752500863376, 2.0874080337793153, 0.2356563916145513, 0.4686935501771012, 0.04217045127985042, -0.7852383363373536, 0.32508024850396566, -0.252640134811954, -0.267040351581149, -0.04037044768274575, -0.1617096254256989, 1.103331780407269, -0.19928238100832113, -0.09984984048655163, -0.05922389179737139, -0.009560898105901829, -0.3456982002488567, -0.1316859286478577], [0.8570700423843842, -2.432215078502745, -0.4622148394974204, -0.20552765809127915, 0.35032281503488844, 1.553531304650114, 0.6420758350560024, -2.01576043620744, -0.09201377362051467, -0.005987052112691726, -0.5442059159499182, -0.0907669238707295, -0.34042375411253484, -0.0028526475483494113, -0.07894426604257204, 0.22892881001857857, -0.14357823621119656, 0.302014573238895, -0.2366585226802032, -0.18935521157807475, -0.34507569616329664, -0.0373627267644325, 0.43895954111333924, 0.12945284172320345], [0.3733850437803521, 0.17540823019420254, 0.43496454593117023, 1.2924898742827555, -0.962979177124032, 1.1202070927754293, -1.5970529506409363, 0.06557043547508914, -0.20685882137447217, -0.4862943342643774, -0.2589251340097933, -0.4151943538046393, 0.8488155257910008, 0.06281358287546539, 0.020743736250380364, -0.2857418192734519, -0.2573210932693595, -0.07897576801203658, 0.11088421913793552, 0.003189649022852577, -0.08310710724666272, -0.2691797380578573, 0.007005097652397537, 0.16419168430302347], [0.43821459458731227, 2.0110248994568027, -0.6479067188572698, -1.3121173495116063, 0.6916124438012572, -0.5192707669176603, 1.4100439299789376, -0.6054822815136355, -0.3602896736987153, 0.5425268034795797, -0.17251842045983504, 0.6698341494816021, -0.17917157192234154, 0.3386149317710625, 0.20399533232622727, -0.4333321740713102, -0.3614716079914333, -0.3233775321470803, -0.3737764880380589, -0.3149931404027084, -0.04475136034260184, -0.2510251999898543, 0.0029158182414732886, -0.13489122239918527], [-0.6694626468675662, 1.1338684935175667, 0.11694121126447923, 0.9869770323160886, -1.2787920844527982, 1.6294537451405493, -0.6017942347772436, 0.7452362957504042, -0.21218024001944996, 0.6527719947548429, 0.002908224343792783, -0.09210369911132849, 0.42259127140313263, 0.0024563848975528964, 0.10365846440841346, 0.04007126283205513, 0.0602553941482109, 0.0420303689992061, -0.28219480562470495, 0.5111008775821935, 0.05986935151494558, 0.45041399794762593, 0.021447709997713713, -0.3132895697175361], [-0.781888037859299, -1.2235702330171991, -0.2153580138863038, 0.28197166828967685, 1.519405404660864, 0.420460649502828, 0.6172545222253629, 0.6032895244947173, -0.15794264066563501, 0.04950275372795994, 0.15562477102327674, -0.6945456227899353, 0.04271174327636989, -0.32214318166927436, -0.4222640634475591, -0.24946904382307752, -0.30270573675823487, -0.11575318341092916, 0.34316215755138096, -0.23191402402667136, -0.019817887464689068, 0.026767925066140678, -0.3504483956436086, 0.04530660738225921], [2.8418605748718293, -0.6057469535150117, 1.252643202680683, 0.005780285065283653, 0.2948538399269293, -0.41289151901794413, 1.0348979822491382, -1.0890044087664563, 0.5868704111333718, -0.3225289692313637, -0.23818543031527958, -0.7096975879921931, 0.41762697332806314, 0.6383659254230696, 0.01782895834868166, 0.46834304220717937, -0.22741126836652054, -0.32073524769330447, 0.3454252839479767, -0.20015171534147147, -0.0031580434825705436, -0.038314568966158875, -0.1537147270409629, 0.12338458788489054], [-1.0613359845182602, -0.09101121727568891, -1.0903604826558846, 0.7331492908268334, 0.9100901752172796, -0.6045437715550088, 0.6811033227955541, -0.5647951900185171, -0.5614189642768957, 0.19528328597836286, 0.12524259494542306, 0.06395023352443997, 0.26239272540254066, -0.02501969627845693, 0.48095667847579127, -0.2685835840555638, -0.31230690160026914, -0.42816686635895984, 0.019256306717579705, 0.47231815985811326, 0.18084378345123503, -0.09868740352743, 0.2678943253083889, -0.28534192960941984], [0.06411053505787061, 0.08997116699318305, 1.8558675117732981, 0.1327581891095484, -0.796503624892602, -0.757452710485491, 1.0700272249604463, -1.4552251677661459, -0.1398677293601113, 0.041534055595773806, 0.2682264896222582, -0.4913968007096764, -0.3694951185691625, -0.41674823219526586, -0.14052332028823972, 0.4959106317386435, 0.17653180646423236, 0.12058257617468617, -0.05244222281515224, -0.07643897643635487, 0.05099532080728244, -0.22564046748181502, 0.586062276824123, 0.0432602996349351], [-0.31103524697638435, -0.23640010730701203, -2.3452387606255485, -0.26724274904716, 0.984781747561774, 0.30920569312573887, -0.8932431606772078, 0.6310110481255097, 0.3025995963634114, 0.10806969881947032, 0.3817886779799233, 0.7110105209545131, 0.4899123589838705, 0.03703738571707733, 0.0654074244105747, 0.42070528276739527, 0.21682687728599365, -0.13748778195742728, -0.3537893983402726, 0.1972803403935822, -0.25719364720390453, 0.032010638343546914, -0.028219225917154925, 0.4054398755806726], [0.5579294335706303, 1.791715428189188, -0.6867497323978002, -0.19852721303740062, 0.09040100569157904, -0.03369671888526279, 0.02929149546509634, -0.07437477500183623, -0.18418187665729246, -0.5724423386850022, 0.015610188604486699, -0.09477653025903152, -0.14563522577282734, 0.22658556332711785, -0.13190465148026012, -0.2978497467313078, -0.21778984564811152, 0.33835320090478793, 0.3628293954367212, -0.32758369478350663, -0.4094341405958112, -0.15425086125397747, 0.19670232542944735, -0.15420812093875721], [-0.5088542689546302, -1.2688790009607223, -0.5106410909261049, -1.0549956769632414, -0.9268384593994783, -0.4142334880526935, 0.41843712158015584, 0.77026927097978, 0.052860603087254765, -0.18891918335479918, -0.3283672394482654, 0.46836706296740727, 0.2396301634321658, -0.14546393492483659, 0.36024630916963335, -0.36430829218209415, 0.2334143543066873, 0.06610157390130213, -0.2280939768104474, -0.042063653347386654, -0.1918696349323236, 0.0957825830532582, -0.11749865736690818, -0.042134122091940944], [-0.8166693389326395, 0.33508766459882083, 0.8029094878440507, 0.08390779101740464, -1.488184570204717, -1.9227299941035585, 0.6745437682132739, 0.8142557528692479, -0.3105590350908489, -0.4805243937881625, 0.12405271862508652, -0.4886437620648844, -0.3018423606122719, -0.12975502511365253, 0.3480977476744816, 0.1206470269818733, -0.18267195551516263, 0.014359577223678756, -0.38571668419232996, -0.05276156241351846, 0.13584647168556382, 0.16818974401458364, 0.07543011816489421, 0.2018030381965931], [0.3296650883376975, -0.8217969008143033, 1.4237537928270256, 1.1498390599064785, -0.011922425360826132, -0.13406356908502046, -1.9036812735730404, 0.663189858196861, 0.3259036506456219, -0.12704251393877206, 0.2301843905613679, -0.44802930639454136, -0.041307781584604665, -0.6634033025502224, 0.0739853766344843, 0.14801142675694182, -0.05879687640761829, 0.3704946348032576, 0.009678407779736126, 0.14836421509821024, 0.19170654174517585, -0.2725488875231438, 0.07793852966866564, -0.04198472429860078], [-1.3402665612596147, 0.6368055435255382, 0.7171228563566132, 0.1910674682163579, 1.498045089231372, -0.2284537915629803, 0.47564695629206555, 0.702687817735606, 0.1883182881778223, -0.2864807125284356, 0.7622579227530126, 0.04151961973933056, -0.15497826748024313, -0.04477075598140247, -0.20531008804469006, 0.50248393823364, -0.07895105310111948, -0.2027782368331217, -0.10872052404057304, 0.20543953963430328, -0.29422083154936535, 0.41963418184409007, -0.14463533938949874, 0.2815758102805824], [0.2996465091192767, -0.2902272388689062, 1.2039972346414773, 0.4723083908780566, -0.15050087418115282, -0.08233811680115814, 0.04688877356724127, 2.0155044068357397, 0.5947521983675967, -0.41512296443057467, -0.3308875839172436, -0.04337368949496247, -0.3788844501019221, 0.08596259195591437, 0.014684711845378179, 0.3042317336965342, 0.00014020110058500653, -0.2402795356216727, 0.30807002477933026, -0.22842159002555523, -0.3823420062911757, -0.23124830013111175, -0.27394186878703347, -0.3272124190219888], [0.17464298969604214, -0.13847733086970396, -1.024022752546728, -0.928813256400828, -1.7370692048256537, 0.289687327552435, -0.04858151316323576, -0.9115834658082063, -0.7392648269095393, -0.14218350787436168, 0.20204934400268004, 0.26234853089774246, -0.39196920667564417, -0.8007523295195257, 0.6543618819790985, -0.09070754658403218, 0.08822196072636922, 0.3957258030440972, -0.05269858255303729, 0.1651147536249891, 0.17543948557862526, 0.03980811767568007, -0.061947715921803564, -0.23188553182727828], [-1.2292407750452434, -0.21335433649146432, -0.5011961096705772, -1.030169314562901, 0.3071892215408123, 0.2017180993868752, -0.12525824535418606, 0.6776787063358746, 0.23545816723089993, 0.3059317890243878, 0.49649668961180415, -0.08777318367787536, -0.8640544593727352, -0.5674135569196704, 0.06105479275821095, 0.18343221354779, -0.35318964733905767, 0.08988167731260518, 0.4702257013316468, -0.3147106233864832, 0.1276836553109194, -0.2927171794372888, 0.512515169542085, -0.10977473108860177], [-0.4971683042062693, 1.2066245097663888, -0.9797486326065873, 0.5467534981653592, 0.6156207073844652, -0.1747903156185379, 0.248568978692802, -1.1420463065639934, 0.006080349637597577, -0.24762292040234454, 0.8080406255502949, -0.2257595389592477, -0.21024650521510546, 0.2467034791791238, 0.2808915033896384, -0.32123372522105836, -0.26472467039152225, 0.08236030354959355, 0.08954467535227592, 0.9637261790694822, -0.05890729256831205, 0.42645987590101475, -0.28111523717439313, 0.5218068084860197], [-1.2480082233523697, -0.1117884033934658, -0.7052439534767031, 0.6111729163217547, 0.05097220010381734, 0.6392574779487141, 0.21718896235931356, 0.1730067773054076, -0.6211287172027435, 0.0774576149415264, -0.09768015880484664, 0.26635264893210603, 0.6364829687973024, -0.4436480364133958, -0.0035662306279435154, -0.008067138036825539, -0.18719869850814166, -0.3321637639595561, -0.1322300038595026, -0.21397934369987415, -0.3010979811039565, -0.245490504853773, 0.5746317662359687, -0.013024507786193634], [0.15721339287544617, -0.25692855450744595, -0.4481148836315309, 1.842280110595818, -1.616597671913992, -0.10833444316999592, 0.8564342146851631, 0.36261842987777093, -0.06257680062809769, -0.022145708236444978, 0.6599583292462268, -0.2668220022101298, -0.21556945975784983, -0.5566860098383574, 0.23092814969179928, 0.22143850045359584, 0.06056248657680831, 0.09200659651229513, -0.11435739234125492, -0.318610297983042, -0.12516087824780325, -0.32482824828343304, -0.23606724985600447, -0.21611515927959782], [1.3149226789404203, 0.5197441158361966, -1.2247680178909832, -0.17681198023948486, -1.2867258181964198, 0.9786951470361591, 1.2648781108687688, -0.40117471752563716, -0.09735116870814774, -0.10384654193048712, 0.3879577698384383, 0.0785278627962158, -0.0685126859544423, 0.2095094363558749, 0.25153211090340927, -0.1673505312890515, 0.18223904745345462, -0.29508072698369714, 0.03503761419542234, 0.35419361099435576, -0.20989708557422182, 0.06433055213399028, -0.22758630275364305, 0.3309175592270001], [0.5492288948097487, -0.29370283189863755, -1.3999503114663705, -0.2814198599190004, -1.4578147884546926, -0.4709602942229804, 0.1076896570093392, 0.626021715407908, 0.7666105884478224, -0.30090289841325546, -0.04962257218097412, -0.10473660529441793, 0.20480889891574589, 0.3977125327262416, 0.019895233715137774, 0.2776614259750883, -0.01457800123312082, 0.051697215055223955, 0.15685040853603963, -0.01840973860505844, 0.2089916550740249, -0.1279640554123763, -0.06380004802734697, 0.12919354600242147], [1.2067473107274809, -0.2328975205509888, 0.22068232862668347, 0.4550088162730094, 0.5279462398377274, -2.596185302134249, -0.8215485310089531, 0.6835714311233532, -0.08511090489842221, 0.048110214823472365, -0.016806042462429442, 0.038734528767031505, -0.11064414167263584, 0.06519513665507516, 0.3515765319714166, -0.605120842359867, -0.27202007729478017, 0.5173341646134015, 0.10956554971583796, -0.316208340331219, 0.16021521375823208, 0.5458606869388487, -0.029387661558163008, 0.7423500028424617], [-0.9245579633246801, 0.25250206299415806, 0.7962799880214309, -1.5273084796585465, -0.1720254741234316, 0.26823171385484024, -0.08957523653773562, -1.3788563434487824, 0.31208215402031164, 0.267329375711744, -0.4866196751952887, 0.037263998237423934, 0.3388817244521527, -0.29487711036536546, 0.5171328097742783, -0.4321719173337672, -0.2923487687721443, 0.33470895671919015, -0.23232514672366564, 0.2635608672649956, -0.20181405656781623, -0.26360435627393286, 0.1181222612214375, 0.09836496880912297], [0.36151513831175913, -0.43460761587028707, 0.7792670661908466, 0.4524516749840567, -0.5128777636946114, 0.20427646704790825, -0.7526942483742309, -0.6527479162544826, -0.33693994523714754, 0.2288585033586509, 0.033345173762955496, -0.5769117070456914, -0.3116944892369112, -0.08238118508165486, -0.4964740649468279, 0.020987730579999406, 0.7986421226924789, 0.014560022453076102, -0.3679946148827174, -0.045123461532874436, 0.5755002412328553, -0.1398797606889127, 0.8159243463068175, -0.12600852184416805], [-1.343463101088413, -0.17121040293187553, 0.7509890578050603, 0.1716900687561518, -0.0354176164343762, -0.5605734583655035, -0.6156431751111762, 0.6065630800021151, 0.15259204874951154, 0.10372656785525275, 0.9944199023352673, 0.04748905801122882, -0.4455314680295239, -0.3796149549311113, 0.40753252222957975, -0.02737782133917069, -0.20503614281354332, -0.07405553747113125, -0.2986482975847456, -0.3904774144780216, -0.25106699831365864, -0.25735765583529174, -0.3303387961374837, -0.2800815514433845], [-1.286114103291461, 1.7524712108224771, -0.11217581450864329, 1.9114692844681824, 1.0617299191357328, -0.3786048433812275, 0.5473885747005633, 0.16290806358384258, -0.2786150383083016, -0.19758592148111104, -0.0916293702998279, 0.0985495309390975, -0.5096666138471198, 0.09796826724412581, 0.6749729293928283, -0.23272025021338877, 0.1009721208283427, 0.2804645435165501, -0.3431513286573492, 0.09324101617764813, 0.28630186176099676, 0.42577683586948845, -0.18710937163198002, -0.027577048332890236], [0.42409908006015146, 0.6697994491412159, -0.5962308809209683, -0.48294751385012064, -0.43540836964975554, -1.2747072323727084, -0.39831295932022376, 0.12610190842265337, 0.19721462184846078, -0.27418461091667695, 0.7364762331938607, -0.17695896467184954, -0.1999230771251718, -0.36627048733372375, -0.3324085454471289, 0.2076832535822281, 0.047459399760853706, 0.21037847804940674, 0.19457354370389804, -0.13736717071164473, 0.24128790097590588, -0.3099164662634703, -0.08212055393409712, 0.07364543163888547], [0.22507228694772222, 0.15162717854178312, -0.461496411939614, 0.7058026187038746, -1.9673586697106695, -0.3860695601931743, -0.4736295264006456, 0.7026128653957567, -0.10984210134626374, -0.6212577743826218, -0.2127437372464743, -0.12618017372273785, 0.4328829215865088, 0.331589611534885, 0.26153483613482875, 0.02818963013722582, -0.3210747278903425, 0.45837482408249586, -0.1561187658168843, 0.07403616437434189, -0.2471940531503228, -0.16798736689484428, 0.3119974792557348, 0.41625788930330976], [0.5760749680628614, 0.650360329167443, -0.08006870370280181, 0.8284062488910365, -1.0089314409084056, 0.031910018051146675, -2.1583209619634327, 1.4083860550039533, 0.6254981480371459, 0.115308540677296, 0.1935598239832041, -0.8247269567147898, -0.9866799560623902, -0.2636879418723935, -0.09990107102590594, -0.3927056095454613, 0.5756087108325727, -0.23382275105376216, -0.2801888407780907, 0.15653137813057286, 0.43842232495072136, -0.22076587700020683, 0.4741707185612162, -0.23212868122796754], [1.3765955358987294, -0.544498001192811, -0.9337558154372374, -1.784362817214597, -1.5130278843818723, 0.06850548925192312, -0.33935138785807517, -1.4175101469736158, 0.4695133027072411, 0.49589992898435004, 0.37520714236678243, -0.2922700671414591, -0.7683871509734721, -0.2381720753651262, -0.4563116982279665, 0.10848626568922246, -0.08563195687771993, -0.32793453009221857, -0.29146374619070836, -0.2891458724846219, -0.08429433334830665, -0.2303881389774529, 0.3837630462497309, -0.44595070421178834], [-0.469763901472642, -0.6035110752591393, 0.3440151495227103, 0.6111852758488845, -0.2906710603021776, 0.06434003173567182, -0.19454583245703633, -1.957227350783414, -0.21641126585208859, 0.338632110211704, 0.20348082710409868, -0.07383675250770144, 0.10951311173576388, 0.6054328832625067, 0.5027026585792468, -0.38477849215712484, 0.1447997071678484, 0.32871482523990275, 0.20999455145114757, 0.3869046311534046, -0.1642792384085865, -0.2891119094281031, -0.272586967928139, -0.11968088301951901], [0.13155727502711762, -0.09393233422662528, 0.6205031132150862, -1.557937667553444, 0.6283407092927207, -0.6331231307379623, 0.06302934770434478, 0.9644254849939022, 0.37615081437391884, -0.30500669007404896, 0.4448226837684453, 0.21684612816010881, -0.20605331714207512, -0.5445869050840261, -0.49319570812554114, 0.08232575775619674, -0.03621827741181872, 0.5299623238500764, 0.2086898404754503, 0.22444946646458874, 0.20391827442492186, -0.2505338693059059, -0.20250985924085188, -0.18306379457966956], [-1.323127713582666, -1.1428633455261938, 0.8610662796896351, -0.9618050009654767, -0.9729421315090532, 0.5231761971201953, -0.3737117163258501, 0.5841195493828693, 0.22269529506425478, -0.0006431254025342484, -0.15391880335427507, -0.21641988969890721, 0.3377410265949831, 0.17214275267417195, -0.2330884185410578, -0.40324685069252103, 0.07957904467595692, 0.34770354788124724, -0.034945998523172594, -0.15317150267383808, 0.08170018824889967, 0.04600695508916604, -0.26170393184706453, -0.09581870405198041], [0.2433741908303534, -0.055755184325821175, 0.8545980110415299, 1.8816642021004204, -0.16978014474163433, 1.3417637306885943, 0.8789681178009093, -0.003897346379606728, -0.3520807162558841, -0.45739093082285975, 0.33092060268867124, 0.1285873147209249, 0.18974332151295611, 0.16898538816067568, -0.07339842529381735, -0.07271385337291834, -0.32259407330807893, -0.19016079215708237, 0.017954706278342916, -0.39299972045151255, -0.24879166381724396, -0.08838418386571958, -0.10126709303616306, 0.823201138846763], [0.3844522267680502, -0.8225122081888168, -0.6979903627043945, 0.2529247313002952, -0.11912854381970828, 1.1774499734345445, -1.3938899496668415, -0.359339440811838, 0.07443492467347537, 0.10821393199355911, 0.4309538590358489, 0.0002391376111076963, -0.18086786416352438, -0.3838605414852111, 0.4453246761851036, -0.12927611345357964, 0.4692303735036653, -0.29046055288224504, -0.1020963431487012, 0.1311658240344666, 0.4708216958575541, -0.23026470591084244, 0.17319067929801477, -0.336693602722937], [-0.5785497980260523, -0.1586441597549394, 1.0327508411855766, -1.0120131670359886, 0.7178792528903372, -0.5783373465276411, -0.4799255291701897, 0.7855722493983684, 0.15277931715934767, 0.04346474315975368, -0.42784032016065626, 0.273714796643097, 0.5600924173094791, 0.37539942483096167, -0.5257108557670188, 0.0758706415930671, -0.291709344065733, -0.2723970156603597, -0.1296179560825368, -0.09047320353163728, 0.38030129985662847, -0.25614577633513935, -0.04349276011737574, 0.05125283271143935], [-0.263901767351675, 0.5352549172553129, 0.016381138305910967, -0.12702866525108095, -0.4055355634758013, -1.6357530326353529, -0.8709855987827676, 0.05374553296962277, -0.026877314387626593, 0.3789911850229313, -0.05692359042231372, -0.36269015847811364, -0.4115087297422069, -0.30083835120765906, -0.15192578475761884, 0.4905704480323362, -0.3300640570670766, 0.09662408719160266, -0.19015077121639853, -0.027501158456060548, 0.29104807736044674, -0.2633689645371149, -0.19971362286493666, -0.3051979221282575], [0.1680991750983199, -1.2816161345846384, 0.8846709919952741, 0.5151075700714485, -1.276181651119077, -0.9899699412755649, 0.3074703666699242, -1.6444984269174825, -0.5326955822087956, -0.2112880026188742, -0.15323744378325646, -0.4236914736832929, -0.4012710339425888, -0.5099067951400534, 0.35202415000409476, 0.4379872445478726, 0.02055594433828267, -0.20168212269607344, 0.11965550220866507, 0.014887786251023997, -0.18694295694684712, -0.2093474678263265, -0.012512900661216873, 0.44685366638324325], [-0.6587060613876426, -0.06293127394299965, -0.2058652991882081, -0.017113359647318988, 0.3063394360796411, -0.7558317473461049, -0.6153775748018417, 1.735419483142887, 0.03873004587151556, 0.5370653352809288, 0.030362474195351083, 0.4896086528629985, -0.6470380496967963, 0.15751142304346877, -0.2585290738401763, -0.1967602465242817, -0.09198137585918095, -0.2762598704936818, 0.31339095235576914, -0.3221896923719442, -0.26981818807842445, 0.09533752665087408, 0.2859177136878936, 0.21722833684696968], [-1.2333338337920663, -0.39073478919294236, 0.03234722035739937, -0.514437725692453, 1.08672683737992, 0.06059395124761967, 0.5553893595980739, -2.389228529556557, -0.2700529308432656, 0.4955674627761106, -0.7231548493649276, 0.3691142788528276, -0.059252154952859494, 0.48788115282851496, -0.12451898281953205, -0.3032351343424593, 0.03761480384905425, 0.15775945004720413, 0.8736746732560289, -0.2657412688657499, -0.00537030049558404, -0.17648692303574834, -0.023697376997988375, 0.11720758894380082], [1.055148857450968, 0.9638150991138437, -0.8036368886674339, 1.1587990119967284, 0.20265419398423573, 0.8623794037000094, 1.5485282638715934, 0.02085044986163271, -0.06490522682309126, 0.16197339261880023, -0.12921451573356157, -0.3030099998033824, 0.043729271295053614, -0.054613949853956026, -0.46558347501378267, -0.5842741976185662, 0.19796749443081982, 0.23196341166503964, -0.1729018149350893, 0.25494391493299934, 0.21049368027556425, 0.3302451883717385, -0.17343489181094776, -0.17766199690653894], [-0.877127612326878, -0.008042998812507989, -1.3002248406437835, -0.6338176042229564, -0.7480267992939809, -0.6538645044868009, 0.9522849365744607, 0.6794194517557776, 0.005044247432040344, -0.6117278194159348, -0.035457794867388114, 0.269171872034227, 0.23371616236486895, -0.36626174383824917, -0.050150269861683014, -0.22980823373874404, 0.029628320852506364, 0.06215647556746891, -0.03649498823828919, -0.31261333693407994, -0.008383472601587607, 0.02450982568942305, 0.21677150579740773, -0.22677948031813502], [-0.7671673301033448, 0.9638830024076583, -1.683436164427493, -0.5015264331470267, -0.15677199895555755, 1.1230261596043123, 0.5521840176941613, 0.3521663300405772, -0.45945923217493073, 0.2585887584242617, -0.38412931415032725, 0.3178646664951029, 0.3823341598310268, 0.6610516376619822, -0.16530662171316227, -0.7352978546787241, -0.33832673268311186, -0.2608756239690507, -0.3347709354636383, -0.3619442557960818, -0.24701467203890337, -0.07609091740826071, -0.15335283417048504, -0.2842791106836676], [1.1821005387999726, 0.6240883491056903, 1.2882467213210462, -0.6017198692121615, -1.5898688468495037, -0.35980978856852824, 0.6592340551859714, 0.18917971554222993, -0.35166879282390806, 0.02261606672438467, 0.05903308544386149, -0.08742128408312974, -0.40196401376557994, -0.46095542415914015, -0.02885627448431806, 0.32232444745268274, -0.3231698527078503, -0.05572002821840141, 0.30195352717405777, -0.032895667204112564, -0.2300967777492032, -0.29171122269120164, 0.37283266331033704, -0.24452704691143065], [0.8261940305540153, 0.6265583198880343, 0.4696875286003662, 0.7749281393342402, -0.6763716148269546, 1.0504425552123975, -1.053802119780373, -0.13842581537688273, 0.37898987343292967, -0.16739227862881384, -0.08648808608695664, 0.41667723257389205, 0.861843599809354, -0.06172336416597984, 0.013190298437893065, 0.09501266429381044, -0.04229413146346037, -0.16727202481259806, -0.10055894893186353, -0.05520829010170449, -0.2734942862874337, 0.11117351795206876, -0.24932886988392605, 0.35976828004424494], [-1.2016134603311783, 0.4562397585913169, -1.5372983638701179, 1.2783188671204015, -1.260411981571114, 0.27635402820230154, -0.24248646983862623, -0.812528529227906, 0.04841221368636336, 0.3329059821119542, 0.17411182680062512, 0.4391063225849832, -0.4610256333555765, 0.1608053810347904, -0.43342181699667903, 0.17603674332846003, -0.3237901067322446, -0.2371110711023945, 0.04747116081555236, -0.12123771065448809, -0.26001053033342864, 0.27500231642758227, 0.36841099477185574, 0.6539637801535447], [1.1478371727183085, -0.3315956154419556, 1.396944666960457, -0.7976509879469217, -0.754605177930316, -1.824317858663762, 0.40654423161033704, 0.7762320477469772, -0.4885576816869808, -0.07448184524923428, 0.5997128012512293, 0.13713148707282638, 0.4283969016464793, 0.13992463115818563, -0.19977731814094404, 0.3693239299338375, -0.17463029192552504, -0.47130739677774336, -0.1473903095555793, 0.22377606881996343, -0.2607829125721727, -0.08224311493331414, -0.14042855344604113, 0.2266184704591391], [0.24552976275045837, -0.10539455709859659, -0.9221938914409062, 2.0873103113544005, 0.6863532652475566, -1.6782554487277352, -0.39950854927985324, -2.3438118963086385, -0.032101646235014894, 0.7229789830836728, 0.11620097944490435, -0.2691079539769177, 0.1323386223575567, 0.2914271655070704, 0.5773113999901268, -0.23230167951849384, -0.29254457193736255, 0.07192970390982757, -0.26410584679814775, 0.17024734542429723, -0.4131211932300867, -0.24749796939728239, -0.09603810104683061, 0.029496462933742102], [1.4412167675292091, 1.702664381637584, 1.3966181721055857, 0.03579777928440465, -0.555519280125002, -1.2665175935908677, 0.39127063253434125, -0.6920401917938077, 0.2910380293656025, -0.2405643412141941, -0.21506609335345148, -0.6262355674380041, -0.6644932422771912, 0.3556106592536824, -0.13731644439367857, 0.14683654756686587, 0.35143709799576145, 0.12819725671994753, -0.3226621872229434, 0.0791159818769505, 0.6348671822842981, 0.2916436873278211, 0.32486065135434716, 0.07286577628882474], [-0.28046299878163394, -0.5055367212466253, -0.3229571389394755, 0.8510859539709363, 1.5737311786054438, 0.1828858172746819, -0.08584213319190315, -1.015518419303452, 0.49734892158138916, -0.12038101332561958, -0.39812575871323597, 0.4107769513748733, -0.10883430265858782, 0.03623189154683438, -0.4437846224256054, 0.09112646839368056, 0.32353571777408324, -0.1257220481077721, 0.16446184072770847, 0.13216428929288365, -0.08675653173947222, 0.17405952544308093, -0.08688857633747592, -0.00560980746788099], [-1.030977757375162, -0.8614294974206607, 0.8421461220913081, 0.2986814758512193, 0.9060062620497942, 0.4410657895257077, -0.47724456891987266, -1.1279497516555252, 0.4798923010565989, 0.0947385844997296, 0.027158724819751363, 0.09175509328841387, 0.0861779977128489, 0.4858643285735437, -0.310694823716404, -0.06225730371026689, 0.3872364924725001, -0.18233968512863052, -0.3441379441715573, 0.38785084948513415, -0.10356956119864202, -0.30387199805381354, -0.28614310295347006, -0.16490603827358538], [-0.26775258092085946, -1.1679637178033788, 1.935287271388765, 0.3211591402927489, -0.33728555056941356, 1.91009239157614, -0.45761692193430187, 0.47222169953764226, 0.4036887807425238, -0.10630586801875866, -0.20898391249125642, 0.09818371351311471, -0.28362539378812784, -0.5442751802569887, 0.07713644430316216, 0.2166235032304636, -0.06001748525995082, -0.08028932962013854, -0.02605354620596723, -0.28287608278359294, -0.06255093528609819, 0.36953689249616506, -0.2968480295638911, 0.5071115379287271], [-0.08441539064692595, 0.34679328858285086, -0.37180760101031, 0.515727555997106, 1.3430916286876735, -1.1285660094751864, -2.184848530739428, 1.1823945473810717, -0.6764254722638722, -0.22638394469629036, -0.0003253346843440902, 0.14647409217669943, 0.15608917227005972, -0.293391168673992, 0.3346093839328002, -0.02244312093003346, 0.4685448431332888, -0.12690017277312468, 0.20480988762058222, -0.1745783268580654, -0.17957737476291608, -0.1280290346342319, 0.1405076477009921, -0.35957965430630734], [0.21110894961406448, 0.7875569302256794, -0.2936363450553137, 1.4219410559421446, 1.7187601408631485, -1.0432388904985812, 0.53914583104009, -0.5648494824256118, -0.6985004312471043, -0.09679768219772833, -0.43495315901035847, 0.5109947796866313, 0.2785959429693882, -0.10341898675226237, 0.9572271118440444, -0.00911717319821617, -0.06117738564935218, 0.048547410979675173, 0.3754307810846003, 0.004890240446961311, 0.23992323926306913, -0.1716974304790063, -0.03518971247645283, -0.12061382702414149], [-1.3702654205835068, -0.21434559314577425, 0.5413006530992759, -1.0908677342972626, -1.2063610572136119, 1.1994822703892503, -0.07604437777164179, 0.32615392854674813, 0.5677350397023859, 0.15780736139616214, -0.6482659980598305, 0.24783945206319288, -0.2366532428761483, 0.36280007890921745, -0.8006477211912347, -0.5855632001329736, -0.0898566752910069, -0.2643301833412404, -0.10593254138632044, -0.06127848954706258, 0.059648376291163395, -0.13035926971152376, -0.30719434084639363, 0.27590801207104787], [-0.9685054989789086, -0.5278501796864375, 0.08715761765810873, 0.23434495992722337, 0.12003969954486493, 1.517228812596085, 0.030337373208547944, -1.4217324119138508, 0.028963192761476367, 0.07967772943224148, -0.1217521574697373, -0.1829706279823601, -0.33978662701960743, 0.08023019607393, 0.10971563490078168, -0.10946940449835894, -0.17376891701493938, 0.13156227624425246, 0.26080084648402496, 0.2417111661027437, 0.055603145049384545, -0.010619029094523433, -0.08912607539639102, -0.034569967194376175], [-0.751491344305616, -0.04116465855366174, 1.1965174232267317, -0.5415429056227267, -0.40829471180155447, -0.024899795444829082, -0.8174775052394209, -0.8116404562778414, 0.07088647631865971, -0.052164126584994336, 0.24403102258644319, -0.5174892386577322, 0.62632109555616, -0.511114356701338, 0.01755084509551925, 0.48956362156175415, -0.08530215542582983, -0.234274115193873, 0.32728363746718625, -0.28955387976668506, -0.08952312263973863, -0.06587157103832182, -0.19003368949799979, 0.014764491302425884], [-0.20446420779008687, 0.8353269555686984, 0.3959123435266859, -0.21539701488134605, 0.319531835297005, -1.2226317106735838, 0.7769039557290737, 0.5732892406691158, -0.059643136774932805, -0.2036290336299266, 0.10682318723527595, -0.3394404221557478, 0.09362502775376413, -0.2603718566548434, -0.2263468785032789, 0.5401781374918155, -0.3415571544400767, -0.011511778944101731, 0.09432527675783015, 0.4982828322183245, -0.14080512109072404, -0.1440703830947566, -0.25907767454729747, -0.10321723952731414], [0.259227496039407, -1.411680553634632, 1.9078350805285544, -2.4971390582770523, -1.0048444338405647, -0.8867992338636421, 0.48660526728844067, -1.4315974759029602, -0.14720828699499647, 0.4931228997341489, 0.008659429358431999, 0.3609794607276253, 0.19003486744804066, 0.4831266703889671, 0.21943804809254994, -0.2520962724365612, -0.1685609144459992, 0.3173209561595863, -0.03217799553537938, 0.6428108607142878, -0.22352655817578573, 0.2435672544645559, -0.37947139243084815, 0.329644409652033], [0.20052757827010798, -0.15343249352814922, -0.3756079593851269, 0.7624226483130893, 1.2737578507090423, 0.3504285425025286, -0.42934427425047056, -2.12878901022762, -0.24164226629775545, -0.07626943093106933, -0.0907121266233434, 0.015081907469656, 0.0845301587619003, -0.2336685762940749, 0.21790299125029008, 0.2988177537954427, 0.23337219503063572, -0.39133238189898445, -0.20212194641516035, -0.34071040674754105, 0.16010906115470003, -0.17810161178597247, -0.09309424961625036, -0.03110062024599879], [1.301936780720559, -0.27783380053726375, -1.9060691805707133, 0.16498528738674925, 1.3011104986421578, -0.1514155362456444, -1.2700649545425384, 1.9315337084614699, 0.3088307606333346, 0.2506943197220515, 0.09275035994955196, -0.11178230221603908, -0.18072199194226263, 0.03352587726284022, 0.44688341039009516, -0.03215570006686235, -0.09481222727076714, -0.13166894522455216, 0.21180835519236227, 0.2368397613850006, 0.05405582274354424, -0.3263338010676524, 0.26487079814611364, 0.3177430377220339], [0.5454274111516545, 0.2801137297410899, 0.9205123626072385, -1.837228714209831, -0.11839471695409205, -0.16335272674578868, 1.9892859450150229, -0.5801599763068691, -0.17228977976527357, -0.045241518015251905, 0.4186454251813021, 0.26116917112944177, -0.39876542012653404, -0.1447628230134588, -0.48152359092573654, 0.20656188848324117, 0.17208653674303034, -0.018356579533536265, 0.11957093373631826, -0.006043091447923698, -0.22979111595988963, 0.17532744601577216, -0.03837014687015718, 0.07068491552381738], [-0.4841406366746691, -1.1925938817008528, -0.876413604496572, -0.1335180526927258, 0.20330374396849155, -0.1869797190204265, 1.7509307903557976, 0.37198921243005123, 0.1470167490521676, -0.5030798413265071, -0.23445479749877707, -0.0750201456902121, -0.2824747752278486, 0.3703353719054794, -0.22135366286573704, -0.3224411158812093, -0.08283460034039522, -0.1934804600048707, 0.245784427938741, -0.26624699599667456, -0.3849702843517216, 0.11787838944680688, -0.31022208263374534, 0.04759157733705181], [0.5839260794397666, 1.16850651774356, 0.5606392575289482, -0.40236424860142367, -1.4967051194546135, 0.3414793603105769, -0.9286466343516145, 1.1150610990352219, -0.21926603430604358, 0.24832398080418708, 0.04578673590918469, 0.5542096566926833, -0.323685919050016, -0.2521383443720639, -0.4670380745856551, 0.0334408791962709, 0.003315341920151121, -0.2226366807775059, 0.4989783984706583, -0.08865431593100918, -0.09368851076104481, 0.429419061538027, 0.18953091150031479, 0.23282890819206456], [-0.6674596597740096, -1.9017669794104968, -0.0190587364643394, 0.9783324109243823, -0.23320646360993275, 0.17733587529459063, 0.0045287699827503015, 1.4797068258465074, 0.21706834324931368, 0.2786992821905636, 0.17880769433239813, 0.6183335533125006, -0.011114033269313667, -0.16456333493144615, -0.0953604871399887, 0.71003711650857, -0.2937685276505008, -0.2713091624112697, 0.08741570290863077, -0.03722846463218566, 0.5039187598022381, -0.2116424049834735, -0.33403081938138984, -0.28057253404740135], [0.2869530637468303, -0.03299569159867769, -0.6676585561172147, -1.371979456067587, 1.289848768362061, 1.0863524139136256, -1.048333444066946, 0.47913427742881853, 0.1999601241903548, -0.12819915987015737, -0.29064448770140855, 0.08985818257967314, -0.38478029087372084, 0.11766045711339401, -0.26399205329795966, -0.21802426812072206, -0.08286615242306376, 0.0832169843092177, -0.14702349439074058, -0.19777747040391097, 0.0485796618900184, 0.07430642084487535, 0.1282916977362367, 0.045323326053283985], [0.307189255706741, -0.3262088724629847, -0.3720747361638647, 0.7000314421799297, -1.1804627748700844, -0.4902418019121738, -0.21937976974385864, -0.07557015996602141, 0.4361919194445981, 0.21487429186903945, -0.21463761082228436, 0.04420779626592455, 0.2869621579007654, 0.04644720182220087, 0.0391742398545346, 0.57315337875845, -0.06636448426146654, -0.1184920335646747, 0.2720188931952543, -0.34125631387085226, -0.3287458022883389, -0.22854259272814023, -0.33309613426752194, 0.10273477285052231], [-0.1744954511804748, 0.18530159690371698, 0.4587347614305566, -0.727473258696677, 0.03804315608348079, -0.4969547172754619, 1.284412750506716, -1.3312280258479983, 0.17199164485674137, 0.2543297774093469, -0.3288027322788703, 0.4754063814965264, 0.1823553262432856, -0.1213792761921279, -0.18997701994756352, -0.2320473432433729, 0.013615751353868569, -0.0017849804287391922, -0.16507590950427098, -0.04656910532552103, 0.03826438253526562, 0.812404587290741, 0.16049568907267425, -0.10013068113204196], [-0.19593811058749802, 0.5976427573697641, -0.3444756824883715, -0.2407837301031421, -0.5492213925935282, 0.2988610341266319, -1.2467668318450238, -0.1380585479318378, 0.4649884748012413, -0.7072254703467877, -0.4393701558433152, 0.370159685661729, 0.7236361156076254, -0.22392294915241806, 0.8477968460412946, -0.07531496002322421, 0.7727409192510843, -0.15569085144642367, 0.47016251214791904, 0.45549067915951763, -0.4011407074514884, 0.13496164929132248, 0.19874972523500983, -0.2939597347043176], [-0.071832349546767, -1.2481556029476393, 0.21334567626490908, -0.3479576966408827, 0.260584861261809, 0.8249694626883597, 0.19397206253310942, -1.113548827932163, 0.06778515430676366, 0.11090952680783, 0.25519183382439675, -0.23034335945348614, -0.08007932766033087, 0.27306477146184405, 0.28025779651735866, 0.6306637066410512, 0.036701453598932926, -0.02764383655438229, -0.05989153612659211, 0.04007914566038116, 0.34618584640850364, -0.24539210564267153, -0.021027092198427303, 0.23805777397601255], [0.3178499876820311, -1.3525326952951366, -0.7974225667084163, 1.511607914576161, -0.013889008486562104, 1.4936646226773012, -0.2913479020778702, -0.03421577075980976, -0.22432258671836344, 0.2721584024182358, 0.7105917730072476, -0.3031744319335444, -0.04645382233833177, 0.009319341633729375, 0.4390450591572582, -0.5952201740484026, -0.2000147318606721, -0.05219304856979138, -0.2619931930694638, 0.6107335872752436, -0.1974054227480302, 0.20019135331480803, -0.2771567200980226, 0.33583092316625973], [-0.9551114412760293, 0.8319658224295132, -0.22712978707645465, 0.6178990531732599, 0.4041090029866158, 0.5418637434404234, 0.2031239627085314, -0.06308001391332772, -0.2735681972358983, -0.10948710718701868, -0.21696878742937936, 0.5153514528712384, 0.3955789350666238, -0.31556505655639217, 0.8669063872263733, -0.22068349135759455, -0.07331093761189156, -0.063514824290559, 0.4861791905612336, 0.2815999816196674, 0.5565784914298711, -0.08477064849971488, 0.10426528930958348, -0.33058928015544714], [0.055074262240165636, -0.550607776260059, -2.1049196214992327, 0.5158120377600739, 1.9735733752371123, 1.0739310602973868, 2.1247846091458955, 0.425360854371574, -0.5453459852351852, -0.12127432381724333, -0.3915540123011682, 0.9880452306430785, 0.24992521521988784, -0.8690959522405176, 0.3044497941902968, 0.06091628225548502, 0.16548896173291244, 0.15025174053727766, -0.07806751856010402, -0.05529484394131078, -0.08187491919806437, 0.005478269578030192, -0.0007439969916447449, 0.175998499410324], [-0.781137423221838, -0.7808271592840581, 0.7438957002502337, 0.41035117017268546, -0.12091035385779729, 0.7779133064367398, -0.8931271235549834, 0.47775854485343894, -0.03374526512696514, -0.18804608088112226, 0.4072071863594249, 0.09657300160946673, 0.3101501607561105, 0.18109273764247455, 0.1754544468377965, 0.8212361487354262, -0.1574410233064019, -0.15163606910580066, 0.13993544112857348, -0.11190148778156746, -0.424768122860922, 0.19897449564615385, -0.19381148652596933, 0.09230479867257177], [-0.1572361358073565, 0.21097339056441924, 1.1935486238375077, 0.008353127059846333, 1.344359639127835, 1.342258258445566, -0.7706394750707167, 2.101296656028365, 0.7171638496461044, -0.12608620108627366, 0.48395981924414166, -0.16725452663882762, -0.2874915496839324, 0.0644100978646636, 0.28658249173593614, -0.5054943873125465, 0.894474258650155, 0.09493966042432166, -0.23665324176454214, 0.1454260154383426, 0.2627248286514305, 0.43345030429009246, 0.2182129101594674, -0.26152056783722694], [-1.0000450225705704, 0.0015936119542420265, 0.7624164315859315, -1.8326308873511534, 1.0312313401498843, 1.1728728152269432, -0.1502755821198142, 0.27239946567263784, -0.15606838580702292, 0.599333985765309, -0.04991431772137136, 0.08461526819497486, -0.23772870104102098, 0.20441091780451162, 0.3072279740999643, -0.5259358473995788, -0.16921396938364172, -0.02886064402698264, 0.2529731119324232, 0.28442252834730697, -0.12506851577157327, 0.09741430034287016, -0.20793726368326618, 0.12322968506477949], [0.3036741542414542, -0.08564041643003555, 1.09824535143001, -0.17972891828274556, 0.020876505922377178, 0.4496350480452374, 0.764061815018946, 1.0185906396145723, 0.33803276221869205, 0.21936061040711688, -0.3073495887214583, -0.031482509058630655, 0.04295707563911371, -0.1345369081449473, -0.049914833047492495, 0.17611758806281583, 0.2154436152588435, -0.1479034791460697, 0.5519647638551449, 0.14505335320552706, 0.00032176436532859695, -0.2471539272389733, 0.10113366319552883, -0.031750029082581434], [-1.2065423007097282, -1.6436493876424652, -0.09098249525500153, 0.09521191383804375, -0.9592369668665331, 0.39218475128962266, 0.5539960968861448, 0.3717427008722977, 0.20189387866768554, 0.13025352997157644, -0.06334431346248343, -0.18918031601162855, 0.19565221893004814, 0.08062737378419392, -0.029153023574445724, -0.3132845498679679, -0.11666798883625489, 0.7648448629657014, 0.6318282490954609, -0.34014750066956084, -0.39341369079978145, -0.05772957503687158, -0.00161474137652459, -0.24267419495301934], [1.5843547605607664, -0.79375138213308, 0.06534080202990462, 1.8095615709617052, 0.7009824067939792, -0.9502105191541199, 0.14746821443651834, 1.0850527241280585, 0.09368766776773339, -0.05593897260503073, -0.17489992267976806, 0.1517907421394878, -0.08478075200832111, 0.03939921226126288, -0.44952346499691354, -0.263709597431253, -0.07405580172927921, 0.0730574448841868, 0.4353962305504388, -0.09484028375592746, 0.369051198911378, -0.0009555813394529683, -0.11127951788560426, -0.06736803439047258], [1.9698264706908541, 0.6571210422211398, 1.1901558841629694, -0.8228565024510518, -0.17727681215773813, 1.2259972857676626, -0.9570456559483518, -0.031316273393841236, -0.37314149906368366, 0.4256165215399991, -0.622339520822987, 0.6615002806436632, -0.09181543715114629, 0.05732436849458562, 0.3549873762531722, -0.6588357924601822, -0.008785291603064904, 0.0009806493830329345, -0.30339814911811225, 0.1892410534225071, 0.3414633721815361, -0.03085767299302229, -0.1552740224386488, -0.18272529329249884], [-1.5625313422492055, 1.3527344190753805, -0.0930379561095341, 0.6248051437495217, -1.3656599850375049, -1.1418023605550496, 1.6706135451619346, -0.28619095664855837, -0.2115543591918856, -0.0586207576710013, -0.25950374648106045, 0.2630567843077786, 0.1600914544798185, 0.3953533077436318, 0.039434380017847666, 0.19547780959218244, -0.16608420402670052, 0.7388266408403295, -0.23228212127085957, 0.4750013861077272, -0.10340028688660756, 0.16826705743065024, 0.1350700516140991, -0.06932871400639765], [-0.3827177946831737, 0.5221410660835545, 0.58016057696876, -1.5649756739676266, -0.8688854346401801, 0.14299790612887034, -0.04644863328298647, 0.3358734182683763, -0.04593710033703485, 0.41395813420266764, 0.18602905212125698, -0.38034754791158737, 0.0094302678738792, 0.3861289426098982, 0.08031611104969305, -0.1871149731138556, 0.13614175111805152, -0.22064323904748456, -0.22848662856582846, -0.27842761223501006, -0.23204132340679076, -0.10252505368939316, 0.059972288432071606, 0.09033786984466206], [-0.28057020504267194, -0.15551832376543867, 0.24575242032934025, -0.4633493165853756, -0.7362746716018213, -0.4222830354981544, -0.04627322455122979, -0.11473157433494753, -0.5159018214125951, -0.7380790592291695, -0.3929346028693106, -0.385958627939105, 0.011546838419072381, 0.031504282869802565, 0.08281822817880215, -0.13144975569431813, 0.4143184183567208, -0.20903972510476612, -0.11135121750406107, -0.033351816742773016, 0.08693843730741001, 0.04680372131543399, 0.17288106615378399, -0.2996401985376708], [-0.3255150703061348, -0.132127186500495, -0.017157596863083373, 0.40761057115827415, 0.39065849501712213, -1.120519075162877, 0.8661480458684945, -1.4174329652156543, -0.611747841493014, 0.4360560640916108, -0.7704961207535053, 0.18572516544936415, 0.2780226932856071, 1.028080195731242, -0.3527878023198699, -0.5399735568213405, -0.07687660450986752, -0.05088587063114091, 0.4221063079779315, -0.11926698423876653, -0.1477047775435845, 0.3620473302065893, 0.2755820638855863, -0.03367749951207485], [0.5854774383011719, -0.5242182678103129, 0.5971923422159519, 1.0420341526038115, -1.72705552972724, 0.6524954520272339, 0.19791002338674005, -0.4036512321803079, 0.07129181962870412, -0.1829346352785133, -0.007509465390233728, 0.06853402018151793, 0.031261189954415576, 0.07711317592906008, 0.4407844005909702, -0.31178089863770625, -0.02520025351757642, 0.19559076056319497, 0.522615104583854, 0.1826344056979511, 0.051867053960482815, 0.22547877270008826, 0.13414955980652526, -0.1394517908290667], [0.43544764084981263, -0.3475624130438563, 0.13869023430358368, -0.7832770216102348, 0.7774024630237021, 0.6360672190922373, 0.6368345610161222, -0.5760661806732028, -0.0834051283277514, -0.2993957131693948, -0.03182720408228862, 0.05117203433358331, 0.36796854611517943, 0.24580326634632765, -0.5559243529973965, -0.21382967691503127, -0.17493366832005355, -0.06589060100199341, -0.17249853901452003, 0.12599153868157564, -0.10016817239046336, -0.29833286073190324, 0.10849025728209476, 0.15719681451522222], [1.7252414790993982, 1.7544662129334934, -0.06548848303164805, -0.23803700536352282, -0.3444072170292885, 0.7256603312036862, 0.9043296004253177, -0.6583767813859421, 0.33941579317359305, -0.5009134247932728, 0.8009435987777521, -0.25711779870247414, 0.0770332116484038, 0.35214120992668463, -0.004063836267890363, 0.1407404036668027, 0.5817905469496708, -0.05441198005081693, -0.06052721444521611, 0.060402026232684855, 0.3879663556145123, -0.14949567329303623, 0.15494199487198157, -0.1599395574060582], [-1.7109094026226348, 0.4582717807756322, -0.020883436199678095, 0.26755576463138386, 0.5226588185091058, -0.9617438642717845, -0.006681932457001787, -0.26098764057488594, 0.30499453126848425, -0.06625295694534028, -0.1367740104972032, 0.11961375597097905, -0.4431753558841361, 0.15630054370747096, 0.7294085073145493, -0.2522796209121205, 0.11166965816048816, -0.48458463329646345, -0.05640578516284433, 0.12352477099398325, 0.09167569654385949, 0.00883512001479137, -0.3415141464973099, 0.06425909612271821], [0.42035701587714097, 1.1049562135993813, 0.01462954477594707, -0.6235918353672285, 1.1987381718705776, 0.7358862228261527, -0.26825441315308823, -1.6119129236518779, 0.5036459412678331, -0.5802315658914613, -0.5450385509941023, 0.25125792533655306, -0.450924781609107, 0.03417272375184492, 0.06901405906309356, 0.7576083705803283, 0.002864939509208908, -0.18928180399230876, 0.09718791563479162, 0.32137321399864355, 0.31436984851113026, 0.32691979825401807, -0.17173218230781254, 0.06092533094879859], [-0.7011721785314765, 0.17932661789760643, 0.537482765746197, -0.35068024612022075, 0.4271133007216475, -0.534072343643516, -0.4861159750715371, 0.4593864978961579, 0.2103898826126362, -0.8046140482990533, 0.10449336315014916, -0.00029967144712620753, -0.20535662315955183, 0.17631905102543963, 0.5444170576583498, -0.24575688695052977, 0.062431452290687584, -0.03146545216892168, 0.7229147407071574, -0.2905463409623583, -0.2874448531735082, 0.02000634515042179, -0.36079799949400915, -0.2853153746349382], [-0.17334742906949321, 0.16750649706438817, 0.8479147325886874, 1.066109255588883, -0.5415825376634192, -0.18376272173560335, -1.3410829473118295, -1.1825409659395727, -0.029432405174542153, 0.10376226239261101, -0.11068766982287163, -0.07492178384412422, 0.2655461844589333, 0.30589150117719943, 0.21404580383925376, -0.5360828378607819, 0.25937733960165676, -0.06176549026889981, 0.1793261169650236, -0.1494895769847161, -0.01926814248923493, 0.37404462551668716, -0.296172246708289, 0.05784531508040763], [0.3243014985724739, -0.39944305493326215, -1.8254784812722302, 0.5434615021992387, -0.7817655980376874, -0.2459947115132389, 0.29062076922568864, 0.32651985471303174, 0.09105126589120692, -0.08940473995248581, 0.6143966833525695, 0.22243182226666927, -0.15940264090487438, -0.11081180124764672, -0.16845592023857164, 0.8397311526695789, -0.14373315743203682, 0.03606828703777804, 0.004053758810844375, 0.278364618781505, -0.4272652807810153, 0.033023989100073085, -0.3767953282624176, -0.012976013349525686], [0.004928564546185405, -1.649284575459582, 0.5327422501039416, -0.42300711686508274, -1.3225104118966342, -2.0153752490820467, 1.1362673003960344, 0.09845120495653042, 0.5480402956211797, 0.6184714313508229, 0.4381938569909835, 0.0253748574845484, -0.018004156265539615, 0.08024859431708826, -0.12558442734770892, 0.13992220740713446, -0.010442625842836669, -0.2973818582104507, 0.038417799502026936, 0.2680204812469522, -0.40455707992638884, -0.37159198580245884, -0.1337126526294392, -0.40177807025992235], [0.15427523568251444, 0.5544906149913623, -0.09446248648031949, -1.17749383997193, 0.6372219888966166, 0.9795315931836135, 0.3843258123859319, 1.338510945844816, -0.1819157569027525, -0.3714621128792141, 0.36922578842014353, 0.2146583620712548, 0.04636485224671548, 0.25894621348112573, 0.03652621695513351, 0.37269610213200555, -0.18789535768899612, -0.24329425107864583, 0.013681270267398625, 0.06849634531371038, -0.2205943455042086, -0.01366615608281376, 0.07210814121801264, 0.3605293124301345], [1.7408502997356816, -0.6330612720148798, -0.44699981323171367, 0.8489995716567548, 0.17092060563834946, 0.24629412281854132, 0.7786873977219223, 0.6342525325194699, -0.9668271981565211, 0.8678917114996042, 0.0588434854711325, 0.6932521680052145, 0.33743508912916526, 0.9492877174657514, -0.1531978616753176, -0.30151436982555496, -0.030789137887892996, -0.1589854465718157, -0.2466032824648634, -0.31641842616229954, 0.21565940264837474, 0.9272864965996205, 0.5532500322253961, 0.11443997144476276], [-0.3287021819765271, 0.14989913276182576, -0.7038145157374832, -0.07331514879947518, -1.0267778647674835, -1.7756585216753962, -0.5588585923079971, -0.5425516594221071, 0.1854716545843512, -0.625667586874744, 0.031970706369065675, -0.09440852034807268, -0.013843964755522431, -0.32064519691252213, 0.21816951747732563, 0.3517494115123886, -0.02528806998582552, 0.11269466186642008, 0.022148120236965777, 0.05122502571680642, -0.17487810816834232, 0.365869332200915, 0.003550589616846919, 0.42869226773641583], [0.8524800832233679, 1.3767209636800748, 0.01754249837569888, 0.5007734751214596, -0.5778266085031056, -0.8035674080814461, -0.3544395894160709, -0.2659550236774337, 0.021049939597323597, -0.5265030692210316, -0.4557507403495481, -0.41268158106262864, 0.18560628450018377, 0.5434377161916347, -0.4609819537102019, 0.054286617961968514, -0.24624862866497002, 0.05944550576552575, -0.12266227333871393, -0.04493808445691954, 0.06923988852079697, -0.06386968010131568, 0.22052834048320644, -0.003901360084208728], [0.3307879687743596, 0.14881150908335875, 1.6101287406631912, -0.08132998509567514, -1.5160138788422748, 0.1763138563785401, -0.6987126571424311, 0.1729196136922101, -0.03923928720185195, -0.23296846430986112, -0.17584708231665325, 0.43236696101621025, 0.08218978909941385, -0.1357446856481753, 0.21974005599483298, 0.8631966156458992, -0.1389009590616046, 0.10622827064402733, 0.23161808705540549, 0.4285035078334655, 0.22806801474349325, -0.09928902227863698, -0.36490433655503535, -0.028971431750761868], [1.0660809711440156, -0.48374689240645236, -0.06930669192876833, 0.5486605069130126, -0.8555808314074573, 0.26882597602884967, 0.43160627687308584, 0.7146264377020078, -0.10401645460872251, 0.1132457320807387, 0.009299044647936308, -0.34635047878731007, -0.266796734656337, -0.6472634428042932, -0.4891107944106912, 0.35411397179323517, 0.10010648494616835, 0.09457464639338639, -0.13489500942095328, 0.001812802836058318, -0.3453284188096101, -0.11281839455280744, -0.2049790875680103, -0.1323613887131544], [1.045375089891175, 0.5297744143849734, 0.3892240341561237, -1.0746773348762386, -2.463064789309706, -0.8228739522554532, 1.256117240077281, 0.10435669161276702, 0.6449005690009258, 0.14278852189137048, 0.058124150945806974, -0.2594078326355343, -0.5998118752557904, -0.09914742163793466, -1.0625856060947214, -0.14515424627581278, 0.23374305549967997, -0.10459043659329795, -0.2734742034138207, 0.0685161180610179, 0.22096052743319894, -0.36854232760788863, 0.5623130630574175, -0.14453781998326376], [-1.8995241933163998, -0.28870847444923303, 0.364965594818028, -1.4619874245128934, 0.5674284869889463, -0.9867050176861942, 0.9047398513681872, 0.03241237789305311, -0.1599261229995701, 0.12141324866934321, 0.12336793136844379, 0.3031666514509453, -0.10516418424461972, 0.16410105227232713, -0.2953819031280527, -0.27511304203838893, 0.3356811350843116, -0.2669771171129074, -0.07755772552581337, 0.3074829937773506, 0.24496016521817848, -0.21684804894853063, 0.8313775162394326, -0.18351219769791888], [2.813473128437561, -1.0506994971324728, 0.29440398217107966, -1.1359377643040989, 1.108931484586748, 0.200462762387256, 0.7989383572619365, 0.10279346676440668, 0.5892327745832874, -0.0988744305630407, 0.5627278676861844, -0.22030060328173737, 0.11589779821237971, 0.4350759002136223, -0.11338373434673212, -0.08041747683032457, 0.35883081577149917, -0.016840275442923158, 0.03130015395348145, -0.07191113166602883, -0.37261838598001573, -0.05144066070442648, 0.011263432987479406, -0.16730515150893344], [-0.9354130478254619, -0.4718397280988566, -1.1734691894727296, -0.7647096090192528, 0.18007230071524527, 1.0822240653291244, 0.7434672720337048, 0.4688655217550236, 0.4143400207740345, 0.015233152687545085, 0.542416720462864, -0.1708760096799918, -0.2021721804309204, 0.16411095702883963, 0.03810848847242143, 0.2025753485557807, 0.5315345970406631, 0.3083298208054412, -0.3317900770818151, -0.027872291402078572, 0.6131085710157389, 0.21580042919376383, -0.10016840356695593, 0.1797387447034072], [-0.39845870480239953, 0.5087070821173352, -0.8005888082637994, 0.3035898279304157, 0.8249450332731441, -0.08326286234450296, -0.49467793604758903, -0.3659567795227434, 0.1255784215607282, -0.21289835129610232, -0.2525740075338674, -0.19238425184133887, -0.4438571933978147, 0.3481694463675674, -0.1686111942013048, -0.33848930344444705, -0.11427922930880433, 0.44455178769063863, -0.21340597908506945, -0.31989050475868863, -0.20332199872031248, -0.11293949385714651, 0.439088598736861, -0.12224474896064562], [0.637252621213044, -0.1811913401226657, -1.3484120133248672, -0.22415310502270502, -0.9408394560597463, 1.4803147459565804, -0.045141876956904164, -1.2824338094408183, -0.010835861875541291, 0.17430972772581194, -0.15797825949162386, 0.13789340546307532, -0.2695850330014744, 0.27475533848397177, -0.7307593094719818, -0.2502463719489736, -0.01236524497905199, -0.15523556559909416, 0.06285029642868997, 0.13417743218437556, -0.1572138467697853, 0.08682565633129774, -0.17306250380955654, -0.02956512478700343], [0.331383534257318, 0.6845621747412074, 0.3958674902047007, -0.17786169856498063, 0.18540712799618686, 0.3486093613105429, 0.878177068349573, 0.33674684030880764, -0.07324913398759256, 0.18523716134468393, 0.5094300602820677, -0.6956267737810472, -0.18113872982215176, -0.05982947077670268, -0.10048022347448968, -0.2205935833839442, -0.11682295270940175, 0.05958602492841766, -0.20069653560072698, -0.1734098097183852, -0.2073871047926618, 0.1988119829032422, -0.12299147679584091, 0.4100141671972232], [2.0888273794208705, -0.10044656404195433, 1.5084919100047047, 0.14453595260128332, -1.5328371230641094, -0.9953223455397903, -1.7487122134556419, -1.4971057006597221, -0.35224970539302153, 0.1473788350064723, -0.8347150302045024, 0.044133445350363204, -0.04414300858052861, 0.74600130445383, -0.20813554354411243, -0.22093990327997998, -0.2065414708127168, -0.11320811813801196, -0.16350965815529506, -0.012962612760500477, 0.09182995235163884, 0.07333605252966438, -0.2356906180606864, -0.3631754745963125], [1.1540121647087138, -0.4721871108336258, 0.6128836139605949, -0.627481707491993, 0.03720952821583872, -0.8831501869659114, 0.7508766684403279, -0.20618553528125855, -0.1406360320347882, -0.00774238624824554, -0.03568153290967878, 0.2411343574900863, -0.24479681864216293, 0.10462992533003368, -0.1514339321665276, -0.1731951853745307, 0.10718812981760617, -0.16811460993857824, -0.08811642548706636, 0.0668121105635157, 0.5654852115108029, -0.14968423491015165, 0.04145939861447949, -0.27996653816428324], [-0.29651747793596483, -0.05581355609242284, 2.1342805967497394, 0.5106423744634195, 0.8234385899225619, -1.0573372987803267, -0.659060283740925, 0.2774025429298952, 0.1794721901549378, -0.1475807464996296, -0.41701095654293563, 0.3085023615105719, 0.5766640617591668, -0.17951874284853284, -0.000261573552815717, 0.7416821578549457, 0.04074020083094902, -0.06010102976123529, 0.25959817786989675, 0.4186186130911113, 0.1915643962466185, -0.24594172592850055, -0.11810299564854625, 0.05728873227814372], [-1.5287330062762274, 1.203150786508074, 0.2923300862438355, 0.11505446563053745, -0.13491268661236147, -0.1253200634191651, -0.5248979160419059, 1.2429215862359098, 0.1486813586473473, -0.3448420066385273, -0.21722376105598906, 0.20711089862924842, 0.70217866099093, -0.1830728812283236, 0.0043656296085268, -0.26751730028040965, 0.3830484954791931, -0.3525570335273798, -0.016626871910980015, -0.27818002388889024, -0.1649025659264187, -0.10965555977098601, 0.34164354024853205, 0.07541146808905148], [0.7023440799218056, 1.125005821060741, -0.263316539977143, -0.6174508091868263, 1.3062924807275322, -1.0345173785025272, -0.6222686093748173, 0.6432511174455126, 0.046915960932979214, -0.7874519512831128, -0.144612886629024, 0.030561452674928685, -0.27953146678844526, 0.36302041485905645, -0.15578488361537648, -0.44946948232577544, 0.46077695649089745, -0.29040824133068854, 0.007422502556006769, 0.34381695853827665, 0.5086356552590547, 0.07341241538154239, -0.3368537958721303, -0.269927149750315], [1.0502260259765033, -1.0236666081533778, -0.2351430512306396, 0.15257888981446996, -0.07567016458288055, -0.7042559143093435, 0.5726578872559688, -0.4459171683910665, 0.12804738494266524, -0.20080564501064363, 0.6242099980474557, 0.00022609809921908799, -0.07318804701430821, -0.501883463724638, -0.3648933267237875, 0.3775184074131805, -0.23578459506293492, 0.1144433255082523, -0.14735484707723245, -0.23227891128541037, 0.03549388389401071, -0.1260074900983449, 0.15340890587459513, -0.2178411519940547], [-0.11203513516049862, -1.8087312607088366, -0.077127822783555, -1.5196598401908392, 0.7013950940682105, 0.5460091033170723, -0.5295790981273839, 0.1581522785194326, -0.4685842851803259, 0.0015161188870098576, -0.2674156601633506, 0.04804021033694593, -0.22995925510030388, -0.05208184524034245, 0.14423313615934907, 0.10430947843998266, 0.20540235271069307, 0.9466839276611918, -0.19319558806753265, 0.24125186489091602, -0.0797990585590736, -0.25009612335307163, 0.2923835385957046, -0.05406535590987671], [0.19341882322449172, -0.044200257245317336, 0.37814580763830047, 0.02338165510981133, -0.3942886098103386, -0.6442477953969115, 1.5004728412205006, 0.18602859621359075, -0.6897754718863388, -0.4792738036732272, 0.12834662889493154, -0.5270901926133137, -0.6136735253346381, -0.44481504388434673, 0.10730018934585972, 0.11031895954769068, -0.21807393490272298, 0.029598998808714465, -0.09387546910526758, -0.33217286851308814, 0.05587186788703396, 0.027470735484444148, -0.29274610685450825, 0.13416779528018274], [0.08017424182932016, 0.6852038649853436, -0.34701495601497373, -0.19631297035926915, 0.6626789087409855, 1.0397900243119191, 0.5667645816914938, -1.2874153885114878, 0.22720499714960601, -0.13802766499535396, 0.1820644945063732, 0.221958965513202, -0.10895790450410243, -0.7711759580493147, -0.16157181045850055, -0.12162688930280005, 0.09996704543341338, 0.3276006159670692, 0.06521485472902341, -0.3111894263213247, -0.1606828147858872, 0.8325344380262193, 0.09534204145860983, 0.6728576519738829], [0.1482424534172894, 0.05967333767599367, 0.4661921469470747, -0.6222552160206273, -0.9237116045551378, -0.018581021269912866, -0.8825008496560864, -0.9207014815517903, 0.12981956212561765, -0.06427949647637592, 0.6169581687057085, -0.2242875910043079, -0.12921639395215193, -0.690297980819498, -0.058663708170986276, 0.3425866605734547, 0.19012310128352955, 0.2450503844638005, 0.19653160527022995, -0.18700692064467267, 0.29741756028210603, -0.28760529553988917, 0.46897182546204025, -0.12365183086162744], [0.03617527426130921, 0.8530826188123258, 0.15750193313278577, 1.071441061241341, -0.8744101875412652, 0.7394659282624305, -0.06971113181166314, -0.7565529477581279, -0.6653037641245676, -0.141358906734266, -0.046904474390939185, 0.147992408964494, 0.5370084958592134, -0.38635404002583384, 0.828459014978222, -0.12818540287865948, 0.12155412196929354, -0.23812944140104847, 0.09916605467347814, 0.5096156689794313, 0.4560565198951407, -0.14554951868037233, 0.4787262332549179, -0.21974029737320647], [-0.2700293904675193, -0.6406362568795131, -0.18268515014301567, -0.5062132410304914, 1.2034851048962927, -0.24363651819717339, -1.3755208179474494, -0.1589043499818555, -0.30117119446978985, -0.13258486636232314, -0.1409574582678159, -0.3763300735089453, 0.17099061186225245, 0.09761524174460755, 0.16933112768182848, -0.21359104297393175, -0.16897975062723355, -0.02079890774123427, 0.12840550987252922, -0.1684419841151123, 0.27554583069769345, 0.013963598936570953, -0.29368866205114036, 0.2653802236266286], [0.4307779988877473, -0.18894916364156833, 0.8508510984316272, -0.643326030201578, -0.7433229464607745, 1.578113078080374, -0.05653346757611561, 0.4853442243385369, -0.2897401111437176, 0.18100051974346967, -0.14401949186631913, 0.334600782508139, 0.26366367230270066, -0.04045709667186725, -0.12808935636664723, -0.8226996555376019, 0.19965598272119947, 0.03750467011771123, 0.2744796659627149, -0.3500187694426847, -0.10092009216524249, 0.06039362752159084, -0.20487341127777944, 0.2157806281035349], [0.525563055461139, 0.5567404317183798, 0.06614885424542845, -0.03534990012527712, 1.0388989465520648, -0.36324909996970145, 0.046929824298052696, 0.6108305488402592, -0.1332574475348321, -0.28245500770970067, -0.07637491809425732, -0.6516943845626747, -0.05390608298194994, -0.35911474035227897, -0.05874587070761443, 0.3660077918410828, -0.34586351994412007, 0.5089508207384643, -0.28755505282270893, -0.2558523110690943, -0.3725439233294841, -0.13300115494694914, 0.06459355484660458, -0.12853487286272564], [-0.24777590986456238, -1.1977520017384575, 0.4658879503909581, 1.0343699130450679, 0.2788496574373172, -1.4454208354137201, 0.5316198555597258, 1.727370080110268, 0.06558577874080176, -0.07343288466289413, -1.1590918269262378, 0.5850884470193648, 0.45626660090429405, -0.21683207108939898, 0.26968753495648856, -0.010889887280388574, 0.27793419736926894, -0.32799986112054036, -0.19106802419030525, 0.03688403987603194, 0.18667235358828332, -0.17076624964277168, 0.3710951179420124, -0.10782780611533922], [-1.242043933477508, -2.1699751873750484, -0.20538070484544843, 0.19293344165999202, 0.7627460689054785, 0.8387740629589513, 0.031116807215643992, 0.48821794667476986, -0.32771563402339443, -0.20162764835829344, -0.23483246469647423, -0.4025837426904634, -0.42411511436539195, -0.2682547914896029, 0.2082262153115972, -0.25889307037695736, 0.04728818105044714, 0.023683921374150506, -0.12174539388521313, 0.08838602082294904, 0.1579961340694738, 0.002311566259505948, 0.14058469080243857, -0.26497321275079466], [0.3910566889792032, 0.1851893409537878, -0.021886458695459923, 0.0037333364935363696, 0.6926258768935128, 0.4634803119694628, -0.4435479115142603, 0.9674434439079169, 0.19070460475269527, 0.34413242580174136, -0.268757341994437, 0.08368593467311083, 0.06677419251413771, -0.07648347434977945, 0.49570131589653316, -0.25670825585126444, -0.06408867689721562, -0.07824416232797088, -0.1555008554307419, -0.20071023306294059, -0.34063384912061784, -0.3510342770069104, -0.09255123749181383, 0.16606150869079614], [-0.5243082768388511, -0.10707971036731136, 0.16162623732205447, -1.4551708283273828, -0.2919500405993867, 0.8721438856708507, 0.6924449977312966, -1.0116907233455097, -0.5909236454810552, 0.2620807989292028, 0.0502850655081553, 0.03849617091119047, 0.040518478966928256, -0.15581211111165735, -0.5167045904812592, -0.033976791656505675, 0.07356633710129705, -0.20558261044805354, -0.12359429494066475, 0.05410003644209122, 0.14260957181292733, -0.22532188898889968, 0.6757915036934744, -0.2614575837121048], [-0.6109808975199392, -0.8029083896575616, -0.18978027877040368, 0.0796259582594954, -1.396986183916356, 0.3836483922713, 0.013871721348260431, -0.042524234327772144, -0.14649014224647108, 0.08647484136052953, -0.1665969001341801, -0.2535495751616879, 0.2661590785109848, 0.383905504402002, 0.09397543266787035, -0.4701709359572391, -0.18839071209635525, 0.05180628164983337, 0.12560778276922216, 0.18480904161888984, 0.3032017295425184, 0.0068772316197776556, -0.31591004093864156, -0.2509343262780661], [-0.4750648511496576, -0.06703046001912809, -1.651901785141422, 0.32590423034139365, 0.244095918693928, -0.0005681678655953127, -1.1272833585761552, 1.1194722288715948, 0.03472452202411611, 0.06760722893706102, -0.2851225440134747, 0.02110614841863695, -0.254783538637575, 0.5587728982160498, -0.5120967623165192, -0.34465250557650257, -0.33488495990164463, -0.26609045139713366, -0.07927353688709497, 0.08078008035093122, 0.38553499961167265, -0.03196054938219409, -0.17339240321701868, -0.012788389879949161], [1.074150949281332, -1.456515072345781, 0.4261214040831726, 0.2603318638240742, -2.2777285340930424, 0.5646123309880002, 0.5417505881682678, 0.6424265577335073, 0.3621656221745464, -0.18418573768346444, -0.2579815988125107, -0.051273687678588045, 0.13142391343506013, 0.07691626115052055, -0.04862609007993893, 0.5165012609917328, -0.10868023145179231, 0.06922563986071546, 0.8058051625364305, -0.06790857473126492, -0.0013800750458921956, -0.25666835419304046, -0.32713412464003105, 0.25252031231422295], [0.24202722237752528, -0.45097208521358273, -0.4496931868907299, 0.5598114545584764, 1.1158681226896696, -0.34609609698168314, -0.30322489280322, 0.6231047884701357, 0.4355684312169667, -0.3010129084025835, 0.49765224202065333, -0.17089007518011134, -0.30695111416902404, -0.571846014445298, -0.27550608072717775, 0.22747897081094967, -0.2881672125492733, 0.23383142782728694, 0.10297426291400588, -0.13469702268732234, -0.24472874679885803, -0.09114122559441058, -0.013827695257716618, -0.18572857945871973], [-1.7416294349955308, 0.4538571105547936, -0.1814884346710165, -1.6868597331776896, 0.7536884911588305, -0.7290517750215755, 0.6726857522868792, 1.2094367402572461, 0.4534344532993828, 0.45818297193125307, -0.1374805661841023, -0.2217155317448143, -0.2445854181495907, -0.5096401530114952, -0.289194721962682, 0.33204807021571037, -0.3462698596803194, 0.17362900438703793, -0.3951448499530477, -0.08951087028633713, 0.12148276930931332, -0.18458340668187714, -0.11444684704220177, -0.2960850194852144], [-0.9603755916479692, -0.8956360551252792, 0.027994565922324573, -1.3156954132617233, 0.7186298462994282, 0.27038005133037596, 0.848132354306522, -1.5490402651757762, 0.23673423597208065, -0.26418016744548317, 0.11873958397150663, 0.14121848994061242, 0.27118721702165155, 0.2872048956990898, -0.5589366817423306, -0.10280453645754417, -0.11792839846705805, -0.3413238740753942, -0.08627711776336051, -0.14367688102923248, 0.0419439665635936, -0.05337560151135628, -0.38411320549256367, -0.44887156784525645], [0.28371061514941387, 0.4727848072902643, -1.655504566609242, 0.8837942974251921, -1.1854998459300252, 0.27088092926250507, -1.2366302307877788, 0.7116343138859139, -0.16640650533072876, 0.29605280135222695, 0.4738415549998311, -0.5359818190219188, -0.45694248266612136, -0.6779003965980765, 0.029753222146150813, 0.28766123242496583, -0.40160949385358224, -0.0007855273457313576, -0.1100799334448229, -0.30432987907332293, -0.024529776800042733, -0.09630002710678463, 0.0838166601065021, -0.4297378021406542]], "0.8": [[0.289255702136749, 0.7730147724169059, 0.17754363144684984, -0.3381369989031399, -0.23910923868579095, -0.4111839033903036, -0.6101942563609568, 0.5690474940720678, -0.44529460154129263, -1.151748374209076, 1.0551104709679842, -0.9227039141918552, 0.13848930379371252, -0.3248972747603689, 0.7080126578427898, -0.4009881658312987, 0.06615282427405267, 0.1749948639892463, -0.1258333669644541, -0.8046427236864354, 0.3666151044500844, -0.5736355807590556, -0.2460383582489237, -0.8549615729299], [0.4070005988959363, -0.48019709753352413, 0.8817509890767913, 0.17088932286393854, -0.4191579835532893, 0.2270377291463308, -0.058048722052615936, -0.33130215719617506, -0.17657112424515306, -0.5823856116331834, 0.23098429465175022, -0.12231031413294585, 0.18573451945515243, -0.41705888736585117, 0.8374025352080184, -0.0317156551771585, -0.8092579445621252, 0.19671632188650348, 0.22398891201447596, -0.34381203700092183, -0.6120928334115218, -0.09974634754379982, -0.5809724973101937, -0.4418525815852813], [-0.8039427014060826, 0.05761894127192094, 0.15874886931227492, -1.0336537342121144, 0.2842849070816475, 0.334557309894445, -0.24524003996975238, 0.059888313484392386, 0.004680890509701196, -0.9876799420320657, 0.19230049052424247, -0.37324691890245426, -1.3342742954015, -1.350963236391, 0.9007362192641399, 1.1592043737333493, 0.5544825209190425, 0.3931655715712429, -0.3431589305313533, -0.24762632529679596, 0.6875436845004345, 0.811540977109397, 0.265571494148372, 0.7403529834492105], [-0.07204319176640875, -0.3108685151313259, -0.1577933114431201, 0.6431456956173782, -0.6488891433833944, 0.1577947772125654, 0.060317850939219146, -0.30255262823705165, -0.4735991576110057, 1.685161156043701, -0.6532207183943541, 0.5824449146744975, -0.47670565723564023, 0.8231805525779263, 0.0773500180666269, -0.264323629251593, -0.03763687581014026, 0.0556560494039919, -0.45040228694244083, -0.4948070129049025, 0.6036191815954293, -0.09174614127306323, 0.6263801855152883, 0.4621413657017886], [-0.1423506907360326, -0.5484144525334854, -0.3965927637220087, 0.07293987209008933, 0.17810703394461813, -0.3698193573142846, 1.4024389468466307, -0.24185391011081322, -1.130962520821984, 0.5052623371709557, -0.21791377637765333, 0.7377179959729652, 0.9545132526699477, -0.38028443523961325, -1.3679802463296784, 0.03201763454641897, 0.14389340012746568, -0.6437166558286914, -0.58913773598843, -0.6398937027298165, -0.1360515071630702, -0.47893800733216796, -0.20115095272961134, -0.3514143386524144], [0.10759383333272798, -0.055100398320142054, -0.17707796777953136, 0.6215878773927158, -0.19670623299060175, 0.6675800543612632, 0.5078271977980282, -0.45200937779520134, 0.07014449093789328, 0.22649921365469702, -1.331722167934769, 0.13914733665337106, -0.5730380038055595, 0.5838782375364527, -1.9120967980782426, -0.3699265353939008, -0.7253342619409369, -0.6034186968105351, -0.20844657376889644, -0.2382701480862161, 0.016240734619846455, -0.4754178785623992, -0.6453379971178037, -0.09912276720319448], [0.5074578516333311, -0.2321275451079458, 1.3454287667603255, -0.09803083834972925, -0.4117290898555595, -0.8403451592655282, -0.6299246355050674, -0.246409820440398, -0.45574501730046824, -0.521072629794863, -0.10126415305764634, 0.2705743030373059, 0.3596201466113629, 0.3995598467198639, 0.48939423025387896, -0.01080963548685349, 0.7750692981806104, 0.1553949397350624, 0.8206278002025459, -0.04531990287954833, 0.6219986655377312, 1.2197130697116338, 0.37150734246968165, 0.18598195613333704], [-0.38790075523252737, -0.47599806801118794, -0.3205594045059521, -0.021550201944721143, 0.7004694387840372, -0.7438046708284786, -0.2834844107014709, -0.41143403970817083, -0.018623188680291385, -0.7062444912372137, 0.5025983146906117, 0.25756514236779726, -0.5562951874282713, -0.5292517899135206, 0.18645416855225808, 0.2140751244557381, 0.4331955443247185, -0.15948633831066542, 1.4008796458426538, -0.699095768553287, 0.11286361856912688, -0.04216417092985213, 0.718524734325279, 0.16069243943543107], [-0.6155884788457593, -0.49179048284235155, -0.42269703558532995, 0.3724469398531537, -0.06413673253728408, -0.20237225757296043, 0.2599258957433987, 0.13445266021780786, -0.07680961856389193, 2.5660654814528683, 0.6698269184826138, -0.27089358385437357, 0.831744761630546, 1.4675991228800043, -0.890244164675237, 0.13287809060716899, 0.4794463085602657, 0.5147030967109559, -0.4062811706852885, 1.0655574362907247, 0.196369166553459, 1.0415928548962627, -0.0921471186401638, -0.3890515234428516], [-0.04680111612587732, 0.20418611376205612, -0.3851305559652451, 0.33419775596413415, 0.24334654996933802, -0.14397775984178537, -0.5955476246690454, 0.6823872236946779, 0.9539983312153199, -0.1012593861380597, 1.4916198380294896, 0.060177973707452585, -0.9745568605217794, -0.6009418849272447, 0.6357756477400656, -0.3721105607439494, -0.11976641106028578, -0.18046097163433564, -0.6840284215260222, 0.46117336785776775, -0.47653779745585423, -0.1911654784614941, 0.10630298058344825, -0.8478896240424321], [0.09300715210321539, 1.3288406008841995, -0.3002039017728122, 0.43037803221204385, -0.17595739459006451, 0.16544983806015615, 0.3637076258264547, -0.3430863836057937, -1.3937819629270045, -0.5073073014525306, 0.1345208717925163, -1.230180626253754, 0.4443111049067679, 0.38363043188838053, -0.2777764947280865, -0.57434646863713, -0.7185028700873806, -0.21555764861927618, 0.4986144211491474, 0.8633304879681337, -0.643172023022927, 0.863031844001049, -0.6014728479897605, 0.5240444636738403], [0.007460692581107475, 0.11000273289339568, 0.07208727705128903, 0.32100311392091124, 0.5032819003129518, 0.4349140641644603, 0.09718348206697494, -0.1432705537349838, -1.0779920054995955, 1.013528316235233, -0.10687163790867317, 1.3971579066728952, 0.5208533172152402, 2.126592289204544, -0.7999355308239314, -0.14994058278963346, 0.05700226189489371, -0.2616679955110179, -0.5204195197053793, -0.6467281513214345, 0.04361550748035825, 1.1780376663790286, 1.285224315092041, 0.5144980663076772], [-0.44586874178885505, -0.26802246783204314, -0.23958969093933877, 0.3578022841720123, -0.143102910364453, -0.5296327909112556, 0.2669609470080956, -0.34482966803419834, -0.31801699185910837, -0.35228487035201994, -1.795670945967615, 1.5347314807189358, 1.6611020821045408, -0.423149928512406, 1.4327366745049106, 0.7487367421740645, 0.7335686094576926, 0.13983163547622515, 0.4343164967443783, 0.3891475074242151, 0.49292951951342323, -0.027087242107632185, 1.081436384316878, 0.3321586450777789], [-0.28566354151671763, -0.0532834494438249, 0.24670481129685667, -0.9628846370525572, -0.49572897179157543, 0.12917240329708074, -0.19587954383478337, -0.37192975716395604, 1.0701089118937746, 0.055808070999692885, 0.9566904000081571, 0.8769052843508452, -0.33772279256231685, 0.7723138415897286, 0.8206370734368992, -0.015673436918314614, 0.9547385494393832, 0.21751513447143897, 0.6927089246072033, 0.5165169504318344, 0.5557243938505382, 0.2985174358370753, 0.3771983099907593, 0.3672258694894827], [-0.18687100257835093, 0.6262904060970639, -0.20423851245916808, 0.37057911587517595, 0.3945436289199163, -0.16159483741445224, 0.18149242476796681, -0.1887505349552944, 0.2231880983267207, 1.0833980301112476, -0.08035022678403528, 0.6578907389404137, 0.1383555000924514, 0.3378695621850638, 0.5314054264219467, -1.323924277575335, 0.1140625183343081, -0.35544744753728963, -0.7065886461267994, -0.48660017324584276, -0.12891079539674058, 0.2613370330669605, -0.20536889415334061, -0.4983697174453871], [-0.2172360991292206, -0.4326930347631437, 0.4417506682795487, -0.10329028658370484, -0.23082728871494015, -0.4762502016359682, 0.8195135591582158, 0.3382924657806862, -0.8173556858806695, 0.585182195576418, -0.7456092239310304, 1.2267938408563657, 1.0013145943796877, 0.06802841682149821, 0.7168351842844646, -0.8081730481409177, 0.18788840070035245, -0.1481676651320394, 0.4574021793897088, 0.7649341994050407, 1.1126463316056077, -0.3330499425284168, 0.6272098361959633, -0.4803259632072934], [-0.00694327259680464, -0.25083241485071656, -0.7256533952345423, 0.19104707872018936, 0.1602887254602704, -0.6067893611100272, 0.5170484549319937, 0.35339168076506994, 0.16309722016876493, -0.5950049572875326, 0.468925546993091, -0.28400130351929675, -0.5365412112531088, -1.0591760992248553, -0.5416242136221687, -0.3186662388697188, -0.05086458323027292, 0.3170208841907174, 0.04508911563508792, -0.14321368435346266, 0.08429653215322143, 0.26472928064781337, 0.06901991283983969, 0.8135147016024541], [-0.3720701973136182, -0.1922007144411786, -0.19044784290335973, 0.1351059842899675, -0.04164816304208431, -0.7139033387016587, 0.6630941590936212, 0.1501665173047418, 1.5086135218835208, 0.2901212098649159, -0.15584217983865795, 1.5163337583645955, 1.423961686480047, 0.6022364066259244, -1.3131990424105582, 1.0431396515967162, 0.15345856745186112, -0.05905806266861077, -0.09277789456181577, -0.692803995706431, -0.6746488393306662, 0.5764509594212304, -0.3064523887674539, 0.8519796528272898], [0.6066484913818655, 0.5712878910819945, -0.08392911446406975, 0.21244004115676787, 0.36885689149426415, 0.40517111663356453, -0.10231119094230018, -0.26300601467616286, -0.43574611391644263, -1.0912880152553899, -0.7169067728991316, 0.5455108894327403, -0.23791376248973342, -0.38514140550942877, 1.2689838912447193, -0.45392125095181907, -0.5703981585201325, 0.05377162678711739, -0.30943095585546687, -0.6114404505416331, -0.5560700403718337, -0.6630720955854771, -0.549374017693373, -0.8074500871626791], [0.06706714626789978, -0.2958730895869991, -0.2528840042502744, -0.7994979049986177, 0.06500463003911201, -0.42953046430858477, -0.2854463569786419, -0.012985734995837038, -0.34116239543383536, 0.6794430815828307, 0.38314105781571434, -0.48526253053593993, 0.07734871196120162, -0.5737847311631732, 0.6414975004560726, 1.3483125588669784, -0.46555358642959344, -0.17201936031879284, -0.2042012821051974, 0.3941785440379366, -0.06004744209676376, -0.325976131072843, -0.5569587650208649, -0.5954647953051931], [0.18971196092424802, 0.8387905334403873, 0.11622314793113582, -0.5363268059014515, 0.08692212311164135, -0.2292000623993695, 0.16090724890312136, -0.2927803467899397, -0.5853998482273082, 0.7230700618987588, -0.13860823164017788, -0.25451050869490927, -0.08865413281415191, 0.2640239667980048, -0.45788907634008386, 0.9295319622358289, 0.202511424598785, 1.782297869432124, -0.28725881642339257, 0.6174468696026228, 0.00818241139710594, 0.6352092390569096, -0.3304315840438174, -0.29241215957996225], [-0.26038073779848336, -0.17346359243828988, -0.28765660572023494, -0.7118764938962514, -0.2848624543764791, 0.041079331677495196, 0.5352434239279256, -0.11930912561328183, 0.2834233535793263, 0.04370800683195559, 0.4873628559053018, -0.5538510641016108, 0.625545263438202, -0.9270650242588022, -0.6615049150327308, 1.0473901871134785, -0.6181933779463391, 0.6407829241090517, -0.25029152292963075, -0.32742145061491496, -0.7904265327522538, -0.2695465530557857, 0.00890651440874362, -0.2400343302585795], [-0.11214752504300658, 0.28664985397465337, 0.27885399479920503, 0.7489071435973655, 0.2983389845388117, 0.0385521455806558, 0.5996528313501194, 0.6865510507208923, 0.12911892128613028, -0.39596041510887364, -0.349990489254041, 1.0154485667645823, 0.5488866778688579, -0.2984587762766282, -0.8468415604614997, 1.330893132883233, -0.5360745470955024, 0.05331647168630934, -0.05205914040742638, 0.09451055939170838, 0.7243543065743888, -0.37729234643068027, -0.42520703017267025, 0.24872277493039205], [-0.15777843861002086, 0.10882126170881196, -0.7988799195576914, -0.08877254457985777, -0.385125612920279, -0.05187424450426615, -0.2507720898040417, -0.06310142958160267, 0.1831855936847176, -0.6376863605772766, -0.6418737764836883, 0.9783900977665312, 1.0545557932696532, 0.7090590070255284, -0.45956823347200704, -0.15311274706336983, 0.08878082104816057, -0.18973543631899212, 0.0671095348928708, 0.16071244007226143, 0.27937496244207194, 0.20746647419355527, -0.2140546116840179, -0.9095311896727597], [0.0061644214412828495, 0.25022784345503596, 0.1291081861110141, -0.17310002046178563, -0.5737642843491847, 0.6213326223563557, 0.6365552037741965, -0.19061075570434918, -0.441291595511628, 1.8683839113124192, -0.7062916391031937, 0.9631352068929049, 0.6378142195361882, -0.08131019834736776, 0.48456645986361513, -1.1130100186381018, -0.4513363822761987, 0.45674655409204584, -0.4195375599994905, 0.04059201481956743, 0.022595618371270308, -0.34792338706778236, 0.15880783843158428, -0.5905263763714632], [0.29872098206897246, -0.6014180595674881, -0.7413894441537543, -0.048569200713489705, 0.7108616404748841, -0.43866506866374755, -0.41548201851792427, 0.721087398490786, 0.30990561681387985, 0.3146703330828281, 0.9901843901076707, 1.1144991383136154, 0.8997774764666905, -0.30492419893745254, -0.12793849087842005, 0.8060649490822025, 0.15364363312192209, -0.32428467572639513, 0.4212817793997396, 0.7737986979658507, -0.7695319537582093, -0.10813854900721967, -0.4681958786155649, 0.3557465397220319], [-0.7821538683175298, 0.3146436522652892, 0.2538099842083387, -0.02143204979477718, 0.11385307913219851, 1.265716760037709, -0.5522624807770996, -0.12848879321879264, -0.23007040999721864, 0.48916497590667096, -0.7943399598599836, 1.1535365365002381, 1.3308507842781319, 1.4386819825170554, -0.49737780148824545, -1.1528765669288077, -0.1332806027614382, -0.3868232404519876, 0.583122828117232, -0.4343923583433106, -0.23381837410703674, 0.7743202836241708, 0.07890689382531499, 0.6752855567098095], [-0.0533151583672066, -0.24870146778369764, -0.6344278503656685, 0.7462515996272009, 0.1284961738380977, -0.7692183968727914, -0.35411933714071137, 0.1895563698826724, -0.002651686944051333, -0.6523378359672014, -1.445086927097203, 0.7782499602677081, 0.8861736789271764, -0.30168606996797265, 1.1740897886793906, 0.5058659745596893, 0.9703848069655674, -0.22053352724343633, -0.2579804989366205, 0.8487819048944159, 0.4093055250460139, 0.6846863145782811, 0.6259876185186382, 0.36964431255943253], [0.22915620401014183, -0.5652459080132979, -0.027386102464054516, 0.17785174364491715, 0.20874992239059156, 0.2309301988104846, -0.8775663527185865, 0.8269290302891865, -0.558603524270913, -0.6320516408258716, 0.11846919590135023, -1.6700114315478094, -0.863547084350058, -1.3740155615874143, 1.4489601296441967, 0.6924162072574588, 0.9925220100099136, 0.04698716673802792, -0.15454202680378432, -0.37761018880098823, 0.6803714146703393, 0.8088571756105295, -0.34444963114737814, 0.5678745993866335], [0.14449252660231607, 0.8037129786633378, 1.4069070797271337, -0.0019310499291240477, -0.5479864137388948, 0.449086155883788, -0.11021506683153628, -0.1892688002869444, 0.8281183083601947, -0.8820089176110368, -0.5555087830750018, 0.6395260866160034, -0.0797818033257639, -0.9975083286340316, 0.20049663495274855, 0.39346483543154875, -0.37024435748225304, -0.06250635010247949, 0.4201604010083095, 0.37868993658411965, -0.19917984154560753, -0.019524502024025125, -0.20059513252227815, -0.18723666309054518], [-0.40342509656648295, 0.7538663358377002, -0.19790145845015455, -0.5304909456919429, -0.18217020875799564, -0.49010250421674934, 0.04806887471168104, -0.17510050838558816, 0.5427571852369265, -0.4273973870882744, -0.5528915370393727, -0.09165910752765428, 0.8435984276227384, 0.48467989118775906, -0.010751930547733062, -0.8420384174566635, 0.28635309027047706, 1.2807833962172261, -0.7991019368831349, 0.5428514008438271, 0.45604361992571396, 0.5163805232304531, 0.14186857933546151, -0.2947882538086519], [-0.4140529722147576, 0.2958966969466362, -0.2953613984745855, 0.375312702960495, 0.6128233972805911, -0.12058317862166092, -0.327816442624797, 0.09843047724713655, 0.5999011138830855, 0.18742689931748496, -0.6146452928555163, -0.08924795554337549, -1.3469922567486992, 1.121177135380947, -1.003150925648542, -1.004574815413937, -0.3098510367740955, -0.688815941140351, -0.19247642248824168, -0.3473023682543586, -0.19769887811381498, -0.008628441501079488, -0.007183036684648939, -0.4766717391781297], [0.4440353573596582, 0.040956480906894493, 0.08494009495926264, 0.05509011960806091, 0.17089426012063627, 0.3397191565515933, -0.3556420396947144, -0.2030297962543526, -1.0445977889172136, 0.35201905310418136, 0.2242095727953773, -1.2047116936265003, -0.9815892556943081, -0.24901269470855522, -1.253747937563381, -0.1396500536916948, 1.1812608807048814, 0.20123592219174116, -0.48236962124227095, 0.1649109233078435, 0.635020072796364, -0.41479202940125326, 1.270888398577312, -0.07408789384502651], [0.07072267117265904, -0.23860228754839288, 0.08308060313014885, 0.29527876533700015, 0.015978328674931173, -0.23283521088793382, -0.38888376027098626, 0.7845914264943321, -0.8157319286768532, -0.5135939263385481, 0.9539494267550684, -0.029975064427873836, 0.5959874550673483, 1.3001576970791564, 0.4748626358851116, 0.9557046318795903, -0.4356309022083312, -0.6966768479769466, 0.3228615045597987, 0.2295453092353148, -0.7090962871981141, 0.38086206230954955, 0.06976985556345294, 0.13372193440957691], [0.4383362511368731, -0.4301321319769783, -0.3912840964252632, 0.8659297766707301, 0.729295037077974, 0.10714320259715547, 0.5153188519314593, -0.6471303052774883, -0.16699010751509308, -0.40817745265951755, -0.2742325502269212, 0.008283310940336557, -0.8892951216780044, -0.04180965457067724, 0.6648134821006897, -0.20421974300476659, -0.1406552357316211, 0.4225092388033862, 0.29069654799386196, -0.5028312942835905, -0.2919080304653395, 0.17353598967490227, -0.33229261781233393, -0.49290036677352494], [0.05210813720128528, 0.3545305864156896, -0.8859352171872547, -0.2674579941473596, 0.3903492900440618, 0.5733731236419745, -0.30295414763980416, 0.13844952908497582, 1.3393764696991968, -1.0244049088386518, 0.15837047572233504, 0.15137129099388316, -0.9049512395318334, -0.023157777994722472, 0.24016914739972048, 0.867401335903817, -0.2046350312889539, 0.0639017705560828, 0.782548948914394, 0.06682453957873895, 0.8293745543363741, -0.32925818541198526, -0.6493473460120578, 0.6398265575351824], [0.7563235758796357, -0.11892535781562072, -0.6302923300457114, 0.040365503373649796, -0.1568513969523507, 0.6520891962993942, 0.04910220571373878, -0.34431851382413114, -1.5133894368559673, -1.6918707505024977, -0.1660669030227245, -1.3620698966627847, 0.5206355522283997, -0.6271729910171535, -0.5709954360965396, 0.49540363907860296, 0.36141513809694376, -0.27017967403636806, -0.6847931475723045, -0.6246564475566736, 0.26061769485778924, -0.14694221102369145, -0.006031420463105901, -0.17864909976825857], [1.1084892895396945, -0.1687630446379993, 0.24634943393674438, 0.35503688912798426, 0.3910319988590964, 0.12793034302826714, 0.24842256742362254, -0.01970696558702832, -0.09538521990695782, 0.214725622413158, -0.30771144576081116, 0.17318668653865538, 0.9190042421611883, -0.18998102439522166, -1.091529173550159, 0.05378864502056185, 0.21114623155451717, -0.36014426394919763, -0.420031186100965, 0.3656995809452292, 0.007046703010936036, -0.05923860136645726, 0.3057632797785345, 0.3078396121754569], [-0.5733347676280485, -0.05055895912635059, -0.07932273808206013, -0.009252610134786565, 0.08940927139426648, -0.2426635290995225, 0.5926102824098538, 0.7030130196795306, 0.4745498669074351, 0.17958901612338424, 1.3147882729410056, -0.42872742867449903, -1.5012347160798307, -0.903733869115949, 0.057269193548006914, -0.014686926534452992, -0.4753417787158363, 0.29321356797049736, -0.3765151213784296, 0.26110067490812466, 0.3010312706534683, -0.47501313428256886, -0.11661906773038534, -0.39028671241148527], [-0.917287848295714, 0.046067050512810154, -0.32796494412389854, -1.0452427555414614, 0.21692250636228289, -0.23992071882538996, -0.2012876057343904, -0.27776997023723443, 0.887935402501307, -1.6389645276027096, -0.03478634740328349, -0.04230142650739303, 0.4369645915898641, -0.017048380957850735, -0.266438401023505, 0.3736392200736489, 0.9484414899041855, 0.44248162132542196, -0.08766634707658987, 0.2711002909647482, 0.6810590248146446, -0.43792839908230763, 0.048819682689711534, -0.0651073420640072], [0.5301385650641107, 0.5647413740883207, 0.15136970702303892, 0.3622366339270797, -0.0262275406636218, 0.11271077072716996, -0.3723236465040507, 0.025587435563246115, 0.7382198759468583, -0.15943049482614774, -0.9839018927671046, -0.2793598617777584, 0.12542005200844086, -0.13618404649596796, 0.45908812099550883, 0.7158494114543582, -0.41537202524408395, -0.2142354771704078, 0.2572372585569651, -0.040337507164058685, 0.429261063758847, -0.5072422555558131, -0.125205847082994, 0.38418391944309], [-0.2626983468643588, 0.19943798376202462, 0.4186307894551807, 0.19925006478606522, 0.5770629078930989, 1.2975452792691409, -1.010060988390299, 0.016365055700544032, -0.9689782082315024, 0.7431017753691599, -0.5455224600227738, 1.4164130151643803, 0.4956957388118666, 1.538412141727893, 0.02757353431204531, -0.38903413171554624, -0.28855372446219935, -0.35943070124532245, -0.10862968294398583, -0.4701192899991038, -0.5046559452638998, -0.032639239629870635, -0.052202583394129996, 0.4845514466760925], [-0.1988593287840184, -0.1504523620368111, -0.6423370092166057, 0.08897267611873633, -0.09408920010484009, -0.24641203557210922, -0.14455472968262684, -0.2517573665912291, 1.41824408915147, 0.504257952023565, -0.4512430128794494, 0.31002515572769374, 0.1465401323100403, 0.1882354043184444, 0.014775001264043262, 0.9217582767882734, -0.6476793128926955, -0.1567020945908034, -0.43685516391594864, -0.5383931360806881, -0.1963987711863964, -0.6260704931052272, -0.1660382897055162, 0.02262999522521273], [-0.9800570960331098, 0.49647337501303607, -0.1303250700744674, -0.3385467109771809, 0.16865962994593106, -0.26019639664219274, -1.04157235183395, 0.40244469487968765, 0.56350417266888, -0.09153492274562496, 0.4410448928797826, -0.8546306362926421, -1.0319130985189127, 0.3461650023809148, -0.5905710782499621, -0.6815109401963382, 0.9549483867236588, -0.5910808976251429, -0.6867702957342181, -0.17524933114530064, 0.9473420088603528, -0.2813353404520281, 0.03627293839576962, -0.30304789094234724], [-0.6867238775467149, -0.04996709563700488, 0.07532825263589653, 0.6423200093155126, 0.5798228777393624, 0.12459999091609375, -0.382430330104268, -0.17356744688728487, 0.39813680939826834, 2.018633087114369, -0.6280065032559053, 0.30602991033675675, -0.3855247246598501, 0.4083379037388576, 1.489402616103921, -1.257688553479671, -0.6934261040456694, 0.3225939177826489, -0.745674760563223, -0.038834016269755744, 0.35400628334118467, -0.3965617132919646, 0.7264805728501652, -0.525407960224733], [0.5304451024733484, 0.7954728811645196, 0.28098326954536923, -0.20852435240155326, 0.5050542012107484, -0.1267567940015407, -0.21629404524148083, -0.1130266820026241, -0.5990632785164839, 0.9514381171784585, -0.6661818022341502, -1.5838557281001973, 0.2218537550035108, -1.1673976062462486, -0.17189785927534904, 1.2567814404114932, -0.23246212572596256, 0.1818279181931874, -0.6316208172748206, -0.23810283014043168, 0.5082601113008226, -0.5255466275098365, -0.37586606267296124, -0.5112446292629546], [0.3113728434234397, 0.1582166207345637, 0.498959347214239, 0.6195932871894408, 0.26489962544029944, -1.0360394076429253, -0.8184948929719293, 0.08043219267829575, -0.4031480023473409, 1.0177336800715056, 0.01118569426931121, 0.2219174806974981, -1.59663916719992, 0.586839355087737, -0.5607120066006421, 0.576579967876682, -0.32675454150967376, -0.2573691967993936, 0.4563969955820297, -0.33385481222004615, -0.38026828832765086, -0.5657653505490257, -0.2668423602470747, -0.03203338831518631], [0.023039799574482583, 0.952658700213932, 0.002330040440324697, 0.0014592678436592295, 0.46527834553681285, 0.5421519479620883, -0.1357173859289468, 0.21953368370006496, 9.261230305609775e-05, -0.31895892623358596, 0.6930429623702599, -1.7784840915917235, -0.8927791133430014, -0.3192023668595949, 0.12317740139102987, -0.01291618963441914, 0.42325304449379375, 0.6102936659548619, -0.15635734149930652, 0.2742539099067387, -0.5947058515187404, 0.11498120799457946, -0.0034727711289237245, -0.486990136949843], [-0.4475696592732388, -0.35558904439156164, 0.6156007694371588, -0.5337120739950044, 0.4552392403524618, 0.3625533395943826, 0.3339720756042788, 0.4139088528982652, 0.24347706531607735, 0.9858069582374355, -0.5701249275143452, 0.7016082570547829, -0.5293768362113683, 0.4002110470346001, -1.4508027403258952, -0.4991024193695695, -0.532961112786174, -0.30014967277320875, 0.10773829086655863, -0.512511873795944, -0.8674079101058053, 0.012962277463261182, -0.30486424458738626, 0.22230769156374858], [0.2997991439413985, -0.860910356423425, -0.47058471363739574, -0.1899535510652162, 0.45175313268762984, -0.47641763312256713, -0.35509631645086187, -0.1500967042431747, -0.5106349140921114, 0.8743017238701867, -0.04346004393989915, -0.8948583381596175, 0.38911589689634096, 0.09330168617792474, 0.7496623584122416, -1.0336991690760937, -0.26366245206419153, 0.6284816365226733, -0.3479029776811403, -0.2035340818077992, -0.23046505418823734, -0.7025751437199502, 0.24063725843179387, 0.19306192868443137], [0.6311548539064832, -0.5655519169388884, -0.6402759833487833, 0.3341038412758485, -0.9629263277978091, 0.2018345897960902, -0.23787825678765334, -0.6869091654004473, 0.1216016588413746, 0.06006250537469367, 0.571346481234317, -0.41144485009477727, 0.7675968114983555, -0.2550642323891803, -0.28300976981959725, 0.3394320945135126, 0.3662863363565079, 0.11556695134467633, 0.12331990258002057, 0.8599409758091355, 0.46216790056427454, 0.15173678300376284, -0.09666392828343302, -0.18761190936944538], [-0.1335148422823241, -0.3804628652056999, 0.09844981179624036, 0.22176532923980652, 0.7189020006936334, 0.04164889659446908, 0.02127029753991804, -0.2449339235175429, 0.12171806926666562, 0.4224353582116574, -0.33623594204286494, -0.2583056918500283, 0.7316364960593229, 0.42952632701960003, -1.3621526959125516, 0.7692110643103672, -0.524951346304755, -0.5253435566921677, -0.6404525426582961, -0.014286526545517169, -0.2765306563502743, -0.2683122035030106, -0.10800487981383988, 0.20236204356305515], [0.04112394995654356, 0.4847474835581217, -0.9178531718359246, 0.347741018555925, -0.22293322582662448, 0.08192051156231951, 0.1261696579379956, 0.38639160101205766, -1.4496789333056046, 0.29140603141713567, -0.562111604028727, 0.005448869922096682, 0.7928295770798746, 1.0130599297305223, 0.0485474317320811, -2.1304000697633034, -0.24170345966645546, 0.01931097274721016, 0.742850875478617, -0.30982186666919403, -0.440564192226647, 0.0453872337903886, -0.4535392366142604, -0.0975518151454427], [0.15649933451045012, -0.123385670095743, 0.1683116287229603, 0.07162652725655963, -0.06906859316949997, 0.1429060457265451, 0.3824871015965046, 0.07147620274540141, 0.22695532722545086, 0.9653485093558661, -0.5762914963343275, -0.43077343152848796, 0.5973660710844477, -0.09446819976416657, 0.7201562744388608, -0.48609263104987405, 0.2218324050642452, 0.0645259757377216, -0.21509199060995396, 0.07525280834547757, -0.6989626135843678, -0.5370890292261622, -0.26599291856049173, 0.9974538888086234], [0.1199835337128482, -0.5008037060032665, -0.0446607582718856, -0.7260549476294623, 0.3611077714067586, -0.3888118034043124, 0.5795845413175277, 1.3338156154014258, 0.3145925897218954, -0.4736888774541778, 0.6094349282757121, -0.9962543955686464, -0.5242735150906005, 0.13595571105961837, -0.15888604909044052, 0.40525595255736363, 1.3876986151240691, 0.10547466168732185, 0.018651603389598523, -0.8237791324736201, -0.24508079660459905, 0.5630558889837247, 0.2655037266969241, -0.05296149616909789], [-0.12344423828585803, 0.6028340510887498, 0.21292730014883401, -0.17104511281268756, -0.3653780831758302, 0.30868157142714603, 0.6260505747967328, 0.1667001427687894, 0.5458330814835202, 0.5213471679936004, -0.563869081522792, 0.10071499666698862, 0.9123235634668392, -0.3348047796236789, 0.42715282691900675, -0.9979495730891054, -0.09100067890700438, -0.14178749691298503, -0.6717022806889916, 0.43829679045054076, -0.5625537536606493, -0.18755908312796374, -0.3888237773399193, 1.3069245079467076], [-0.614157632769445, -0.3973824010385688, -0.09367391275488283, 0.645518592242027, 0.1579591968400488, 0.1996434296623372, 0.5399231890126287, -0.08014375077584455, 0.9096475457535266, -0.33318844227955124, 1.4990976422300584, -0.3271487742285958, -0.8382071861377363, -0.058059526849622956, -0.3556206669808365, -0.4979849236028315, 0.2618827663149934, 0.443469850496763, 1.1829900980358516, 0.46573488180358186, 0.46273164309866227, 1.3635039586044517, 0.8787351064410526, 0.08738804442753971], [0.012292742072710146, -0.034557911280425964, -0.8461245158196634, 0.2656432549537445, 0.21724956370004897, 0.5008044706917877, -0.5812616140548187, -0.35040610055786636, -1.322543861617282, 0.7211771994785907, 0.12047461474038837, 0.5933799520019681, 0.9350654656636858, 1.9247288614008584, -0.45460228538973313, -1.2510718060974457, -0.051646222786543614, -0.38767208788577123, 0.4420822367932602, -0.3709518360438341, -0.2528893214518472, 1.441005821049913, 0.432349826004981, 0.41360332815588513], [0.4629770308259327, 0.17836810277308174, 0.6845125264695497, -0.3016016140752825, 0.11951954009595221, -0.26649626390265607, 0.1190243149533999, -0.2041399768239293, -0.1392451886575141, -0.920245609747074, 0.6026314787933941, 0.19348419420802146, -0.523581439113709, 0.004636131063590319, 0.3877871091994037, -0.33434588626619044, -0.4296576064572807, -0.008697037921427514, 0.6235952216696674, -0.5064008639749025, -0.7256108190369607, -0.18023635117253517, -0.4409013995897788, -0.5524514282641291], [0.2875165844690813, 0.49814109138267454, 0.3448119579048032, -0.7048343467919383, 0.463657020062575, 0.2555286551458123, -0.5130942521879042, -0.38131256407752384, -0.3600504381859082, 1.6486789475065076, 0.05629504619032248, -0.1162500115476105, 0.5022520651459279, 0.09891850682842913, -0.30311723275142993, 0.6050858322588333, 0.6788227542626911, 0.6189033880459673, -0.4609674299988535, 1.0222994433964092, 0.1733088128411549, 1.0146942846667841, -0.5888593868661297, -0.7556226202224315], [0.05518793125557145, 0.2839893612365816, -0.20179794729672054, -0.6255899024723715, 0.15710478897323982, 0.12648663145148342, 1.1149663818068762, -0.5594011952543431, 0.8723727369259155, 0.08987620467563708, -0.38891569710692064, -0.047704970067709296, 0.4240926530328803, 0.034530549945173836, -0.37115270991674726, 0.592545775139474, 0.4928062748340061, -0.1420153010079194, -0.1526277844533527, 0.07886150429551061, -0.512231063243804, -0.4156019874696255, 0.135864362227226, 1.3340479046016558], [1.1627368360223753, 0.7778683366958984, 0.16415052650062992, 0.7742718422037376, 0.07101526763518963, 0.5019171524166246, -0.3685869379910442, 0.04555206611463432, -0.5715101766127503, -0.5190209550234044, -0.42991392829853586, 0.47787728162280463, 1.2803782164650497, -0.08934427536490969, -0.255826002955659, 0.5175915234026938, -0.09366463327710242, -0.9008728735353397, 0.44432171665329373, 0.06156789070557714, -0.20391411485907734, 0.5041605572113529, -0.13343144700353343, 1.014313890624876], [-0.3951954190777976, -0.6222355262477676, -0.11488167832097902, -0.21451769250163785, 0.2926161228193536, 0.6380368975470628, -0.10475701595340403, 0.03637084100594554, 3.3039874504995828, -0.25321785944655545, 0.8118914655965046, -1.1896062808262209, 0.3485027473331256, 0.3814205316115023, 0.9590785142770899, 0.2159242362608293, -0.3662264452795242, -0.5807262923756857, 0.282109421535726, -0.531349835226231, -0.26109783169236683, -0.1923678458242174, -0.16561129149080667, -0.3749577452518127], [0.13427132514847484, -0.6654582076510004, 0.1476247425958658, 0.07140357736126239, 0.004531403834956281, -0.46367281717530473, -0.95180050744399, -0.10033375508560273, -0.17720894600200676, -0.30768256836057734, -0.7317667658992947, -1.4419336337277229, 0.17948724628910748, -0.12601265606021325, 0.8063994412298017, 0.7841684744721447, -0.3055128919439241, 0.9382216043822017, -0.3107503577980666, -0.6357781243093403, -0.41836683060321417, 0.1398971391848394, -0.44170415937506113, 0.04218447594127383], [0.1907341736030984, 0.6075919914335581, 0.566134152373887, 0.687389265410025, 0.1982244576298059, 0.5847739113883452, -0.1219798368254525, 0.28816673602748144, -0.18358260658374534, -0.726083034971755, 0.2825253194125379, -0.12834365953216878, -0.3319983117757582, -0.9408532150535002, 0.09058360535702133, 1.4481053255719891, -0.5645539386492068, -0.014174858244734993, -0.6512432464317693, 1.1239388267811818, 0.89953051594856, 0.043881445451449966, -0.5088785351408723, -0.11036844719957888], [0.46180805635666927, 1.176211870829366, 0.13478409462564003, -0.4763072338393541, 0.6671471272295388, -0.3200683142187519, -0.054068907235398464, -0.11976748720486158, -0.5098524318880031, 1.0241534429183492, 0.15658100238435485, -0.6046242204519386, 0.1640152967569599, 0.4003473449382779, -0.609056035913103, 0.42570010001402014, -0.27255969095978655, -0.44098688780121004, -0.5192499108767706, 0.02846903051186735, -0.2019852633156815, 0.7546180938939352, -0.10686235309290566, -0.053739095452097416], [-0.3481543708037107, 0.6050025778322696, 0.30635925507001344, -0.1945239741415869, 0.0583489677116097, -0.15370299294783715, 0.2617500991961637, -0.15705812804698205, -0.06623936259458026, -0.49711868927042707, 1.9690905563005805, 0.44348448807401913, -1.0423677069089563, -0.8790307707285249, 0.25608212628998894, 0.38229913485476347, 0.41667811990395676, -0.5558569348158313, -0.0791011135084424, -0.7239000701111119, -0.18579986044824373, -0.5716019830401831, -0.18932645522891267, -0.45596792479351567], [-0.2858109722037105, -0.2295676033736215, -0.19507571178322944, 0.19000343125470637, -0.4014686645728811, 0.0060658232751191485, 0.18155876250431685, 1.0437040168896576, 0.4713127832291026, 0.9373871003542024, 0.08434090255970084, -1.5704766726747073, 0.6501604970079313, -0.505280269623908, -0.534080703162298, -0.0807408953654915, -0.3234192508513978, 2.206663560814538, -0.39856476201664226, -0.19969968097310326, -0.11844778359474278, -0.019121796211803658, -0.6913964004977134, -0.2633718572957154], [0.42853502119219206, -1.2161075392513725, -0.23110741974871019, -0.10276382904563956, 0.1751614075174442, 0.7767656523250569, 0.32103791752800115, -1.0078802181037199, -0.18402754724102935, -0.011974104225383453, -1.0884118318998364, -0.181533847741459, -0.6808475082250697, -0.0057052950966988225, -0.15788853208514408, 0.45785762003715713, -0.2871564724223931, 0.60402914647779, -0.4733170453604064, -0.3787104231561495, -0.6901513923265933, -0.074725453528865, 0.8779190822266785, 0.2589056834464069], [0.18669252189017602, 0.08770411509710126, 0.2174822729655851, 0.6462449371413777, -0.48148958856201596, 0.5601035463877145, -0.7985264753204682, 0.03278521773754457, -0.41371764274894435, -0.9725886685287548, -0.5178502680195866, -0.8303887076092786, 1.6976310515820017, 0.12562716575093077, 0.04148747250076073, -0.5714836385469038, -0.514642186538719, -0.15795153602407316, 0.22176843827587103, 0.006379298045705154, -0.16621421449332544, -0.5383594761157146, 0.014010195304795074, 0.32838336860604694], [0.2191072972936561, 1.0055124497284014, -0.32395335942863485, -0.656058674755803, 0.34580622190062854, -0.2596353834588301, 0.7050219649894687, -0.3027411407568177, -0.7205793473974306, 1.0850536069591594, -0.3450368409196701, 1.3396682989632043, -0.3583431438446831, 0.677229863542125, 0.40799066465245454, -0.8666643481426204, -0.7229432159828666, -0.6467550642941606, -0.7475529760761178, -0.6299862808054169, -0.08950272068520368, -0.5020503999797086, 0.005831636482946577, -0.26978244479837055], [-0.33473132343378303, 0.5669342467587832, 0.05847060563223961, 0.4934885161580442, -0.639396042226399, 0.8147268725702745, -0.30089711738862174, 0.37261814787520203, -0.4243604800388999, 1.3055439895096859, 0.005816448687585566, -0.18420739822265697, 0.8451825428062653, 0.004912769795105793, 0.20731692881682692, 0.08014252566411026, 0.1205107882964218, 0.0840607379984122, -0.5643896112494099, 1.022201755164387, 0.11973870302989116, 0.9008279958952519, 0.042895419995427425, -0.6265791394350722], [-0.3909440189296494, -0.6117851165085995, -0.10767900694315188, 0.1409858341448384, 0.7597027023304319, 0.21023032475141398, 0.3086272611126814, 0.3016447622473586, -0.31588528133127003, 0.09900550745591988, 0.3112495420465535, -1.3890912455798705, 0.08542348655273978, -0.6442863633385487, -0.8445281268951182, -0.49893808764615505, -0.6054114735164697, -0.23150636682185832, 0.6863243151027619, -0.4638280480533427, -0.039635774929378136, 0.053535850132281355, -0.7008967912872172, 0.09061321476451842], [1.4209302874359144, -0.30287347675750587, 0.6263216013403414, 0.002890142532641826, 0.14742691996346463, -0.20644575950897204, 0.5174489911245691, -0.544502204383228, 1.1737408222667436, -0.6450579384627274, -0.47637086063055917, -1.4193951759843861, 0.8352539466561263, 1.2767318508461392, 0.03565791669736332, 0.9366860844143587, -0.45482253673304107, -0.6414704953866089, 0.6908505678959534, -0.40030343068294294, -0.006316086965141087, -0.07662913793231775, -0.3074294540819258, 0.24676917576978108], [-0.5306679922591301, -0.04550560863784445, -0.5451802413279422, 0.36657464541341667, 0.45504508760863976, -0.30227188577750436, 0.340551661397777, -0.2823975950092585, -1.1228379285537915, 0.3905665719567257, 0.2504851898908461, 0.12790046704887995, 0.5247854508050813, -0.05003939255691386, 0.9619133569515825, -0.5371671681111276, -0.6246138032005383, -0.8563337327179197, 0.03851261343515941, 0.9446363197162265, 0.36168756690247006, -0.19737480705486, 0.5357886506167778, -0.5706838592188397], [0.0320552675289353, 0.04498558349659152, 0.927933755886649, 0.06637909455477418, -0.3982518124463009, -0.37872635524274545, 0.535013612480223, -0.7276125838830729, -0.2797354587202226, 0.08306811119154761, 0.5364529792445164, -0.9827936014193528, -0.738990237138325, -0.8334964643905317, -0.28104664057647943, 0.991821263477287, 0.3530636129284647, 0.24116515234937233, -0.10488444563030448, -0.15287795287270975, 0.10199064161456488, -0.45128093496363003, 1.172124553648246, 0.0865205992698702], [-0.15551762348819215, -0.118200053653506, -1.172619380312774, -0.13362137452357997, 0.4923908737808869, 0.1546028465628694, -0.44662158033860383, 0.3155055240627548, 0.6051991927268228, 0.21613939763894063, 0.7635773559598465, 1.4220210419090262, 0.979824717967741, 0.07407477143415465, 0.1308148488211494, 0.8414105655347905, 0.4336537545719873, -0.27497556391485456, -0.7075787966805452, 0.3945606807871644, -0.5143872944078091, 0.06402127668709383, -0.05643845183430985, 0.8108797511613453], [0.2789647167853151, 0.8958577140945939, -0.34337486619890006, -0.0992636065187003, 0.04520050284578952, -0.01684835944263139, 0.014645747732548169, -0.037187387500918115, -0.36836375331458493, -1.1448846773700043, 0.031220377208973398, -0.18955306051806303, -0.2912704515456547, 0.4531711266542357, -0.26380930296052024, -0.5956994934626156, -0.43557969129622304, 0.6767064018095759, 0.7256587908734424, -0.6551673895670133, -0.8188682811916224, -0.30850172250795493, 0.3934046508588947, -0.30841624187751443], [-0.254427134477315, -0.634439500480361, -0.2553205454630524, -0.5274978384816207, -0.4634192296997391, -0.20711674402634672, 0.2092185607900779, 0.38513463548988996, 0.10572120617450953, -0.37783836670959836, -0.6567344788965308, 0.9367341259348145, 0.4792603268643316, -0.29092786984967317, 0.7204926183392667, -0.7286165843641883, 0.4668287086133746, 0.13220314780260425, -0.4561879536208948, -0.08412730669477331, -0.3837392698646472, 0.1915651661065164, -0.23499731473381635, -0.08426824418388189], [-0.4083346694663197, 0.1675438322994104, 0.4014547439220253, 0.04195389550870232, -0.7440922851023584, -0.9613649970517791, 0.3372718841066369, 0.4071278764346239, -0.6211180701816978, -0.961048787576325, 0.24810543725017303, -0.9772875241297688, -0.6036847212245438, -0.25951005022730506, 0.6961954953489632, 0.2412940539637466, -0.36534391103032526, 0.028719154447357512, -0.7714333683846599, -0.10552312482703692, 0.27169294337112765, 0.3363794880291673, 0.15086023632978843, 0.4036060763931862], [0.1648325441688487, -0.4108984504071516, 0.7118768964135127, 0.5749195299532393, -0.005961212680413066, -0.06703178454251021, -0.9518406367865201, 0.33159492909843047, 0.6518073012912438, -0.2540850278775441, 0.4603687811227358, -0.8960586127890827, -0.08261556316920933, -1.3268066051004448, 0.1479707532689686, 0.29602285351388363, -0.11759375281523658, 0.7409892696065152, 0.019356815559472253, 0.2967284301964205, 0.3834130834903517, -0.5450977750462876, 0.1558770593373313, -0.08396944859720155], [-0.6701332806298074, 0.3184027717627691, 0.35856142817830655, 0.09553373410817893, 0.7490225446156858, -0.11422689578149013, 0.23782347814603275, 0.3513439088678029, 0.3766365763556446, -0.5729614250568712, 1.5245158455060253, 0.08303923947866113, -0.30995653496048625, -0.08954151196280494, -0.4106201760893801, 1.00496787646728, -0.15790210620223896, -0.4055564736662434, -0.2174410480811461, 0.41087907926860656, -0.5884416630987307, 0.8392683636881801, -0.2892706787789975, 0.5631516205611647], [0.14982325455963832, -0.1451136194344531, 0.6019986173207387, 0.23615419543902827, -0.0752504370905764, -0.041169058400579064, 0.02344438678362063, 1.0077522034178699, 1.1895043967351935, -0.8302459288611493, -0.6617751678344872, -0.08674737898992493, -0.7577689002038442, 0.17192518391182873, 0.029369423690756357, 0.6084634673930684, 0.00028040220117001306, -0.4805590712433454, 0.6161400495586605, -0.45684318005111046, -0.7646840125823514, -0.4624966002622235, -0.5478837375740669, -0.6544248380439776], [0.08732149484802107, -0.06923866543485196, -0.5120113762733639, -0.46440662820041395, -0.8685346024128268, 0.1448436637762175, -0.02429075658161788, -0.4557917329041031, -1.4785296538190786, -0.28436701574872336, 0.4040986880053601, 0.5246970617954849, -0.7839384133512883, -1.6015046590390514, 1.308723763958197, -0.18141509316806437, 0.17644392145273843, 0.7914516060881944, -0.10539716510607458, 0.3302295072499782, 0.35087897115725053, 0.07961623535136014, -0.12389543184360713, -0.46377106365455656], [-0.6146203875226216, -0.10667716824573215, -0.2505980548352886, -0.5150846572814505, 0.15359461077040612, 0.1008590496934376, -0.06262912267709302, 0.33883935316793723, 0.47091633446179987, 0.6118635780487756, 0.9929933792236083, -0.17554636735575072, -1.7281089187454703, -1.1348271138393409, 0.1221095855164219, 0.36686442709558, -0.7063792946781153, 0.17976335462521037, 0.9404514026632936, -0.6294212467729664, 0.2553673106218388, -0.5854343588745776, 1.02503033908417, -0.21954946217720353], [-0.24858415210313461, 0.6033122548831944, -0.4898743163032936, 0.27337674908267956, 0.30781035369223253, -0.08739515780926893, 0.12428448934640099, -0.5710231532819966, 0.012160699275195154, -0.4952458408046891, 1.6160812511005898, -0.4515190779184954, -0.4204930104302109, 0.4934069583582476, 0.5617830067792768, -0.6424674504421167, -0.5294493407830445, 0.1647206070991871, 0.17908935070455184, 1.9274523581389644, -0.1178145851366241, 0.8529197518020295, -0.5622304743487863, 1.0436136169720394], [-0.6240041116761847, -0.05589420169673289, -0.3526219767383515, 0.3055864581608773, 0.025486100051908666, 0.31962873897435706, 0.10859448117965677, 0.08650338865270378, -1.242257434405487, 0.1549152298830528, -0.19536031760969327, 0.5327052978642121, 1.2729659375946047, -0.8872960728267916, -0.007132461255887031, -0.016134276073651078, -0.37439739701628333, -0.6643275279191122, -0.2644600077190052, -0.4279586873997483, -0.602195962207913, -0.490981009707546, 1.1492635324719374, -0.026049015572387268], [0.07860669643772307, -0.12846427725372295, -0.22405744181576542, 0.9211400552979089, -0.8082988359569959, -0.054167221584997954, 0.4282171073425815, 0.18130921493888544, -0.12515360125619537, -0.044291416472889956, 1.3199166584924535, -0.5336440044202596, -0.43113891951569966, -1.1133720196767147, 0.46185629938359857, 0.4428770009071917, 0.12112497315361662, 0.18401319302459027, -0.22871478468250983, -0.637220595966084, -0.2503217564956065, -0.6496564965668661, -0.47213449971200894, -0.43223031855919564], [0.65746133947021, 0.25987205791809825, -0.6123840089454916, -0.08840599011974241, -0.6433629090982098, 0.4893475735180795, 0.6324390554343844, -0.20058735876281855, -0.19470233741629547, -0.20769308386097424, 0.7759155396768767, 0.1570557255924316, -0.1370253719088846, 0.4190188727117498, 0.5030642218068185, -0.334701062578103, 0.36447809490690924, -0.5901614539673943, 0.07007522839084468, 0.7083872219887115, -0.41979417114844364, 0.12866110426798055, -0.4551726055072861, 0.6618351184540002], [0.2746144474048743, -0.14685141594931875, -0.6999751557331851, -0.1407099299595002, -0.7289073942273463, -0.23548014711149015, 0.053844828504669595, 0.3130108577039539, 1.5332211768956447, -0.6018057968265109, -0.09924514436194824, -0.20947321058883586, 0.40961779783149177, 0.7954250654524831, 0.03979046743027555, 0.5553228519501766, -0.02915600246624164, 0.10339443011044791, 0.31370081707207925, -0.03681947721011688, 0.4179833101480498, -0.2559281108247526, -0.12760009605469394, 0.25838709200484294], [0.6033736553637404, -0.11644876027549439, 0.11034116431334172, 0.22750440813650466, 0.26397311991886363, -1.2980926510671242, -0.4107742655044765, 0.34178571556167653, -0.17022180979684443, 0.09622042964694473, -0.033612084924858884, 0.07746905753406301, -0.22128828334527167, 0.13039027331015032, 0.7031530639428332, -1.210241684719734, -0.5440401545895603, 1.034668329226803, 0.2191310994316759, -0.632416680662438, 0.32043042751646417, 1.0917213738776974, -0.058775323116326016, 1.4847000056849233], [-0.46227898166234, 0.126251031497079, 0.39813999401071537, -0.7636542398292732, -0.08601273706171579, 0.13411585692742012, -0.04478761826886781, -0.6894281717243912, 0.6241643080406233, 0.534658751423488, -0.9732393503905774, 0.07452799647484787, 0.6777634489043054, -0.5897542207307309, 1.0342656195485567, -0.8643438346675344, -0.5846975375442885, 0.6694179134383803, -0.4646502934473313, 0.5271217345299912, -0.40362811313563246, -0.5272087125478657, 0.236244522442875, 0.19672993761824595], [0.18075756915587954, -0.2173038079351435, 0.3896335330954233, 0.22622583749202832, -0.2564388818473056, 0.10213823352395411, -0.3763471241871154, -0.32637395812724124, -0.6738798904742951, 0.4577170067173018, 0.06669034752591099, -1.1538234140913828, -0.6233889784738224, -0.16476237016330972, -0.9929481298936558, 0.04197546115999881, 1.5972842453849578, 0.029120044906152203, -0.7359892297654348, -0.09024692306574887, 1.1510004824657105, -0.2797595213778254, 1.631848692613635, -0.2520170436883361], [-0.6717315505442064, -0.08560520146593775, 0.3754945289025301, 0.08584503437807589, -0.0177088082171881, -0.28028672918275177, -0.307821587555588, 0.30328154000105756, 0.3051840974990231, 0.2074531357105055, 1.9888398046705347, 0.09497811602245763, -0.8910629360590478, -0.7592299098622226, 0.8150650444591595, -0.05475564267834138, -0.41007228562708664, -0.1481110749422625, -0.5972965951694912, -0.7809548289560432, -0.5021339966273173, -0.5147153116705835, -0.6606775922749674, -0.560163102886769], [-0.6430570516457303, 0.8762356054112385, -0.05608790725432164, 0.9557346422340911, 0.5308649595678664, -0.18930242169061373, 0.2736942873502816, 0.08145403179192129, -0.5572300766166032, -0.3951718429622221, -0.1832587405996558, 0.197099061878195, -1.0193332276942395, 0.19593653448825163, 1.3499458587856565, -0.46544050042677754, 0.2019442416566854, 0.5609290870331002, -0.6863026573146984, 0.18648203235529626, 0.5726037235219935, 0.8515536717389769, -0.37421874326396004, -0.05515409666578047], [0.2120495400300757, 0.3348997245706079, -0.2981154404604841, -0.2414737569250603, -0.21770418482487774, -0.6373536161863541, -0.19915647966011185, 0.06305095421132668, 0.39442924369692156, -0.5483692218333539, 1.4729524663877214, -0.3539179293436991, -0.3998461542503436, -0.7325409746674475, -0.6648170908942578, 0.4153665071644562, 0.09491879952170741, 0.4207569560988135, 0.3891470874077961, -0.27473434142328945, 0.48257580195181177, -0.6198329325269406, -0.16424110786819424, 0.14729086327777094], [0.1125361434738611, 0.07581358927089156, -0.23074820596980697, 0.35290130935193725, -0.9836793348553347, -0.19303478009658712, -0.23681476320032277, 0.3513064326978783, -0.21968420269252747, -1.2425155487652435, -0.4254874744929486, -0.2523603474454757, 0.8657658431730176, 0.66317922306977, 0.5230696722696575, 0.05637926027445164, -0.642149455780685, 0.9167496481649917, -0.3122375316337686, 0.14807232874868378, -0.4943881063006456, -0.33597473378968856, 0.6239949585114696, 0.8325157786066195], [0.28803748403143065, 0.32518016458372145, -0.040034351851400904, 0.4142031244455182, -0.5044657204542027, 0.015955009025573334, -1.0791604809817161, 0.7041930275019765, 1.2509962960742917, 0.230617081354592, 0.3871196479664082, -1.6494539134295796, -1.9733599121247805, -0.527375883744787, -0.19980214205181188, -0.7854112190909226, 1.1512174216651454, -0.4676455021075243, -0.5603776815561814, 0.3130627562611457, 0.8768446499014427, -0.44153175400041367, 0.9483414371224324, -0.4642573624559351], [0.6882977679493646, -0.2722490005964055, -0.46687790771861865, -0.8921814086072984, -0.756513942190936, 0.034252744625961555, -0.16967569392903756, -0.7087550734868079, 0.9390266054144822, 0.9917998579687001, 0.7504142847335649, -0.5845401342829182, -1.5367743019469442, -0.4763441507302524, -0.912623396455933, 0.2169725313784449, -0.17126391375543987, -0.6558690601844371, -0.5829274923814167, -0.5782917449692438, -0.1685886666966133, -0.4607762779549058, 0.7675260924994618, -0.8919014084235767], [-0.23488195073632098, -0.3017555376295696, 0.17200757476135511, 0.3055926379244422, -0.14533553015108877, 0.032170015867835904, -0.09727291622851815, -0.9786136753917068, -0.43282253170417717, 0.677264220423408, 0.40696165420819735, -0.14767350501540288, 0.21902622347152775, 1.2108657665250133, 1.0054053171584936, -0.7695569843142497, 0.2895994143356968, 0.6574296504798055, 0.41998910290229513, 0.7738092623068092, -0.328558476817173, -0.5782238188562062, -0.545173935856278, -0.23936176603903803], [0.06577863751355881, -0.04696616711331263, 0.31025155660754306, -0.7789688337767219, 0.31417035464636034, -0.3165615653689811, 0.03151467385217239, 0.482212742496951, 0.7523016287478377, -0.6100133801480979, 0.8896453675368906, 0.43369225632021763, -0.41210663428415023, -1.0891738101680521, -0.9863914162510823, 0.1646515155123935, -0.07243655482363744, 1.0599246477001527, 0.4173796809509006, 0.4488989329291775, 0.4078365488498437, -0.5010677386118118, -0.40501971848170376, -0.36612758915933913], [-0.661563856791333, -0.5714316727630968, 0.4305331398448175, -0.4809025004827383, -0.48647106575452653, 0.26158809856009757, -0.18685585816292502, 0.2920597746914346, 0.44539059012850957, -0.0012862508050684967, -0.30783760670855015, -0.43283977939781443, 0.6754820531899662, 0.3442855053483439, -0.4661768370821156, -0.8064937013850421, 0.15915808935191383, 0.6954070957624945, -0.06989199704634519, -0.30634300534767617, 0.16340037649779934, 0.09201391017833208, -0.5234078636941291, -0.19163740810396082], [0.12168709541517668, -0.027877592162910584, 0.4272990055207649, 0.9408321010502101, -0.08489007237081715, 0.6708818653442971, 0.4394840589004546, -0.0019486731898033637, -0.7041614325117682, -0.9147818616457195, 0.6618412053773425, 0.2571746294418498, 0.37948664302591223, 0.33797077632135136, -0.1467968505876347, -0.1454277067458367, -0.6451881466161579, -0.38032158431416474, 0.03590941255668583, -0.7859994409030251, -0.4975833276344879, -0.17676836773143917, -0.20253418607232612, 1.646402277693526], [0.19222611338402507, -0.4112561040944083, -0.3489951813521972, 0.1264623656501476, -0.05956427190985413, 0.5887249867172721, -0.6969449748334207, -0.17966972040591897, 0.14886984934695074, 0.21642786398711822, 0.8619077180716977, 0.0004782752222153926, -0.36173572832704876, -0.7677210829704222, 0.8906493523702071, -0.2585522269071593, 0.9384607470073306, -0.5809211057644901, -0.2041926862974024, 0.2623316480689332, 0.9416433917151082, -0.4605294118216849, 0.34638135859602953, -0.673387205445874], [-0.28927489901302617, -0.07932207987746968, 0.5163754205927882, -0.5060065835179943, 0.3589396264451685, -0.2891686732638205, -0.23996276458509483, 0.39278612469918417, 0.30555863431869534, 0.08692948631950737, -0.8556806403213125, 0.547429593286194, 1.1201848346189582, 0.7507988496619233, -1.0514217115340376, 0.1517412831861342, -0.583418688131466, -0.5447940313207194, -0.2592359121650736, -0.18094640706327456, 0.7606025997132569, -0.5122915526702787, -0.08698552023475148, 0.1025056654228787], [-0.13195088367583746, 0.26762745862765647, 0.008190569152955482, -0.06351433262554046, -0.2027677817379006, -0.8178765163176763, -0.43549279939138374, 0.02687276648481138, -0.05375462877525319, 0.7579823700458626, -0.11384718084462744, -0.7253803169562273, -0.8230174594844138, -0.6016767024153181, -0.3038515695152377, 0.9811408960646724, -0.6601281141341532, 0.19324817438320532, -0.38030154243279707, -0.055002316912121096, 0.5820961547208935, -0.5267379290742298, -0.3994272457298733, -0.610395844256515], [0.08404958754915993, -0.6408080672923192, 0.442335495997637, 0.25755378503572424, -0.6380908255595384, -0.4949849706377824, 0.15373518333496208, -0.8222492134587411, -1.0653911644175913, -0.4225760052377484, -0.3064748875665129, -0.8473829473665858, -0.8025420678851776, -1.0198135902801069, 0.7040483000081895, 0.8759744890957452, 0.04111188867656534, -0.4033642453921469, 0.23931100441733014, 0.029775572502047994, -0.37388591389369424, -0.418694935652653, -0.025025801322433747, 0.8937073327664865], [-0.32935303069382127, -0.031465636971499816, -0.10293264959410403, -0.008556679823659492, 0.15316971803982055, -0.3779158736730524, -0.3076887874009208, 0.8677097415714434, 0.07746009174303112, 1.0741306705618576, 0.060724948390702166, 0.979217305725997, -1.2940760993935927, 0.31502284608693754, -0.5170581476803526, -0.3935204930485634, -0.1839627517183619, -0.5525197409873636, 0.6267819047115383, -0.6443793847438885, -0.5396363761568489, 0.19067505330174817, 0.5718354273757872, 0.43445667369393937], [-0.616666916896033, -0.19536739459647115, 0.016173610178699685, -0.25721886284622647, 0.54336341868996, 0.03029697562380983, 0.2776946797990369, -1.1946142647782785, -0.5401058616865312, 0.9911349255522212, -1.4463096987298552, 0.7382285577056552, -0.11850430990571899, 0.9757623056570299, -0.2490379656390641, -0.6064702686849186, 0.0752296076981085, 0.31551890009440825, 1.7473493465120578, -0.5314825377314998, -0.01074060099116808, -0.3529738460714967, -0.04739475399597675, 0.23441517788760163], [0.5275744287254839, 0.4819075495569218, -0.4018184443337169, 0.5793995059983641, 0.10132709699211785, 0.43118970185000466, 0.7742641319357966, 0.010425224930816353, -0.12981045364618252, 0.32394678523760045, -0.25842903146712315, -0.6060199996067648, 0.08745854259010723, -0.10922789970791205, -0.9311669500275653, -1.1685483952371325, 0.39593498886163964, 0.4639268233300793, -0.3458036298701786, 0.5098878298659987, 0.4209873605511285, 0.660490376743477, -0.3468697836218955, -0.3553239938130779], [-0.43856380616343893, -0.004021499406253994, -0.6501124203218916, -0.3169088021114782, -0.3740133996469904, -0.32693225224340045, 0.4761424682872303, 0.3397097258778888, 0.010088494864080687, -1.2234556388318696, -0.07091558973477623, 0.538343744068454, 0.4674323247297379, -0.7325234876764983, -0.10030053972336603, -0.4596164674774881, 0.05925664170501273, 0.12431295113493782, -0.07298997647657839, -0.6252266738681599, -0.016766945203175215, 0.0490196513788461, 0.43354301159481545, -0.45355896063627005], [-0.38358366505167235, 0.4819415012038291, -0.8417180822137464, -0.2507632165735133, -0.07838599947777877, 0.561513079802156, 0.27609200884708057, 0.17608316502028856, -0.9189184643498615, 0.5171775168485234, -0.7682586283006545, 0.6357293329902058, 0.7646683196620536, 1.3221032753239643, -0.33061324342632453, -1.4705957093574482, -0.6766534653662237, -0.5217512479381013, -0.6695418709272766, -0.7238885115921636, -0.49402934407780674, -0.15218183481652142, -0.3067056683409701, -0.5685582213673352], [0.5910502693999862, 0.3120441745528451, 0.644123360660523, -0.3008599346060807, -0.7949344234247517, -0.1799048942842641, 0.3296170275929857, 0.09458985777111495, -0.7033375856478161, 0.04523213344876934, 0.11806617088772298, -0.17484256816625948, -0.8039280275311599, -0.9219108483182803, -0.05771254896863612, 0.6446488949053655, -0.6463397054157006, -0.11144005643680283, 0.6039070543481155, -0.06579133440822513, -0.4601935554984064, -0.5834224453824033, 0.7456653266206741, -0.4890540938228613], [0.4130970152770076, 0.3132791599440171, 0.23484376430018308, 0.38746406966712005, -0.33818580741347726, 0.5252212776061986, -0.5269010598901864, -0.06921290768844136, 0.7579797468658593, -0.3347845572576277, -0.17297617217391328, 0.8333544651477841, 1.723687199618708, -0.12344672833195967, 0.02638059687578613, 0.1900253285876209, -0.08458826292692075, -0.3345440496251961, -0.20111789786372705, -0.11041658020340898, -0.5469885725748674, 0.2223470359041375, -0.4986577397678521, 0.7195365600884899], [-0.600806730165589, 0.2281198792956584, -0.7686491819350589, 0.6391594335602007, -0.6302059907855568, 0.13817701410115074, -0.12124323491931309, -0.40626426461395293, 0.09682442737272672, 0.6658119642239084, 0.34822365360125024, 0.8782126451699664, -0.922051266711153, 0.3216107620695808, -0.8668436339933581, 0.35207348665692006, -0.6475802134644892, -0.474222142204789, 0.09494232163110472, -0.24247542130897617, -0.5200210606668573, 0.5500046328551645, 0.7368219895437115, 1.3079275603070895], [0.5739185863591542, -0.16579780772097777, 0.6984723334802284, -0.3988254939734608, -0.37730258896515795, -0.9121589293318809, 0.2032721158051685, 0.38811602387348854, -0.9771153633739617, -0.14896369049846855, 1.1994256025024586, 0.27426297414565276, 0.8567938032929586, 0.27984926231637125, -0.3995546362818881, 0.738647859867675, -0.3492605838510501, -0.9426147935554867, -0.2947806191111586, 0.44755213763992685, -0.5215658251443454, -0.16448622986662828, -0.28085710689208226, 0.4532369409182782], [0.12276488137522917, -0.05269727854929829, -0.46109694572045307, 1.0436551556772, 0.34317663262377823, -0.8391277243638675, -0.19975427463992662, -1.1719059481543193, -0.06420329247002979, 1.4459579661673456, 0.2324019588898087, -0.5382159079538354, 0.2646772447151134, 0.5828543310141407, 1.1546227999802536, -0.4646033590369877, -0.5850891438747251, 0.14385940781965514, -0.5282116935962955, 0.34049469084859446, -0.8262423864601735, -0.49499593879456477, -0.19207620209366122, 0.058992925867484204], [0.7206083837646045, 0.8513321908187919, 0.6983090860527927, 0.017898889642202324, -0.2777596400625009, -0.6332587967954337, 0.19563531626717062, -0.3460200958969038, 0.582076058731205, -0.4811286824283882, -0.43013218670690295, -1.2524711348760083, -1.3289864845543824, 0.7112213185073648, -0.27463288878735714, 0.29367309513373174, 0.7028741959915229, 0.25639451343989506, -0.6453243744458868, 0.158231963753901, 1.2697343645685961, 0.5832873746556422, 0.6497213027086943, 0.14573155257764947], [-0.14023149939081694, -0.25276836062331265, -0.1614785694697377, 0.4255429769854681, 0.7868655893027218, 0.09144290863734095, -0.04292106659595157, -0.5077592096517259, 0.9946978431627783, -0.24076202665123916, -0.7962515174264719, 0.8215539027497466, -0.21766860531717563, 0.07246378309366876, -0.8875692448512108, 0.18225293678736113, 0.6470714355481665, -0.2514440962155442, 0.32892368145541695, 0.2643285785857673, -0.17351306347894443, 0.34811905088616185, -0.17377715267495183, -0.01121961493576198], [-0.515488878687581, -0.4307147487103303, 0.421073061045654, 0.14934073792560962, 0.45300313102489703, 0.22053289476285381, -0.2386222844599363, -0.5639748758277625, 0.9597846021131978, 0.1894771689994592, 0.054317449639502725, 0.18351018657682774, 0.1723559954256978, 0.9717286571470874, -0.621389647432808, -0.12451460742053377, 0.7744729849450002, -0.36467937025726105, -0.6882758883431146, 0.7757016989702683, -0.20713912239728405, -0.6077439961076271, -0.5722862059069401, -0.32981207654717076], [-0.13387629046042973, -0.5839818589016893, 0.9676436356943824, 0.16057957014637442, -0.16864277528470678, 0.9550461957880699, -0.2288084609671509, 0.2361108497688211, 0.8073775614850476, -0.21261173603751732, -0.41796782498251284, 0.19636742702622942, -0.5672507875762557, -1.0885503605139775, 0.15427288860632432, 0.4332470064609272, -0.12003497051990164, -0.1605786592402771, -0.05210709241193446, -0.5657521655671859, -0.12510187057219638, 0.7390737849923301, -0.5936960591277822, 1.0142230758574542], [-0.042207695323462975, 0.1733966442914254, -0.18590380050515498, 0.2578637779985529, 0.6715458143438366, -0.5642830047375931, -1.092424265369714, 0.5911972736905358, -1.3528509445277443, -0.4527678893925807, -0.0006506693686881804, 0.29294818435339887, 0.31217834454011945, -0.586782337347984, 0.6692187678656004, -0.04488624186006692, 0.9370896862665776, -0.25380034554624936, 0.40961977524116444, -0.3491566537161308, -0.35915474952583215, -0.2560580692684638, 0.2810152954019842, -0.7191593086126147], [0.10555447480703223, 0.39377846511283965, -0.14681817252765683, 0.7109705279710722, 0.8593800704315742, -0.5216194452492905, 0.2695729155200449, -0.28242474121280586, -1.3970008624942085, -0.19359536439545666, -0.8699063180207169, 1.0219895593732626, 0.5571918859387764, -0.20683797350452474, 1.9144542236880888, -0.01823434639643234, -0.12235477129870435, 0.09709482195935035, 0.7508615621692006, 0.009780480893922623, 0.47984647852613826, -0.3433948609580126, -0.07037942495290565, -0.24122765404828297], [-0.6851327102917533, -0.10717279657288711, 0.27065032654963794, -0.5454338671486312, -0.6031805286068058, 0.599741135194625, -0.03802218888582089, 0.16307696427337404, 1.1354700794047718, 0.3156147227923243, -1.296531996119661, 0.49567890412638577, -0.4733064857522966, 0.7256001578184349, -1.6012954423824695, -1.1711264002659472, -0.1797133505820138, -0.5286603666824808, -0.21186508277264088, -0.12255697909412516, 0.11929675258232679, -0.2607185394230475, -0.6143886816927873, 0.5518160241420957], [-0.48425274948945424, -0.2639250898432187, 0.043578808829054363, 0.11717247996361167, 0.06001984977243246, 0.7586144062980424, 0.01516868660427397, -0.7108662059569253, 0.057926385522952734, 0.15935545886448296, -0.2435043149394746, -0.3659412559647202, -0.6795732540392149, 0.16046039214786, 0.21943126980156336, -0.2189388089967179, -0.34753783402987876, 0.2631245524885049, 0.5216016929680499, 0.4834223322054874, 0.11120629009876909, -0.021238058189046866, -0.17825215079278203, -0.06913993438875235], [-0.37574567215280796, -0.020582329276830867, 0.5982587116133659, -0.2707714528113633, -0.2041473559007772, -0.01244989772241454, -0.4087387526197104, -0.40582022813892066, 0.14177295263731943, -0.10432825316998867, 0.48806204517288637, -1.0349784773154644, 1.25264219111232, -1.022228713402676, 0.0351016901910385, 0.9791272431235083, -0.17060431085165967, -0.468548230387746, 0.6545672749343725, -0.5791077595333701, -0.17904624527947727, -0.13174314207664364, -0.38006737899599957, 0.029528982604851768], [-0.10223210389504342, 0.41766347778434915, 0.19795617176334293, -0.10769850744067301, 0.15976591764850248, -0.6113158553367919, 0.3884519778645368, 0.28664462033455784, -0.11928627354986561, -0.4072580672598532, 0.2136463744705519, -0.6788808443114956, 0.18725005550752827, -0.5207437133096868, -0.4526937570065578, 1.080356274983631, -0.6831143088801535, -0.023023557888203462, 0.1886505535156603, 0.996565664436649, -0.2816102421814481, -0.2881407661895132, -0.5181553490945949, -0.20643447905462828], [0.12961374801970346, -0.7058402768173159, 0.9539175402642771, -1.248569529138526, -0.5024222169202822, -0.443399616931821, 0.2433026336442203, -0.71579873795148, -0.29441657398999294, 0.9862457994682978, 0.017318858716863998, 0.7219589214552506, 0.3800697348960813, 0.9662533407779342, 0.4388760961850999, -0.5041925448731224, -0.3371218288919984, 0.6346419123191726, -0.06435599107075876, 1.2856217214285757, -0.44705311635157147, 0.4871345089291118, -0.7589427848616963, 0.659288819304066], [0.10026378913505397, -0.0767162467640746, -0.18780397969256343, 0.3812113241565446, 0.6368789253545211, 0.1752142712512643, -0.21467213712523525, -1.06439450511381, -0.4832845325955109, -0.15253886186213866, -0.1814242532466868, 0.030163814939312, 0.1690603175238006, -0.4673371525881498, 0.43580598250058017, 0.5976355075908854, 0.46674439006127144, -0.7826647637979689, -0.4042438928303207, -0.6814208134950821, 0.32021812230940006, -0.35620322357194495, -0.18618849923250072, -0.06220124049199758], [0.6509683903602794, -0.13891690026863185, -0.9530345902853565, 0.08249264369337463, 0.6505552493210789, -0.0757077681228222, -0.6350324772712692, 0.9657668542307348, 0.6176615212666692, 0.501388639444103, 0.1855007198991039, -0.22356460443207815, -0.36144398388452526, 0.06705175452568043, 0.8937668207801903, -0.0643114001337247, -0.1896244545415343, -0.26333789044910433, 0.42361671038472454, 0.4736795227700012, 0.10811164548708849, -0.6526676021353048, 0.5297415962922273, 0.6354860754440678], [0.2727137055758272, 0.14005686487054492, 0.46025618130361917, -0.9186143571049153, -0.05919735847704602, -0.08167636337289434, 0.9946429725075113, -0.2900799881534345, -0.34457955953054714, -0.09048303603050381, 0.8372908503626042, 0.5223383422588835, -0.7975308402530681, -0.2895256460269176, -0.9630471818514731, 0.41312377696648234, 0.3441730734860607, -0.03671315906707253, 0.23914186747263652, -0.012086182895847395, -0.45958223191977926, 0.3506548920315443, -0.07674029374031437, 0.14136983104763476], [-0.24207031833733453, -0.5962969408504264, -0.43820680224828595, -0.06675902634636288, 0.10165187198424576, -0.09348985951021324, 0.8754653951778987, 0.1859946062150256, 0.2940334981043352, -1.0061596826530141, -0.46890959499755414, -0.1500402913804242, -0.5649495504556972, 0.7406707438109588, -0.4427073257314741, -0.6448822317624185, -0.16566920068079044, -0.3869609200097414, 0.491568855877482, -0.5324939919933491, -0.7699405687034432, 0.23575677889361377, -0.6204441652674907, 0.09518315467410363], [0.29196303971988324, 0.5842532588717799, 0.280319628764474, -0.2011821243007118, -0.7483525597273066, 0.17073968015528843, -0.4643233171758072, 0.5575305495176108, -0.43853206861208716, 0.49664796160837416, 0.09157347181836938, 1.1084193133853666, -0.647371838100032, -0.5042766887441278, -0.9340761491713102, 0.0668817583925418, 0.006630683840302242, -0.4452733615550118, 0.9979567969413166, -0.17730863186201837, -0.18737702152208963, 0.858838123076054, 0.37906182300062957, 0.4656578163841291], [-0.3337298298870048, -0.9508834897052483, -0.009529368232169698, 0.4891662054621911, -0.11660323180496636, 0.0886679376472953, 0.0022643849913751503, 0.7398534129232536, 0.43413668649862736, 0.5573985643811272, 0.35761538866479625, 1.2366671066250012, -0.022228066538627335, -0.3291266698628923, -0.1907209742799774, 1.42007423301714, -0.5875370553010016, -0.5426183248225394, 0.17483140581726153, -0.07445692926437132, 1.0078375196044762, -0.423284809966947, -0.6680616387627797, -0.5611450680948027], [0.14347653187341514, -0.016497845799338846, -0.3338292780586073, -0.6859897280337934, 0.6449243841810304, 0.5431762069568127, -0.5241667220334729, 0.2395671387144092, 0.3999202483807096, -0.25639831974031474, -0.5812889754028171, 0.17971636515934628, -0.7695605817474417, 0.23532091422678802, -0.5279841065959193, -0.43604853624144413, -0.16573230484612753, 0.1664339686184354, -0.29404698878148117, -0.39555494080782194, 0.0971593237800368, 0.1486128416897507, 0.2565833954724734, 0.09064665210656797], [0.1535946278533705, -0.16310443623149232, -0.18603736808193236, 0.35001572108996487, -0.5902313874350422, -0.24512090095608688, -0.10968988487192931, -0.03778507998301071, 0.8723838388891962, 0.4297485837380789, -0.4292752216445687, 0.0884155925318491, 0.5739243158015308, 0.09289440364440174, 0.0783484797090692, 1.1463067575169, -0.1327289685229331, -0.2369840671293494, 0.5440377863905086, -0.6825126277417045, -0.6574916045766778, -0.45708518545628046, -0.6661922685350439, 0.20546954570104461], [-0.08724772559023738, 0.09265079845185847, 0.22936738071527826, -0.36373662934833845, 0.019021578041740393, -0.24847735863773093, 0.6422063752533579, -0.665614012923999, 0.34398328971348274, 0.5086595548186938, -0.6576054645577406, 0.9508127629930528, 0.3647106524865712, -0.2427585523842558, -0.37995403989512705, -0.4640946864867458, 0.027231502707737137, -0.0035699608574783844, -0.33015181900854196, -0.09313821065104207, 0.07652876507053125, 1.624809174581482, 0.3209913781453485, -0.20026136226408392], [-0.09796905529374901, 0.298821378684882, -0.17223784124418573, -0.12039186505157104, -0.2746106962967641, 0.14943051706331592, -0.6233834159225119, -0.06902927396591889, 0.9299769496024826, -1.4144509406935755, -0.8787403116866304, 0.740319371323458, 1.4472722312152508, -0.4478458983048361, 1.6955936920825891, -0.15062992004644843, 1.5454818385021687, -0.31138170289284733, 0.9403250242958381, 0.9109813583190353, -0.8022814149029768, 0.26992329858264497, 0.39749945047001967, -0.5879194694086352], [-0.0359161747733835, -0.6240778014738195, 0.10667283813245453, -0.17397884832044136, 0.1302924306309045, 0.4124847313441798, 0.09698603126655471, -0.5567744139660814, 0.1355703086135273, 0.22181905361566, 0.5103836676487935, -0.46068671890697227, -0.16015865532066173, 0.5461295429236881, 0.5605155930347173, 1.2613274132821024, 0.07340290719786585, -0.05528767310876458, -0.11978307225318421, 0.08015829132076233, 0.6923716928170073, -0.49078421128534305, -0.042054184396854606, 0.4761155479520251], [0.15892499384101552, -0.6762663476475682, -0.3987112833542081, 0.7558039572880805, -0.006944504243281051, 0.7468323113386505, -0.14567395103893507, -0.017107885379904878, -0.4486451734367269, 0.5443168048364716, 1.4211835460144953, -0.6063488638670887, -0.09290764467666354, 0.01863868326745875, 0.8780901183145164, -1.190440348096805, -0.4000294637213442, -0.10438609713958276, -0.5239863861389276, 1.2214671745504873, -0.3948108454960604, 0.40038270662961606, -0.5543134401960452, 0.6716618463325195], [-0.4775557206380146, 0.41598291121475656, -0.11356489353822731, 0.3089495265866299, 0.20205450149330786, 0.27093187172021166, 0.10156198135426568, -0.031540006956663855, -0.5471363944717966, -0.21897421437403736, -0.4339375748587587, 1.0307029057424768, 0.7911578701332476, -0.6311301131127843, 1.7338127744527465, -0.4413669827151891, -0.14662187522378312, -0.127029648581118, 0.9723583811224672, 0.5631999632393349, 1.1131569828597423, -0.16954129699942977, 0.20853057861916696, -0.6611785603108943], [0.027537131120082815, -0.27530388813002943, -1.0524598107496164, 0.2579060188800369, 0.986786687618556, 0.5369655301486934, 1.0623923045729475, 0.21268042718578697, -1.0906919704703704, -0.24254864763448666, -0.7831080246023364, 1.976090461286157, 0.4998504304397757, -1.7381919044810352, 0.6088995883805935, 0.12183256451097003, 0.3309779234658249, 0.3005034810745553, -0.15613503712020804, -0.11058968788262157, -0.16374983839612875, 0.010956539156060385, -0.0014879939832894897, 0.351996998820648], [-0.39056871161091894, -0.390413579642029, 0.3719478501251168, 0.20517558508634273, -0.06045517692889864, 0.38895665321836986, -0.4465635617774916, 0.23887927242671944, -0.06749053025393029, -0.3760921617622445, 0.8144143727188498, 0.19314600321893347, 0.620300321512221, 0.3621854752849491, 0.350908893675593, 1.6424722974708523, -0.3148820466128038, -0.3032721382116013, 0.27987088225714696, -0.22380297556313491, -0.849536245721844, 0.3979489912923077, -0.38762297305193866, 0.18460959734514354], [-0.07861806790367823, 0.10548669528220961, 0.5967743119187537, 0.004176563529923166, 0.6721798195639174, 0.6711291292227829, -0.3853197375353583, 1.0506483280141823, 1.4343276992922087, -0.2521724021725473, 0.9679196384882833, -0.33450905327765523, -0.5749830993678648, 0.1288201957293272, 0.5731649834718723, -1.010988774625093, 1.78894851730031, 0.1898793208486433, -0.4733064835290843, 0.2908520308766852, 0.525449657302861, 0.8669006085801849, 0.4364258203189348, -0.5230411356744539], [-0.5000225112852852, 0.0007968059771210132, 0.38120821579296577, -0.9163154436755766, 0.5156156700749421, 0.5864364076134715, -0.07513779105990709, 0.13619973283631892, -0.31213677161404585, 1.198667971530618, -0.09982863544274272, 0.16923053638994973, -0.47545740208204196, 0.40882183560902324, 0.6144559481999285, -1.0518716947991575, -0.33842793876728344, -0.05772128805396528, 0.5059462238648464, 0.5688450566946139, -0.25013703154314654, 0.19482860068574032, -0.41587452736653235, 0.24645937012955899], [0.1518370771207271, -0.042820208215017766, 0.5491226757150048, -0.08986445914137277, 0.010438252961188587, 0.22481752402261868, 0.38203090750947294, 0.509295319807286, 0.6760655244373841, 0.43872122081423376, -0.6146991774429166, -0.06296501811726131, 0.08591415127822742, -0.2690738162898946, -0.09982966609498499, 0.35223517612563165, 0.430887230517687, -0.2958069582921394, 1.1039295277102898, 0.2901067064110541, 0.0006435287306571939, -0.4943078544779466, 0.20226732639105766, -0.06350005816516287], [-0.6032711503548641, -0.8218246938212325, -0.04549124762750076, 0.04760595691902187, -0.4796184834332665, 0.1960923756448113, 0.27699804844307235, 0.18587135043614883, 0.4037877573353711, 0.2605070599431529, -0.12668862692496685, -0.3783606320232571, 0.3913044378600963, 0.16125474756838784, -0.05830604714889145, -0.6265690997359358, -0.23333597767250977, 1.5296897259314028, 1.2636564981909217, -0.6802950013391217, -0.7868273815995629, -0.11545915007374316, -0.00322948275304918, -0.4853483899060387], [0.7921773802803831, -0.39687569106653997, 0.03267040101495231, 0.9047807854808525, 0.3504912033969896, -0.4751052595770599, 0.07373410721825915, 0.5425263620640292, 0.18737533553546679, -0.11187794521006146, -0.3497998453595361, 0.3035814842789756, -0.16956150401664222, 0.07879842452252576, -0.8990469299938271, -0.527419194862506, -0.14811160345855842, 0.1461148897683736, 0.8707924611008776, -0.18968056751185491, 0.738102397822756, -0.0019111626789059366, -0.22255903577120853, -0.13473606878094516], [0.9849132353454269, 0.3285605211105698, 0.5950779420814846, -0.4114282512255259, -0.08863840607886905, 0.6129986428838312, -0.47852282797417584, -0.015658136696920615, -0.7462829981273673, 0.8512330430799983, -1.244679041645974, 1.3230005612873263, -0.18363087430229258, 0.11464873698917125, 0.7099747525063445, -1.3176715849203644, -0.01757058320612981, 0.001961298766065869, -0.6067962982362245, 0.3784821068450142, 0.6829267443630722, -0.06171534598604458, -0.3105480448772976, -0.3654505865849977], [-0.7812656711246027, 0.6763672095376901, -0.04651897805476704, 0.3124025718747608, -0.6828299925187523, -0.5709011802775247, 0.8353067725809672, -0.14309547832427916, -0.4231087183837712, -0.1172415153420026, -0.5190074929621209, 0.5261135686155572, 0.320182908959637, 0.7907066154872636, 0.07886876003569533, 0.3909556191843649, -0.33216840805340103, 1.477653281680659, -0.46456424254171913, 0.9500027722154544, -0.20680057377321512, 0.33653411486130047, 0.2701401032281982, -0.1386574280127953], [-0.19135889734158681, 0.26107053304177724, 0.29008028848437994, -0.7824878369838132, -0.43444271732009, 0.07149895306443517, -0.023224316641493232, 0.16793670913418812, -0.0918742006740697, 0.8279162684053353, 0.37205810424251395, -0.7606950958231747, 0.0188605357477584, 0.7722578852197964, 0.1606322220993861, -0.3742299462277112, 0.27228350223610304, -0.4412864780949691, -0.45697325713165693, -0.5568552244700201, -0.4640826468135815, -0.20505010737878632, 0.11994457686414321, 0.18067573968932413], [-0.14028510252133594, -0.07775916188271932, 0.12287621016467011, -0.23167465829268777, -0.36813733580091057, -0.21114151774907716, -0.023136612275614893, -0.05736578716747376, -1.0318036428251902, -1.476158118458339, -0.7858692057386212, -0.77191725587821, 0.023093676838144762, 0.06300856573960513, 0.1656364563576043, -0.26289951138863626, 0.8286368367134416, -0.41807945020953224, -0.22270243500812215, -0.06670363348554603, 0.17387687461482002, 0.09360744263086798, 0.34576213230756797, -0.5992803970753416], [-0.1627575351530674, -0.0660635932502475, -0.008578798431541685, 0.20380528557913705, 0.19532924750856104, -0.5602595375814384, 0.4330740229342472, -0.708716482607827, -1.223495682986028, 0.8721121281832216, -1.5409922415070105, 0.3714503308987283, 0.5560453865712142, 2.056160391462484, -0.7055756046397398, -1.079947113642681, -0.15375320901973505, -0.10177174126228182, 0.844212615955863, -0.23853396847753305, -0.295409555087169, 0.7240946604131786, 0.5511641277711726, -0.0673549990241497], [0.29273871915058597, -0.2621091339051564, 0.29859617110797587, 0.5210170763019056, -0.8635277648636199, 0.3262477260136169, 0.09895501169337001, -0.20182561609015395, 0.14258363925740825, -0.3658692705570266, -0.015018930780467456, 0.13706804036303585, 0.06252237990883115, 0.15422635185812017, 0.8815688011819404, -0.6235617972754125, -0.05040050703515284, 0.39118152112638993, 1.045230209167708, 0.3652688113959022, 0.10373410792096563, 0.4509575454001765, 0.26829911961305053, -0.2789035816581334], [0.2177238204249063, -0.17378120652192813, 0.06934511715179184, -0.3916385108051174, 0.38870123151185104, 0.3180336095461186, 0.3184172805080611, -0.2880330903366014, -0.1668102566555028, -0.5987914263387896, -0.06365440816457724, 0.10234406866716662, 0.7359370922303589, 0.4916065326926553, -1.111848705994793, -0.42765935383006254, -0.3498673366401071, -0.13178120200398682, -0.34499707802904006, 0.2519830773631513, -0.2003363447809267, -0.5966657214638065, 0.21698051456418951, 0.31439362903044443], [0.862620739549699, 0.8772331064667466, -0.03274424151582402, -0.1190185026817614, -0.17220360851464425, 0.36283016560184306, 0.4521648002126588, -0.32918839069297107, 0.6788315863471861, -1.0018268495865457, 1.6018871975555042, -0.5142355974049483, 0.1540664232968076, 0.7042824198533693, -0.008127672535780726, 0.2814808073336054, 1.1635810938993416, -0.10882396010163387, -0.12105442889043222, 0.12080405246536971, 0.7759327112290246, -0.29899134658607246, 0.30988398974396314, -0.3198791148121164], [-0.8554547013113173, 0.22913589038781607, -0.010441718099839046, 0.1337778823156919, 0.2613294092545529, -0.4808719321358922, -0.003340966228500893, -0.13049382028744297, 0.6099890625369685, -0.13250591389068056, -0.2735480209944064, 0.2392275119419581, -0.8863507117682722, 0.3126010874149419, 1.4588170146290986, -0.504559241824241, 0.2233393163209763, -0.9691692665929269, -0.11281157032568866, 0.2470495419879665, 0.18335139308771897, 0.01767024002958274, -0.6830282929946198, 0.12851819224543642], [0.21017850793857046, 0.5524781067996906, 0.007314772387973534, -0.31179591768361425, 0.5993690859352887, 0.3679431114130763, -0.1341272065765441, -0.8059564618259388, 1.0072918825356663, -1.1604631317829226, -1.0900771019882045, 0.5025158506731061, -0.901849563218214, 0.06834544750368984, 0.13802811812618712, 1.5152167411606565, 0.005729879018417816, -0.3785636079846175, 0.19437583126958324, 0.6427464279972871, 0.6287396970222605, 0.6538395965080361, -0.3434643646156251, 0.12185066189759718], [-0.3505860892657382, 0.0896633089488032, 0.2687413828730985, -0.17534012306011035, 0.21355665036082372, -0.26703617182175793, -0.24305798753576852, 0.2296932489480789, 0.4207797652252724, -1.6092280965981065, 0.20898672630029833, -0.0005993428942524151, -0.41071324631910366, 0.35263810205087925, 1.0888341153166996, -0.49151377390105955, 0.12486290458137517, -0.06293090433784336, 1.4458294814143149, -0.5810926819247166, -0.5748897063470164, 0.04001269030084358, -0.7215959989880183, -0.5706307492698764], [-0.0866737145347466, 0.08375324853219407, 0.42395736629434366, 0.5330546277944413, -0.2707912688317096, -0.09188136086780166, -0.6705414736559147, -0.5912704829697863, -0.05886481034908431, 0.20752452478522201, -0.22137533964574327, -0.14984356768824844, 0.5310923689178666, 0.6117830023543989, 0.4280916076785075, -1.0721656757215638, 0.5187546792033135, -0.12353098053779962, 0.3586522339300472, -0.2989791539694322, -0.03853628497846986, 0.7480892510333743, -0.592344493416578, 0.11569063016081527], [0.16215074928623693, -0.19972152746663105, -0.912739240636115, 0.2717307510996193, -0.3908827990188437, -0.12299735575661944, 0.14531038461284432, 0.16325992735651584, 0.18210253178241384, -0.17880947990497162, 1.228793366705139, 0.44486364453333854, -0.31880528180974876, -0.22162360249529345, -0.3369118404771433, 1.6794623053391577, -0.28746631486407365, 0.07213657407555608, 0.00810751762168875, 0.55672923756301, -0.8545305615620306, 0.06604797820014617, -0.7535906565248351, -0.025952026699051372], [0.002464282273092702, -0.8246422877297909, 0.2663711250519708, -0.21150355843254134, -0.6612552059483171, -1.0076876245410231, 0.5681336501980172, 0.049225602478265205, 1.0960805912423595, 1.2369428627016459, 0.876387713981967, 0.0507497149690968, -0.03600831253107923, 0.16049718863417653, -0.25116885469541783, 0.2798444148142689, -0.020885251685673338, -0.5947637164209014, 0.07683559900405387, 0.5360409624939044, -0.8091141598527777, -0.7431839716049177, -0.2674253052588784, -0.8035561405198447], [0.07713761784125721, 0.2772453074956811, -0.04723124324015974, -0.5887469199859648, 0.31861099444830826, 0.4897657965918067, 0.19216290619296592, 0.669255472922408, -0.363831513805505, -0.7429242257584282, 0.7384515768402871, 0.4293167241425096, 0.09272970449343096, 0.5178924269622515, 0.07305243391026701, 0.7453922042640111, -0.37579071537799225, -0.48658850215729166, 0.02736254053479725, 0.13699269062742075, -0.4411886910084172, -0.02733231216562752, 0.14421628243602527, 0.721058624860269], [0.8704251498678407, -0.3165306360074399, -0.2234999066158568, 0.42449978582837733, 0.08546030281917472, 0.12314706140927065, 0.3893436988609611, 0.3171262662597349, -1.9336543963130421, 1.7357834229992084, 0.117686970942265, 1.386504336010429, 0.6748701782583305, 1.8985754349315027, -0.3063957233506352, -0.6030287396511099, -0.06157827577578599, -0.3179708931436314, -0.4932065649297268, -0.6328368523245991, 0.4313188052967495, 1.854572993199241, 1.1065000644507923, 0.2288799428895255], [-0.16435109098826353, 0.07494956638091288, -0.35190725786874155, -0.03665757439973758, -0.5133889323837417, -0.887829260837698, -0.2794292961539985, -0.2712758297110536, 0.3709433091687024, -1.251335173749488, 0.06394141273813135, -0.18881704069614536, -0.027687929511044863, -0.6412903938250443, 0.43633903495465126, 0.7034988230247772, -0.05057613997165104, 0.22538932373284015, 0.044296240473931554, 0.10245005143361284, -0.34975621633668463, 0.73173866440183, 0.007101179233693838, 0.8573845354728317], [0.4262400416116839, 0.6883604818400373, 0.00877124918784944, 0.2503867375607298, -0.28891330425155276, -0.401783704040723, -0.17721979470803542, -0.13297751183871684, 0.042099879194647194, -1.0530061384420633, -0.9115014806990962, -0.8253631621252573, 0.37121256900036753, 1.0868754323832694, -0.9219639074204038, 0.10857323592393703, -0.49249725732994004, 0.1188910115310515, -0.24532454667742787, -0.08987616891383908, 0.13847977704159395, -0.12773936020263135, 0.4410566809664129, -0.007802720168417456], [0.1653939843871798, 0.07440575454167936, 0.8050643703315955, -0.040664992547837564, -0.7580069394211373, 0.08815692818927004, -0.3493563285712155, 0.08645980684610505, -0.0784785744037039, -0.46593692861972225, -0.3516941646333065, 0.8647339220324205, 0.1643795781988277, -0.2714893712963506, 0.43948011198966597, 1.7263932312917984, -0.2778019181232092, 0.21245654128805466, 0.46323617411081097, 0.857007015666931, 0.4561360294869865, -0.19857804455727396, -0.7298086731100707, -0.057942863501523736], [0.5330404855720077, -0.24187344620322615, -0.03465334596438416, 0.27433025345650625, -0.4277904157037286, 0.1344129880144248, 0.2158031384365429, 0.3573132188510039, -0.20803290921744502, 0.2264914641614774, 0.018598089295872616, -0.6927009575746201, -0.533593469312674, -1.2945268856085863, -0.9782215888213824, 0.7082279435864703, 0.2002129698923367, 0.18914929278677278, -0.26979001884190656, 0.003625605672116636, -0.6906568376192203, -0.22563678910561488, -0.4099581751360206, -0.2647227774263088], [0.5226875449455874, 0.26488720719248665, 0.19461201707806183, -0.5373386674381193, -1.2315323946548529, -0.41143697612772656, 0.6280586200386404, 0.05217834580638351, 1.2898011380018517, 0.28557704378274096, 0.11624830189161395, -0.5188156652710686, -1.1996237505115808, -0.19829484327586933, -2.125171212189443, -0.29030849255162555, 0.46748611099935994, -0.2091808731865959, -0.5469484068276415, 0.1370322361220358, 0.4419210548663979, -0.7370846552157773, 1.124626126114835, -0.2890756399665275], [-0.9497620966581998, -0.14435423722461652, 0.18248279740901396, -0.7309937122564466, 0.2837142434944731, -0.49335250884309706, 0.45236992568409357, 0.016206188946526555, -0.3198522459991402, 0.24282649733868641, 0.24673586273688758, 0.6063333029018906, -0.21032836848923944, 0.32820210454465426, -0.5907638062561054, -0.5502260840767779, 0.6713622701686232, -0.5339542342258148, -0.15511545105162675, 0.6149659875547012, 0.48992033043635697, -0.43369609789706126, 1.6627550324788651, -0.36702439539583775], [1.4067365642187803, -0.5253497485662364, 0.14720199108553983, -0.5679688821520493, 0.554465742293374, 0.10023138119362798, 0.3994691786309682, 0.05139673338220333, 1.1784655491665748, -0.1977488611260814, 1.1254557353723689, -0.44060120656347473, 0.23179559642475941, 0.8701518004272446, -0.22676746869346423, -0.16083495366064915, 0.7176616315429983, -0.033680550885846317, 0.0626003079069629, -0.14382226333205766, -0.7452367719600315, -0.10288132140885296, 0.02252686597495881, -0.3346103030178669], [-0.4677065239127309, -0.23591986404942827, -0.5867345947363647, -0.38235480450962633, 0.09003615035762264, 0.5411120326645622, 0.37173363601685233, 0.23443276087751175, 0.828680041548069, 0.03046630537509017, 1.084833440925728, -0.3417520193599836, -0.4043443608618408, 0.32822191405767925, 0.07621697694484286, 0.4051506971115614, 1.0630691940813262, 0.6166596416108824, -0.6635801541636303, -0.055744582804157145, 1.2262171420314778, 0.43160085838752765, -0.20033680713391186, 0.3594774894068144], [-0.19922935240119974, 0.25435354105866753, -0.40029440413189965, 0.15179491396520783, 0.41247251663657203, -0.041631431172251473, -0.2473389680237945, -0.18297838976137168, 0.2511568431214564, -0.42579670259220465, -0.5051480150677348, -0.38476850368267773, -0.8877143867956294, 0.6963388927351348, -0.3372223884026096, -0.6769786068888941, -0.22855845861760865, 0.8891035753812773, -0.4268119581701389, -0.6397810095173773, -0.40664399744062496, -0.22587898771429302, 0.878177197473722, -0.24448949792129124], [0.31862631060652197, -0.09059567006133283, -0.6742060066624335, -0.1120765525113525, -0.4704197280298731, 0.7401573729782901, -0.022570938478452082, -0.6412169047204092, -0.021671723751082582, 0.34861945545162387, -0.3159565189832477, 0.27578681092615065, -0.5391700660029488, 0.5495106769679435, -1.4615186189439635, -0.5004927438979472, -0.02473048995810398, -0.3104711311981883, 0.12570059285737994, 0.2683548643687511, -0.3144276935395706, 0.17365131266259548, -0.3461250076191131, -0.05913024957400686], [0.165691767128659, 0.34228108737060364, 0.19793374510235032, -0.0889308492824903, 0.09270356399809343, 0.1743046806552714, 0.43908853417478644, 0.1683734201544038, -0.14649826797518511, 0.37047432268936786, 1.0188601205641354, -1.3912535475620944, -0.3622774596443035, -0.11965894155340535, -0.20096044694897935, -0.4411871667678884, -0.2336459054188035, 0.11917204985683531, -0.40139307120145395, -0.3468196194367704, -0.4147742095853236, 0.3976239658064844, -0.24598295359168182, 0.8200283343944464], [1.044413689710435, -0.05022328202097716, 0.7542459550023523, 0.07226797630064165, -0.7664185615320546, -0.4976611727698951, -0.8743561067278208, -0.7485528503298611, -0.7044994107860431, 0.2947576700129446, -1.6694300604090049, 0.08826689070072641, -0.08828601716105722, 1.49200260890766, -0.41627108708822486, -0.44187980655995995, -0.4130829416254336, -0.22641623627602392, -0.3270193163105901, -0.025925225521000954, 0.18365990470327767, 0.14667210505932876, -0.4713812361213728, -0.726350949192625], [0.5770060823543569, -0.23609355541681287, 0.3064418069802974, -0.3137408537459964, 0.018604764107919357, -0.44157509348295565, 0.37543833422016387, -0.10309276764062926, -0.2812720640695764, -0.01548477249649108, -0.07136306581935756, 0.4822687149801726, -0.48959363728432587, 0.20925985066006736, -0.3028678643330552, -0.3463903707490614, 0.21437625963521234, -0.3362292198771565, -0.17623285097413272, 0.1336242211270314, 1.1309704230216058, -0.2993684698203033, 0.08291879722895898, -0.5599330763285665], [-0.14825873896798242, -0.027906778046211417, 1.0671402983748697, 0.2553211872317097, 0.41171929496128096, -0.5286686493901633, -0.3295301418704624, 0.1387012714649476, 0.3589443803098756, -0.2951614929992592, -0.8340219130858713, 0.6170047230211438, 1.1533281235183337, -0.3590374856970657, -0.000523147105631434, 1.4833643157098915, 0.08148040166189804, -0.12020205952247058, 0.5191963557397935, 0.8372372261822226, 0.383128792493237, -0.4918834518570011, -0.2362059912970925, 0.11457746455628744], [-0.7643665031381136, 0.6015753932540369, 0.14616504312191775, 0.05752723281526872, -0.06745634330618074, -0.06266003170958255, -0.2624489580209529, 0.6214607931179548, 0.2973627172946946, -0.6896840132770546, -0.4344475221119781, 0.41422179725849684, 1.40435732198186, -0.3661457624566472, 0.0087312592170536, -0.5350346005608193, 0.7660969909583862, -0.7051140670547597, -0.03325374382196003, -0.5563600477777805, -0.3298051318528374, -0.21931111954197202, 0.6832870804970641, 0.15082293617810297], [0.35117203996090274, 0.5625029105303705, -0.13165826998857147, -0.3087254045934131, 0.653146240363766, -0.5172586892512635, -0.3111343046874086, 0.3216255587227563, 0.09383192186595843, -1.5749039025662257, -0.289225773258048, 0.06112290534985737, -0.5590629335768905, 0.7260408297181129, -0.31156976723075297, -0.8989389646515509, 0.9215539129817949, -0.5808164826613771, 0.014845005112013539, 0.6876339170765533, 1.0172713105181095, 0.14682483076308478, -0.6737075917442606, -0.53985429950063], [0.5251130129882516, -0.5118333040766888, -0.11757152561531979, 0.07628944490723498, -0.037835082291440274, -0.3521279571546717, 0.28632894362798433, -0.22295858419553322, 0.2560947698853305, -0.40161129002128726, 1.2484199960949114, 0.00045219619843817597, -0.14637609402861643, -1.003766927449276, -0.729786653447575, 0.755036814826361, -0.47156919012586984, 0.2288866510165046, -0.2947096941544649, -0.46455782257082073, 0.07098776778802142, -0.2520149801966898, 0.30681781174919026, -0.4356823039881094], [-0.056017567580249304, -0.9043656303544182, -0.0385639113917775, -0.7598299200954196, 0.3506975470341052, 0.2730045516585361, -0.2647895490636919, 0.07907613925971628, -0.9371685703606518, 0.003032237774019715, -0.5348313203267012, 0.09608042067389186, -0.45991851020060776, -0.1041636904806849, 0.28846627231869815, 0.20861895687996532, 0.41080470542138614, 1.8933678553223836, -0.3863911761350653, 0.48250372978183204, -0.1595981171181472, -0.5001922467061433, 0.5847670771914092, -0.10813071181975342], [0.09670941161224585, -0.022100128622658664, 0.1890729038191502, 0.011690827554905664, -0.19714430490516927, -0.32212389769845573, 0.7502364206102502, 0.09301429810679536, -1.3795509437726776, -0.9585476073464544, 0.25669325778986307, -1.0541803852266274, -1.2273470506692763, -0.8896300877686935, 0.21460037869171944, 0.22063791909538136, -0.43614786980544595, 0.05919799761742893, -0.18775093821053515, -0.6643457370261763, 0.11174373577406792, 0.054941470968888295, -0.5854922137090165, 0.2683355905603655], [0.040087120914660074, 0.34260193249267173, -0.17350747800748684, -0.09815648517963456, 0.33133945437049267, 0.5198950121559596, 0.28338229084574684, -0.6437076942557438, 0.45440999429921203, -0.2760553299907079, 0.3641289890127464, 0.443917931026404, -0.21791580900820487, -1.5423519160986294, -0.3231436209170011, -0.2432537786056001, 0.19993409086682676, 0.6552012319341384, 0.13042970945804683, -0.6223788526426494, -0.3213656295717744, 1.6650688760524386, 0.19068408291721967, 1.3457153039477658], [0.0741212267086447, 0.029836668837996832, 0.23309607347353734, -0.3111276080103136, -0.46185580227756884, -0.009290510634956431, -0.44125042482804316, -0.4603507407758951, 0.2596391242512353, -0.12855899295275183, 1.233916337411417, -0.4485751820086158, -0.25843278790430385, -1.380595961638996, -0.11732741634197255, 0.6851733211469094, 0.3802462025670591, 0.490100768927601, 0.3930632105404599, -0.37401384128934534, 0.5948351205642121, -0.5752105910797783, 0.9379436509240805, -0.24730366172325488], [0.018087637130654605, 0.42654130940616286, 0.07875096656639288, 0.5357205306206705, -0.43720509377063255, 0.3697329641312152, -0.03485556590583157, -0.3782764738790639, -1.3306075282491352, -0.282717813468532, -0.09380894878187837, 0.295984817928988, 1.0740169917184268, -0.7727080800516677, 1.656918029956444, -0.25637080575731896, 0.24310824393858707, -0.47625888280209694, 0.19833210934695628, 1.0192313379588627, 0.9121130397902814, -0.29109903736074466, 0.9574524665098358, -0.43948059474641293], [-0.1350146952337596, -0.32031812843975654, -0.09134257507150782, -0.2531066205152457, 0.6017425524481463, -0.12181825909858668, -0.6877604089737246, -0.07945217499092774, -0.6023423889395797, -0.2651697327246463, -0.2819149165356318, -0.7526601470178906, 0.3419812237245049, 0.1952304834892151, 0.33866225536365696, -0.4271820859478635, -0.3379595012544671, -0.04159781548246854, 0.25681101974505843, -0.3368839682302246, 0.5510916613953869, 0.027927197873141907, -0.5873773241022807, 0.5307604472532572], [0.21538899944387363, -0.09447458182078415, 0.42542554921581355, -0.32166301510078893, -0.3716614732303872, 0.789056539040187, -0.028266733788057802, 0.24267211216926843, -0.5794802222874352, 0.36200103948693935, -0.28803898373263825, 0.669201565016278, 0.5273273446054013, -0.0809141933437345, -0.25617871273329446, -1.6453993110752039, 0.39931196544239894, 0.07500934023542245, 0.5489593319254298, -0.7000375388853693, -0.20184018433048498, 0.12078725504318168, -0.4097468225555589, 0.4315612562070698], [0.26278152773056945, 0.27837021585918986, 0.033074427122714224, -0.017674950062638556, 0.5194494732760324, -0.1816245499848507, 0.023464912149026344, 0.30541527442012956, -0.2665148950696642, -0.5649100154194013, -0.15274983618851465, -1.3033887691253494, -0.10781216596389988, -0.7182294807045579, -0.11749174141522886, 0.7320155836821656, -0.6917270398882401, 1.0179016414769286, -0.5751101056454179, -0.5117046221381886, -0.7450878466589682, -0.2660023098938983, 0.12918710969320915, -0.25706974572545127], [-0.12388795493228118, -0.5988760008692287, 0.23294397519547902, 0.5171849565225339, 0.13942482871865858, -0.7227104177068601, 0.2658099277798629, 0.8636850400551339, 0.13117155748160353, -0.14686576932578826, -2.3181836538524756, 1.1701768940387296, 0.9125332018085881, -0.43366414217879795, 0.5393750699129771, -0.02177977456077715, 0.5558683947385379, -0.6559997222410807, -0.3821360483806105, 0.07376807975206388, 0.37334470717656665, -0.34153249928554336, 0.7421902358840248, -0.21565561223067845], [-0.6210219667387539, -1.084987593687524, -0.1026903524227242, 0.096466720829996, 0.38137303445273923, 0.4193870314794756, 0.015558403607821994, 0.2441089733373849, -0.6554312680467889, -0.4032552967165869, -0.46966492939294846, -0.8051674853809268, -0.8482302287307839, -0.5365095829792058, 0.4164524306231944, -0.5177861407539147, 0.09457636210089428, 0.04736784274830101, -0.24349078777042626, 0.17677204164589808, 0.3159922681389476, 0.004623132519011896, 0.28116938160487714, -0.5299464255015893], [0.19552834448960157, 0.09259467047689389, -0.01094322934772996, 0.0018666682467681846, 0.34631293844675637, 0.23174015598473138, -0.22177395575713013, 0.4837217219539584, 0.38140920950539053, 0.6882648516034827, -0.537514683988874, 0.16737186934622167, 0.13354838502827543, -0.1529669486995589, 0.9914026317930663, -0.5134165117025289, -0.12817735379443124, -0.15648832465594176, -0.3110017108614838, -0.40142046612588117, -0.6812676982412357, -0.7020685540138208, -0.18510247498362767, 0.3321230173815923], [-0.2621541384194255, -0.05353985518365567, 0.08081311866102722, -0.7275854141636913, -0.1459750202996933, 0.4360719428354253, 0.34622249886564826, -0.5058453616727548, -1.1818472909621105, 0.5241615978584055, 0.1005701310163106, 0.07699234182238095, 0.08103695793385651, -0.3116242222233147, -1.0334091809625183, -0.06795358331301135, 0.1471326742025941, -0.4111652208961071, -0.2471885898813295, 0.10820007288418244, 0.28521914362585465, -0.45064377797779936, 1.3515830073869488, -0.5229151674242096], [-0.30549044875996956, -0.40145419482878075, -0.09489013938520184, 0.0398129791297477, -0.6984930919581779, 0.19182419613564997, 0.006935860674130215, -0.021262117163886072, -0.29298028449294217, 0.17294968272105907, -0.3331938002683602, -0.5070991503233758, 0.5323181570219696, 0.767811008804004, 0.1879508653357407, -0.9403418719144782, -0.3767814241927105, 0.10361256329966674, 0.2512155655384443, 0.36961808323777967, 0.6064034590850368, 0.013754463239555311, -0.6318200818772831, -0.5018686525561322], [-0.23753242557482876, -0.03351523000956404, -0.8259508925707109, 0.16295211517069683, 0.12204795934696398, -0.00028408393279765636, -0.5636416792880775, 0.5597361144357973, 0.06944904404823223, 0.13521445787412203, -0.5702450880269494, 0.0422122968372739, -0.50956707727515, 1.1175457964320996, -1.0241935246330385, -0.6893050111530051, -0.6697699198032893, -0.5321809027942673, -0.15854707377418994, 0.16156016070186244, 0.7710699992233453, -0.06392109876438817, -0.34678480643403736, -0.025576779759898322], [0.537075474640666, -0.7282575361728904, 0.21306070204158628, 0.13016593191203707, -1.138864267046521, 0.2823061654940001, 0.27087529408413386, 0.3212132788667536, 0.7243312443490928, -0.3683714753669289, -0.5159631976250214, -0.10254737535717609, 0.26284782687012026, 0.1538325223010411, -0.09725218015987785, 1.0330025219834655, -0.21736046290358463, 0.13845127972143093, 1.611610325072861, -0.13581714946252985, -0.002760150091784391, -0.5133367083860809, -0.6542682492800621, 0.5050406246284459], [0.12101361118876262, -0.22548604260679134, -0.22484659344536492, 0.2799057272792381, 0.5579340613448347, -0.17304804849084154, -0.15161244640160998, 0.31155239423506786, 0.8711368624339334, -0.602025816805167, 0.9953044840413067, -0.3417801503602227, -0.6139022283380481, -1.143692028890596, -0.5510121614543555, 0.45495794162189934, -0.5763344250985466, 0.4676628556545739, 0.20594852582801176, -0.2693940453746447, -0.48945749359771606, -0.18228245118882117, -0.027655390515433236, -0.37145715891743947], [-0.8708147174977653, 0.22692855527739678, -0.09074421733550823, -0.8434298665888447, 0.3768442455794152, -0.3645258875107877, 0.33634287614343955, 0.604718370128623, 0.9068689065987656, 0.9163659438625061, -0.2749611323682046, -0.4434310634896286, -0.4891708362991814, -1.0192803060229905, -0.578389443925364, 0.6640961404314207, -0.6925397193606389, 0.34725800877407587, -0.7902896999060954, -0.17902174057267425, 0.24296553861862663, -0.3691668133637543, -0.22889369408440355, -0.5921700389704287], [-0.4801877958239845, -0.44781802756263955, 0.013997282961162285, -0.6578477066308616, 0.359314923149714, 0.13519002566518795, 0.42406617715326095, -0.774520132587888, 0.4734684719441613, -0.5283603348909663, 0.23747916794301327, 0.28243697988122485, 0.5423744340433031, 0.5744097913981796, -1.1178733634846612, -0.20560907291508834, -0.2358567969341161, -0.6826477481507884, -0.17255423552672103, -0.28735376205846497, 0.0838879331271872, -0.10675120302271256, -0.7682264109851273, -0.8977431356905129], [0.1418553075747069, 0.23639240364513212, -0.8277522833046209, 0.441897148712596, -0.5927499229650126, 0.13544046463125253, -0.6183151153938893, 0.3558171569429569, -0.3328130106614575, 0.5921056027044539, 0.9476831099996622, -1.0719636380438375, -0.9138849653322427, -1.355800793196153, 0.059506444292301626, 0.5753224648499317, -0.8032189877071645, -0.001571054691462715, -0.2201598668896458, -0.6086597581466459, -0.049059553600085466, -0.19260005421356927, 0.1676333202130042, -0.8594756042813084]]}}, {"name": "grid_regular", "n_cells": 100, "n_genes": 5, "k": 8, "max_m": 1, "decay": "scaled_gaussian", "k_per_harmonic": [8, 16], "locations": [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0], [3.0, 0.0], [4.0, 0.0], [5.0, 0.0], [6.0, 0.0], [7.0, 0.0], [8.0, 0.0], [9.0, 0.0], [0.0, 1.0], [1.0, 1.0], [2.0, 1.0], [3.0, 1.0], [4.0, 1.0], [5.0, 1.0], [6.0, 1.0], [7.0, 1.0], [8.0, 1.0], [9.0, 1.0], [0.0, 2.0], [1.0, 2.0], [2.0, 2.0], [3.0, 2.0], [4.0, 2.0], [5.0, 2.0], [6.0, 2.0], [7.0, 2.0], [8.0, 2.0], [9.0, 2.0], [0.0, 3.0], [1.0, 3.0], [2.0, 3.0], [3.0, 3.0], [4.0, 3.0], [5.0, 3.0], [6.0, 3.0], [7.0, 3.0], [8.0, 3.0], [9.0, 3.0], [0.0, 4.0], [1.0, 4.0], [2.0, 4.0], [3.0, 4.0], [4.0, 4.0], [5.0, 4.0], [6.0, 4.0], [7.0, 4.0], [8.0, 4.0], [9.0, 4.0], [0.0, 5.0], [1.0, 5.0], [2.0, 5.0], [3.0, 5.0], [4.0, 5.0], [5.0, 5.0], [6.0, 5.0], [7.0, 5.0], [8.0, 5.0], [9.0, 5.0], [0.0, 6.0], [1.0, 6.0], [2.0, 6.0], [3.0, 6.0], [4.0, 6.0], [5.0, 6.0], [6.0, 6.0], [7.0, 6.0], [8.0, 6.0], [9.0, 6.0], [0.0, 7.0], [1.0, 7.0], [2.0, 7.0], [3.0, 7.0], [4.0, 7.0], [5.0, 7.0], [6.0, 7.0], [7.0, 7.0], [8.0, 7.0], [9.0, 7.0], [0.0, 8.0], [1.0, 8.0], [2.0, 8.0], [3.0, 8.0], [4.0, 8.0], [5.0, 8.0], [6.0, 8.0], [7.0, 8.0], [8.0, 8.0], [9.0, 8.0], [0.0, 9.0], [1.0, 9.0], [2.0, 9.0], [3.0, 9.0], [4.0, 9.0], [5.0, 9.0], [6.0, 9.0], [7.0, 9.0], [8.0, 9.0], [9.0, 9.0]], "features": [[2.0409191213851825, -2.5556650313141818, 0.41809884672577885, -0.5677696061279298, -0.45264929211044586], [-0.2155971630897659, -2.019986129147251, -0.23193237764418947, -0.8652130762749417, 3.3229995166448827], [0.22578661322792176, -0.3526307943415954, -0.2812874181513504, -0.6680463461089501, -1.0551505512051214], [-0.39080097723465473, 0.48194538850678587, -0.2385536065733667, 0.9577587029597641, -0.19980212906658], [0.024259565076664623, 1.545820851212812, 0.5451055226876446, -0.505228735614018, -0.1828389745977349], [0.5405251317548021, 1.9350880340988528, -0.2696203273419135, -0.24355867907910456, 1.0023136012756912], [-0.8864599431605871, -0.291720232439864, 0.8825389674564839, 0.5803500161908991, 0.09151670328235219], [0.6701043548284794, -2.8281623068437627, 1.02130681750008, -0.9596447598081417, -1.6686198426559695], [0.27644575952099965, 0.7005448853493901, -0.4447674556827841, -1.0764058401008076, 0.026124833534033623], [-0.05274730824287927, 1.4055981660180925, 0.7474079874793504, 0.19381564626462, 1.1116332052239921], [-0.20552304990579248, -0.9258995736483681, 0.584058311025248, 0.5825384186556901, -0.2148289111268558], [-0.7828085779639662, 0.22915390521326254, -2.4938942784579905, 0.690124770162812, 0.4913682607449912], [-1.6388571438904884, 0.06135350983817159, -0.9640996635412404, 0.7572210447581504, -2.034167273443428], [-0.9144945379945887, 0.7095799877420675, 1.156401048432157, -2.158005380126208, -0.49803984475130336], [0.32802009254257697, -0.6092161379498706, 1.5906402313231438, -1.1912266816177808, 0.354531946286926], [-1.0484055185445111, 1.4059629431348852, -0.021651229055558368, -0.3722505640006159, -1.7181849497326165], [1.6818255450666806, 0.7527785926973876, 0.753563837509362, 1.1378812589177814, 0.3492265781230293], [-0.6392466105764212, -0.8002412270301018, -0.800199979361005, 1.3700723413337117, -1.4603812011954127], [-0.5963695117707888, -0.32124391928619556, 0.22461902534909414, 0.5753493885078089, -1.2490970090955427], [-1.730013451272522, -0.004414232621967487, 1.2135638252860816, 0.7570580592965243, 0.21565078369996044], [-0.3171556440173552, 0.2932336958002246, -0.24333508574217566, 0.817206580492595, -0.7944473388868819], [0.13423994708633882, -0.11078013611159404, 0.5433593895301524, 0.22463852364937692, 2.550034636307906], [1.498654758135483, 1.4967371655185107, -2.0395038375946424, -0.3403166247023773, -0.6086106159129299], [0.5327215998890392, -2.279026489055327, 1.1744986790091876, 1.0669833108953142, -1.3020708582457947], [-0.9785485286214127, -0.8011720107811816, 0.043295900283144985, 0.6409710646894711, 2.0478860553573326], [-0.19744542988767094, 0.7675025589036195, 0.15541781005943467, 1.7599262839082537, 0.7421578612115688], [1.3685504508744795, -1.0776751897834627, -0.19224071152595104, -0.8137724218420405, 1.5049474040083073], [0.6576399038177728, -0.3051444257775161, -0.4524678870704014, 0.4846648782067015, -0.7014955301795535], [-0.9305888762121555, 0.4812744922715323, 2.463132032105226, -0.24613355406481327, -0.5558657807935545], [-1.171156834025543, -1.3350109575593827, 0.524983234564226, 0.8508030327785525, 0.0091747208824902], [0.3325759886762084, 0.11591657750710396, 0.13865484604722084, -1.5261590525828475, -0.45811827304922115], [0.11147930758994773, -0.7831667805636854, -0.47642974385981746, -0.8191201803277345, -0.3334966741984413], [0.8531082743251359, -0.40658035065559817, -0.15387068019710476, 0.813718359438118, 0.6447702141569163], [1.6952075589596332, -2.090485078128588, 0.856858944523106, -0.4822840867730822, 0.13469181881788084], [0.837719384899064, 1.0832531556913447, 1.0393506903088359, 0.15510669107825276, 1.6096626830183138], [-0.2829742272161367, -0.14098191307078672, 0.7993511888940862, -0.5513724079804637, 2.160906258701247], [1.019206565354622, 2.1755753226203938, -0.026589187155779802, -0.38308855026130717, 0.16704800216692559], [0.7345765026061907, -0.5874276868740115, 0.3797017469724474, -0.01680427892083426, 1.6156817605764437], [-0.6627018123008657, 1.046161771728719, -0.6438635355400087, -0.9606341931074224, -0.7102994273756232], [-1.1901858618422472, 0.1463503600664521, 1.0312607960786646, 0.1643148785347983, 0.6243251121848756], [1.6321741955751323, 0.27002644717885166, 0.19516236096309458, -0.27506146796027464, -1.6082422850112825], [0.7597389318680837, -1.7564604476259789, 0.6526764363838281, -0.014320335733954404, 1.1267814508104348], [-0.067770260510462, -0.8232001579576669, 0.3579102667525859, -0.5602361357081261, -0.1809568246618137], [0.0418707868620003, -0.13454971174566932, -0.18880227497381663, -0.8324449882870513, -0.18913378409281006], [-2.13834060712102, -0.15733209522523053, -1.198055985931922, 1.1202636903470218, 1.2699267473212534], [-1.951025780521256, 0.14491679036588978, -0.12636392216675604, -1.0467156300808687, 0.5316531426489993], [-0.46168954465474565, -1.7675990956866041, -0.2666766520569678, -0.14825311830009477, 0.10643101824147437], [-1.2312329987327657, 0.6156809269215894, 0.7354570881988916, -1.1458272768549103, -0.6588555689831765], [-0.08033731382935666, -0.5659253270123664, 1.7437546098496857, 0.20837211615824647, -1.010582036354199], [-0.7881089276247821, -0.05747025825572099, 2.2957788082586084, -0.17826432182306642, 0.12747641923980615], [0.5140453781581755, -0.0401259362630417, 2.280660872566708, -0.5315249470251602, 0.7442031251457859], [0.16043796898357113, 0.6211963732164166, -1.1766429584197382, 1.768112695107191, -0.12152750716346146], [0.03416326206751611, -0.9349762618687502, -0.7296952681832494, 0.5642394331680308, 0.9864998861106795], [0.7532546907537343, 1.2089702496885697, 0.7144889121895972, 0.02846183335685169, 0.8365259894445134], [0.5936032404079788, -0.10057526654145102, 0.726072718540168, 1.285697394529069, 0.2345713239341999], [-0.35620509743082307, 0.7187113729613218, 1.9007217378325845, -0.2105620431624384, -0.09230962211598169], [-0.13639753203462462, 1.2230174081629868, -1.837198256913153, 0.3658453707474612, 1.1922639157608697], [-0.8133831709015653, 1.4889774081624723, 0.5353090084702862, -0.5490359172550382, 0.20413981937772036], [-1.5344921212662044, -0.5655710361854747, 1.8269038175493117, -0.8938040482383052, 1.8445717319111685], [-0.08157358819027508, 0.9946628839764439, 0.04389702264947434, -2.24148154362366, -0.5726513109844991], [0.1898535965813863, -1.1509497089580938, -1.3474107332725922, 0.3661858537229255, -0.649414999777468], [-1.6958272209806426, -0.6841151736064445, 0.8607375733597276, -0.47374607008243474, 0.9347725714518614], [1.5272727626498412, 0.03251540049551873, -1.1296833434653808, -1.3015650956398057, -0.026253854187163014], [0.8810556770082387, 0.2690153283133568, 0.5472571901882256, -0.4433417809053284, 0.3004227591479358], [-0.4713087658775225, -0.32560990354708425, -1.292246473319263, -1.5722129972246757, -0.4819566918389441], [-1.1075993405277864, -0.9587457201198237, 0.6710474629653865, -0.10708092147336722, 2.914125888022547], [0.926342075423221, -0.6331876151795489, 0.7780073420949039, 0.3568038879399853, -0.6856810795173335], [1.102594967084939, -0.7753286078642612, -3.0583812523616074, 0.7940647591398647, -0.6172591186177742], [1.4860374923545419, -0.6496722067169012, -1.1813542467853593, 1.548461665941953, -1.0754983251353518], [0.20339369150255643, 1.4497271957967346, 0.11449734341089023, -0.08058491531778637, 0.10242343723857332], [0.8390536522388322, -0.8068121596797956, 0.6106409992957679, 0.5770754169394714, 2.332712025382542], [-0.3365255299285121, -0.9148298592004128, 0.735687023006662, -0.3971572496742207, 0.28911616638337856], [0.13257652253025445, 1.1683939613256054, -0.6568374851700608, -0.09227952885816246, -2.5521126492129294], [-0.8901138962794292, 1.5363388115385548, -0.6815059146443607, -0.7014768178924555, -1.2179071819849998], [0.579834289685921, 0.17799016337176263, -1.1868668596304217, 0.6674503740893216, 0.26010587984314715], [0.7540333794321797, -0.6414795084271917, 1.7380087577355086, 0.40986760593441185, -0.11688951697619845], [-0.5188342816073336, -0.24482737168821864, 0.8587919943195114, -0.268966692098378, 1.0781438737081128], [0.5806761725615901, 1.34649517381152, 0.8141042283911752, -0.06293926633583413, -1.9093399421565507], [0.29857058049706936, 0.7890760328884069, 0.16289228138710912, 0.5564317167499324, -0.47162009784744924], [-0.3804775819610508, -0.942389043899057, 1.3619004028225532, 0.15839426359312406, -0.49248608454765586], [-1.3318525072296399, -0.15330727623306564, 1.4426311919625505, 0.46192164641731587, -0.7245215730251725], [1.429494960235201, 1.428510149498043, 0.9807761712193034, 0.7888168682681604, 1.1556517800640662], [0.5432590463456582, 0.7750008175241467, -0.7800253357812693, 1.4995578106517762, 0.23118019002747622], [2.0242118077633657, -2.0422479736216355, 0.7054088681323775, 0.9814615404533438, -0.3429326109514602], [0.45244430747526604, 0.748326398332743, 0.5773815122948983, -0.5396592560845508, -0.14193782995556545], [1.0190394667806781, 1.2773200842190644, 0.09897684360803072, 0.07703247904000432, 0.20049635374714067], [1.0376652098418804, -1.054038467943683, -1.3290658339488934, 0.1243149661886982, -1.1065287680035132], [-0.5871094746650899, 0.08629573829863545, 0.4825049304155798, -1.0720918354802698, 0.8016054467552017], [-1.7737146221951365, 0.5454160492757826, -1.577731751159489, -1.2749233921914813, 0.6422219295773648], [-0.4063622235346329, -0.7955582977503591, -0.4447767592897314, 0.46503259415537146, -0.05404679613036737], [-0.029382775458245247, 1.0547764003067657, -0.7163905922233165, -0.4719336785754862, -0.5224299788413164], [1.1689221606866564, 0.9914056580780776, 1.287076554368245, -0.033750607022160345, -0.15680255183864147], [0.8527729960275634, -0.394411679840583, 0.8306663583748539, 0.724292751580105, -0.6983180131877972], [-0.08319466924015172, -0.11925099258087192, 1.7333403801281198, 2.587823339085075, -0.09992724908523933], [0.014064678908795957, -2.281584454788879, 0.21153229962984432, -0.007032972324828838, -1.0728437917831282], [0.7855942327622222, -1.5657538112025182, -0.21485295179845887, 0.13885676222309065, -1.2489999428150438], [0.8567407422067436, 1.0555617492223077, -1.3864208531734517, -1.4078385985858624, 0.6022594837290922], [-0.030497003390982384, -1.2114031397194822, -0.2952267328703558, -0.10751668062926192, -0.14303893375775825], [0.8274886487936504, 0.38419824987466866, 1.7694638062602646, 1.3743604920127137, 0.6784737722930204], [1.0770793746294716, 1.3238196707795207, 0.7059948367398967, -1.2257422789738366, 0.8594171615043201]], "harmonics": [[[-0.2950577859633129, -0.5511612377254462, -0.5066038270911133, 0.13540084476187605, 0.5830213354179755], [0.0384207134821683, -0.6308410158744377, -0.49285619253336244, 0.04978212751166409, -0.4011780948506191], [-0.507843812344438, -0.1635808946692294, -0.5091645086381394, -0.07289393376291785, 0.16536519848242484], [-0.25973502404483184, 0.21362457533130716, 0.39946933216804265, -0.7381214596921624, -0.4260570814232008], [-0.22090840815396778, 0.5670141274870882, 0.3921277481251933, -0.3867426166182757, 0.011216598290601633], [-0.13790364897519056, 0.49050761842857554, 0.6220561464013562, 0.012859702898921004, -0.33465964586691943], [0.4590528842451707, 0.09992176899798803, 0.20200222361173079, 0.00110595539860117, -0.3981905123760044], [-0.06867885297402378, 0.11216564560709343, 0.048442676805834826, 0.4117168372895066, -0.32225165870295447], [-0.3324261603505191, -0.43541874299475436, 0.6450003842845933, 0.27702906728880033, -0.5458989988309867], [-0.5650535272687927, -0.3649776109693305, 0.4764181189713714, 0.12411167757256865, -0.513380464270311], [0.16746962487938452, -0.6431193925244716, -0.5402761849222125, 0.06953647284074388, 0.4521650622095395], [-0.0315567183651459, -0.5916967633528857, -0.19106347659968914, 0.052731000044364526, 0.3589430546481957], [0.009582738308270264, 0.0175275232941099, -0.5038958545320161, -0.29588797992562743, 0.08816166359020959], [-0.1299006602845422, -0.23181335539624404, 0.11479210056735023, 0.19146505165796981, -0.5121876823184222], [-0.44448420355398904, 0.551412422255146, 0.35532670809833933, -0.10172984982460179, -0.03808666936206571], [0.3517271173159893, 0.42097315379827915, 0.4778624954095526, 0.23510191996675242, 0.6968839662892989], [-0.06059482585781885, -0.1630450041775922, 0.0161843927795968, 0.21428782266936525, -0.3154559639352973], [0.38687656066920173, -0.4649680040445366, 0.48400180810207677, 0.0756461963234424, -0.454450427286774], [-0.49405475235492635, -0.19367761972688974, 0.5584987563244312, 0.18147881234714452, -0.3996539335801071], [-0.5662386385088202, 0.09632238743791938, 0.5601296342395466, 0.21485744618491925, -0.15272648787892207], [0.2064708712296118, -0.29346252367380754, -0.17486251244878814, -0.21735344464507286, 0.28207036429072224], [0.029691285036707114, 0.10881374633950257, -0.9066129113977014, 0.11036553439130484, -0.37970466827391], [-0.010595571714853933, -0.6167769865464886, 0.019632277766994267, 0.2441723473925803, -0.040719670147124715], [0.24811797558239948, -0.10317870146380864, 0.12941376348465314, -0.3442748420344528, 0.22702994963302547], [0.20349806352596242, -0.1822234269834795, 0.8921188386822174, -0.0005695453409062038, 0.2401561844198952], [0.1671680344796386, 0.18275296936485763, 0.38557993679548075, -0.20587052754062068, 0.8720538520702547], [0.4221902382048241, 0.5535550064868661, 0.10139317657304876, 0.5347212143742135, 0.14267364016037964], [0.20939179038429492, -0.024089406574165702, 0.33345480085622814, 0.07971504122444935, 0.0628321656848085], [-0.5312384011652616, -0.25647667360561127, 0.09506684023663617, 0.3484222905351523, -0.35762255174646046], [-0.9534829693099859, 0.26536188117561, 1.0305763856689658, 0.11329669623689122, -0.16065001998079245], [0.45631137225248525, -0.33972994187349226, 0.165019957926597, 0.00891705954443612, -0.049994876927387945], [0.5756898185501187, -0.255289879337987, 0.05154631874888388, -0.11349958896126681, 0.3751995307885839], [0.66130163709897, -0.724213923193496, -0.03372166234841379, -0.3289122180727523, 0.018615827821329575], [0.23556292206973045, -0.31267752652622244, 0.07370492492686281, 0.27215339552171314, 0.33856483298478024], [-0.4152160033519552, -0.6561143000451338, 0.16833325638043414, 0.20032607700600005, 0.9152290269620039], [-0.23349142349915242, 0.37518551906034875, 0.038150224305742955, 0.14759195607297962, 0.9199025635257762], [-0.0019840885050301216, -0.4918720093257077, 0.14587057831506553, -0.25009302945084216, 0.8886952740822204], [-0.04481040100692083, 0.34208776876109304, 0.24933038195169252, -0.41707985593989905, -0.31277988433906373], [-0.455900757630576, -0.17799550812074844, 1.193995495685566, 0.01920204289026664, 0.00956141114176485], [-0.7118224570246346, -0.06303825967507896, 1.0432882490903221, -0.1323040492170386, -0.25456414542916206], [0.35387137842980076, -0.4411662433448663, 0.3674936604936526, -0.2780091581534827, 0.15859532415572195], [0.4505055540874577, -0.22488113897918122, -0.054349172916966663, -0.03799723439072728, -0.21267080406468736], [0.508571818778195, -0.6248835232904859, -0.07663016638081159, 0.12978253108676271, 0.47038638219276196], [0.23439975948312894, -0.33967457452473254, 0.1954125902975658, 0.25363201885806247, 0.6335296316913089], [0.07200693816025511, 0.13969755899884204, 0.59873699179471, -0.17466890762773965, 0.618102041346429], [-0.34490642290605816, 0.1427565598931272, 0.19718449669151866, 0.15410547047706794, 0.8410291771051053], [-0.44247076992674045, 0.8154498088025681, 0.09399813254118175, -0.47860925273554056, 0.5303992978442562], [-0.21326878428228865, 0.08662801126088286, 0.34078083350020244, -0.24078116596537422, 0.3610121123173559], [-0.8142103437957332, 0.3437298873923962, 0.8673786802929596, -0.7498013473716829, 0.2569238656180128], [-0.650375004450279, 0.21086835293950523, 0.7871562998411893, -0.6302935608746397, -0.08050196004569019], [0.3448571222328005, -0.43068359122050853, -0.28809006431927753, 0.3025814803282036, -0.10043986282948374], [0.2102134150843537, -0.7079152818128787, 0.3484927112876746, -0.22394993074601743, 0.4242513005041406], [0.39352577769767505, -0.020204547982433183, -0.04848118698884895, -0.1585065769685565, 0.2663364446800994], [0.16157341067090392, -0.2564586001164241, -0.21408004647042617, -0.09822204017116107, 0.2701700562151102], [-0.5467121952403703, 0.18336639622231815, 0.09637631310297524, -0.30882484269030025, 0.5525588356448765], [-0.6121456026305468, -0.19009244731204183, -0.2598599187524296, 0.06239188844613583, 0.827717343746915], [-0.3840410768609246, -0.11360360169074737, 0.341238290441582, -0.21766841465143316, 0.10390758537712548], [-0.14265921029065934, -0.21996766487366168, -0.29809309161395114, 0.018246700611797763, 0.06965494803361844], [0.02521104306521053, 0.3140443868035862, 0.19714507188786326, -0.22300360647733936, -0.49574618985269675], [-0.3683722599652668, 0.049975763368911776, 1.07153603829745, -0.028178478300619775, 0.1810907594594363], [-0.00854883043697318, -0.34323989593423637, 0.7369168218552038, 0.03166577576901619, 0.7346651905894616], [0.38348495063178156, -0.28616684177828894, -0.35925779787644335, 0.11575314036967334, 0.04203183439589983], [-0.1339564207590124, 0.17503005349237333, -0.030584488934962538, -0.015590428022620352, -0.0728411468376555], [0.26502613194052593, 0.43378862247808897, -0.5518951885415061, -0.38676275622054446, -0.23757906706061574], [0.17930152072672678, 0.1344688901957789, 0.43333907741108696, 0.19359623152108596, 0.5673497420685023], [0.1851998022444097, -0.05822187788953556, 0.3990750339973413, 0.0026540777328995717, 0.002530267707197925], [-0.09596454438348918, 0.11814350753510128, -0.14209265099352386, 0.0957983736332406, 0.59920765822586], [0.20413042129956974, 0.3587762393300667, 0.24198511658724076, 0.19492241737037244, -0.27140565496533603], [-0.04651029298873487, 0.3910548701841437, 0.0720006286062369, -0.16307500656402776, -0.08922568286703729], [0.05199471033545572, -0.16900757285823573, 0.2379773220262207, -0.10201551390269169, -0.29273063643340175], [-0.3077016464487775, -0.26226278698080013, 0.44041758958767263, 0.07732961535240669, -0.06899872967677044], [0.1950125145437061, 0.14232327433488445, 0.14663575352684077, 0.2189057296788823, 0.21326058720827887], [0.361244458440933, 0.1514971932043906, -0.049518928698720134, -0.07833893358591369, 0.05107232237647873], [0.7733215338099727, 0.03200982645038955, -0.31799624886357725, 0.024904196655685884, -0.4232697102987026], [0.210034578522497, 0.09731737539912375, 0.22613817160128907, -0.3571307773453109, -0.06852089899866079], [0.15825412657342136, -0.06399775928217033, -0.03248660180946242, -0.07525254451610326, 0.5381841248429825], [0.5842682452869509, -0.19434001417975813, 0.1815698208905538, 0.11190169613799769, -0.35877859843601734], [0.1894244354107453, -0.1740487827569519, -0.5355469357890558, 0.0647452413806824, -0.05479565551548235], [0.01161584388701995, 0.046942036258882366, -0.34024567312341636, 0.0702671416986719, -0.4519537115964001], [0.055875775785576474, 0.45013807254725496, -0.305560146549869, 0.06535709985846372, -0.2146634794679027], [0.5585622166081564, 0.3225360078197694, 0.36367309399337144, 0.20539298638244083, 0.6422509578149155], [0.15755330962616565, 0.20166385335492015, 0.4522368590693717, 0.3162223128679975, -0.1805951538705673], [0.7263536871454603, 0.1516878174752936, 0.5666819496690012, 0.5213074539159189, -0.5046011833458367], [0.1359301418435532, 0.3776399877970692, 0.07411021387930983, 0.5814842536843647, -0.5444435653397385], [0.6522140369399081, -0.5431399925305778, 0.18713808898454987, 0.48968088637304946, -0.3834984575593205], [0.581806688257017, -0.5260973326670947, 0.002464375112269029, -0.06290739029271576, -0.3620928426604082], [0.3029599522178185, 0.1880940499357068, 0.17990303132234117, -0.41262537425407975, 0.15990224122194818], [0.09164785810758058, 0.10397793300692007, -0.2794799227628356, -0.19841124361956516, -0.26049695312520366], [0.1264211831696343, 0.1203988649972217, 0.544146917622651, 0.11649510349602941, 0.017608145003222764], [-0.08366729436986028, 0.4512178628560228, 0.3974388514056285, -0.29968809238135896, 0.22481924510500848], [0.39900464188381973, 0.33127117130736217, 0.8728365551535949, 0.4417678139762049, 0.11626146106582608], [0.37426669436038673, 0.44341572705837, 0.44434846771124625, 0.5835194792242945, -0.0013370905325560062], [0.7680422925440018, 0.2584502175193192, 0.6152452253955994, 1.0240544355994348, -0.09380891648767775], [0.7644672282326628, -0.7331665450298718, 0.3506186655065815, 0.4399144179672682, -0.5418169102652824], [0.7192066220533456, -0.2485212712910907, 0.4495532664953817, 0.5786925609371487, -0.31554905823803986], [0.6014440417301712, -0.11759846962864244, -0.16859205790596346, -0.193524305059987, -0.22685649114990747], [0.43559049057590193, -0.7131894416143947, -0.1746697470814821, -0.0415368222942792, -0.35600794028678834], [0.2449319434983259, 0.2998537592462962, -0.12417412889965157, -0.42192117857572264, 0.26375342288799236], [-0.20717489002737818, 0.17132940581656875, -0.2725762188207153, -0.6621693485615705, 0.3301103602447768], [-0.25029117210352575, -0.09668583772332419, 0.21124404550315645, 0.14458601590031697, 0.13252355042918104]], [[0.07956574367628223, 0.08918256757140108, 0.10083925361557573, 0.14665987257849133, 0.19275528716952245], [0.3730740251847221, 0.4919759080473981, 0.20788194879682295, 0.1536819792902454, 0.2391333891170376], [0.15522996129024033, 0.5742297537942486, 0.3311705894019001, 0.08436374206483212, 0.5310944543068306], [0.08679195295680964, 0.4914338740690735, 0.41212004604117874, 0.06800879272580168, 0.1212039402253526], [0.160138561929755, 0.3442628682783121, 0.17737745600643118, 0.1256461568344857, 0.24658195835674218], [0.11492126950892823, 0.3439501965690604, 0.07245271114461646, 0.27331748524641936, 0.10028832405310942], [0.04956583663161823, 0.7193265170996054, 0.03477537332922678, 0.22276341395539778, 0.4048906634240463], [0.15368051103198527, 0.2227402048773803, 0.04230019868716487, 0.2137778167112825, 0.17185104730538645], [0.3451452114851388, 0.43359558630395423, 0.1589442085037365, 0.13810897267080888, 0.36844662672799466], [0.36687942876337765, 0.05524999756628801, 0.2105097677364776, 0.18078965564140126, 0.1276912372620002], [0.2686876504932274, 0.5496437478960539, 0.20818832453857347, 0.15801964294144888, 0.2192174168877028], [0.19073604127939228, 0.5479479224848814, 0.23716876751465335, 0.18489652084117364, 0.3082438868636775], [0.24580425766270825, 0.18598827395515008, 0.4967165094441669, 0.28879508860036135, 0.45564542334537866], [0.23334634595315326, 0.39016297604671835, 0.5430367861433686, 0.21508151700381387, 0.2664339066232763], [0.03342536561409744, 0.5998250928492053, 0.07985672727047687, 0.3077146661259854, 0.3575627832359578], [0.2580066908149641, 0.2917375196070118, 0.19925329234698577, 0.37082557362978874, 0.2263465761945532], [0.24551224367744443, 0.5634855210412897, 0.15136158896632132, 0.13613997408854095, 0.4039753277710241], [0.39489975640475744, 0.30090223262172766, 0.12460237430698647, 0.15730027702287727, 0.3525207110434491], [0.4459110353964647, 0.2476253813216764, 0.3380310026400403, 0.14594245182729845, 0.31216470802891105], [0.29455246949540337, 0.2565178570631568, 0.20479946931501056, 0.10875615354178458, 0.2460117824312482], [0.21305458159458954, 0.25412463248282524, 0.25808207818491774, 0.3212369101140454, 0.23748903993421602], [0.31130855738985014, 0.11819680557178354, 0.3298519399028577, 0.20730578766419633, 0.07126974449256189], [0.4732276126416683, 0.39045810111141765, 0.3917678722327368, 0.0053476224821959375, 0.42846938189765904], [0.4873671014461543, 0.3189530574307101, 0.4878865885119839, 0.17425926190673882, 0.5175452281275268], [0.25606129239091197, 0.39772844716464706, 0.09483620277770344, 0.2671636481512836, 0.6140245629392767], [0.39757462523112275, 0.16594658333560766, 0.18837358173492164, 0.04189257977026545, 0.5181249706003889], [0.15710673170908204, 0.24053716749024004, 0.04060639846718984, 0.3364421046373327, 0.473073925029692], [0.5220068213327492, 0.2686688784887866, 0.2505356440630097, 0.3556944693255581, 0.5992916114154143], [0.5058451410084769, 0.13177540235133856, 0.3030457419100463, 0.292931322286685, 0.17861168976107628], [0.14618344705317043, 0.08795581243252693, 0.15193970457129094, 0.21749599786010024, 0.174688798059597], [0.31395085840169673, 0.1033369652266331, 0.2652434474001178, 0.16669732100889292, 0.2118419788624617], [0.20454354905469713, 0.31853382599144564, 0.2746546792919453, 0.21977261222722738, 0.1743483228309104], [0.19432653188197782, 0.33233361500412256, 0.3069027137970188, 0.08631018385440845, 0.20745089171450165], [0.2732617064648384, 0.17773217718094111, 0.2226756515955083, 0.1336037672928354, 0.43055264723088016], [0.4573644128418094, 0.47862169139875976, 0.20369522858393596, 0.043440024730620724, 0.3573947361938091], [0.358190686299719, 0.16515229377888685, 0.15280652524021274, 0.3393212225720676, 0.17714410029745337], [0.528965804304834, 0.08840142105257694, 0.04492777745699705, 0.21516189925045184, 0.40915230955852716], [0.4431148371376338, 0.09635006150777375, 0.3281006642530119, 0.19429306369501, 0.33176061725338085], [0.3941817981155904, 0.06644668904055152, 0.32223243872555474, 0.25605561646111247, 0.08899249267930004], [0.18120657048265634, 0.24482107292534117, 0.24076602214420056, 0.40549844689401443, 0.1188051714690599], [0.0436797077307465, 0.1384978786638334, 0.19838118488670847, 0.22764102893491917, 0.18247534388390005], [0.16315948148528306, 0.21266639925843675, 0.16468826401373335, 0.2783281054331597, 0.24407215038882035], [0.19578763890475792, 0.19639926209733208, 0.07365637416219747, 0.09583944390019881, 0.11577177983392], [0.35503541208893574, 0.41333397361380386, 0.044581158945291244, 0.16636538673450693, 0.2276640579528952], [0.4483145712124876, 0.12952818712203257, 0.09440835012499586, 0.097484599560036, 0.3277610581556913], [0.1462115542861219, 0.09706219058756733, 0.05008726877563696, 0.2165372830468471, 0.29225077410388256], [0.2934727156541024, 0.06871053903924197, 0.11047586297510595, 0.1356280471275953, 0.30544218332727313], [0.2465781482282949, 0.07071727012072275, 0.41005124717809516, 0.07800846475395586, 0.19448970739221846], [0.09360648644597995, 0.05230038675776285, 0.3238693499028324, 0.06650853041158124, 0.11407212598400525], [0.23525593091304767, 0.14533888337204104, 0.16679682514708996, 0.25385623829159676, 0.035929971985957224], [0.3322412131125504, 0.12018308956561773, 0.10730277755963918, 0.17749338480112692, 0.28038750930382506], [0.27838188322287866, 0.10719829853665136, 0.3142127455236365, 0.04117180383735652, 0.12748117593682776], [0.20051837519027216, 0.34200743515630894, 0.18417176857307027, 0.18921882750436161, 0.08426534457126689], [0.2007162953130653, 0.3081650068779611, 0.16225856735611263, 0.19450861530802785, 0.17149608874243022], [0.46213601699283524, 0.016519675106129523, 0.12897084504566408, 0.21338955805603987, 0.18782397067761347], [0.3024662035125397, 0.10624379870809762, 0.18406521660031214, 0.07468305280433654, 0.03201384007840386], [0.3246096271452875, 0.13018165071788226, 0.23463391240792458, 0.23237971246838215, 0.27402258666977636], [0.45752031235018153, 0.0785066728760352, 0.6307851918404375, 0.3607784572165385, 0.17440135338469795], [0.4329270473158352, 0.08504150839991692, 0.6713492678861523, 0.3781647182041589, 0.13177002319759568], [0.3751312192780522, 0.13570586888872488, 0.48672853563501384, 0.1934810832191446, 0.13318245634597398], [0.19925246790203346, 0.015049139610927258, 0.22691224616716946, 0.10873528760729123, 0.2092629501728494], [0.12657598928290886, 0.2406691251699662, 0.23066799330659074, 0.205719483566131, 0.13712767188438393], [0.20468965899708366, 0.4394594186258909, 0.10040057277929927, 0.2229529091768406, 0.47423115639289654], [0.15991057868520964, 0.10759217143397272, 0.1889304307211806, 0.1332680801303548, 0.4648703391207225], [0.2521066250931956, 0.27445993110398914, 0.38664780206970534, 0.17417127217497355, 0.39440540716107647], [0.28761495483835436, 0.14766552872970068, 0.11447857245222391, 0.15188563605380495, 0.09484162830066047], [0.3453159679568052, 0.21316230862917976, 0.5032356247627823, 0.15525456427064457, 0.4900966281689254], [0.2777432291835836, 0.08286562124875389, 0.14128087850792478, 0.1372584378593298, 0.3502410003603378], [0.25821499965348477, 0.12843848012814038, 0.4516881217642804, 0.31579634159845327, 0.2800843992664417], [0.19631660581557148, 0.14973911603983103, 0.3592961949453486, 0.41086640946474573, 0.12771008223938482], [0.04727706218033352, 0.36468961325598104, 0.2984392068661507, 0.09855213771695884, 0.09201009592065018], [0.2532979851833475, 0.5197066694617266, 0.37214761273140323, 0.2723582387433586, 0.4919577629291638], [0.206006028938773, 0.20897333739227966, 0.27405880452505343, 0.4108191012087884, 0.32793599669663526], [0.14118448747773055, 0.19439316435399395, 0.17745637208665294, 0.4360747722503115, 0.20527126320756878], [0.2531694478932376, 0.1981570224974053, 0.34395730354682597, 0.2336416586703091, 0.46379377536611877], [0.3268852165269771, 0.1658583519373259, 0.20996892329424754, 0.10841707431485158, 0.36873161839535146], [0.12432340343443052, 0.21711156650017263, 0.21135629808002418, 0.1568816274821562, 0.3922157222181399], [0.28863140567754947, 0.16791754804627118, 0.258678438126495, 0.3360323488690937, 0.17018401315457926], [0.4011347818685714, 0.11582421194995056, 0.1623600804403578, 0.2316048429310051, 0.23822345689062432], [0.12507309301922606, 0.14795611582167803, 0.10201307451724274, 0.10633605543487507, 0.18160162746853448], [0.15759228792436902, 0.4631272465526036, 0.10564563162096885, 0.096996123995596, 0.3279956952479913], [0.3572446571782517, 0.29002456975463314, 0.27171119401266003, 0.22930518488050133, 0.24265918997609992], [0.21284914637478788, 0.2788927549781025, 0.4033202679065013, 0.3949521755088106, 0.30744109375800366], [0.11038493219579916, 0.4293529250401813, 0.46946638378319333, 0.5377271154929837, 0.09780757406709188], [0.07280519235486636, 0.4380925850585228, 0.2204602986657953, 0.3193612660043352, 0.26767208051252084], [0.12512958943010755, 0.18654026739140644, 0.29833538181583397, 0.1713756585068339, 0.29526396968416585], [0.302356269791621, 0.02566725360176855, 0.34474628656511963, 0.24175268667775132, 0.02871865198875202], [0.35450351273862396, 0.2226073428453231, 0.10381435823578615, 0.12404889527835593, 0.28641419826268466], [0.06701743933314311, 0.03378004130704939, 0.2175981793617086, 0.17354669494141928, 0.34920955374636026], [0.19066195109396805, 0.18583362579017362, 0.23118384880598913, 0.16609201149295041, 0.3308673507667759], [0.27519475782221764, 0.1553666367636061, 0.06280766766926996, 0.1251012874073749, 0.17368211680942228], [0.25850380749147805, 0.20215837378031093, 0.08781741009090817, 0.30418742524996056, 0.20272676894543099], [0.05337228476908619, 0.4919662564488951, 0.20887451612580554, 0.29443046192242767, 0.1908801225095977], [0.10542511533833027, 0.4436482553004334, 0.12254493291374632, 0.19658897506296807, 0.13035410205476888], [0.07074777418356037, 0.12659168032419732, 0.37310987825187636, 0.5281962893779497, 0.042940841951381724], [0.06370950934815388, 0.3478976440139796, 0.3584991387197853, 0.3663987705660039, 0.21284111729075694], [0.2515543175031627, 0.24618335308421002, 0.03528170361178249, 0.13473918919616792, 0.2560929792758111], [0.2911565154460602, 0.17832706789379493, 0.36073790345171025, 0.1811131790907054, 0.23351750197897553], [0.19778516453849124, 0.21919981977815528, 0.1938532357730349, 0.09557656512502294, 0.14227102767635022], [0.12552619271466056, 0.03827311169032459, 0.08432218434536684, 0.04028267427248485, 0.13010874691843233]]], "banksy": {"0.2": [[1.889629472376613, -2.096712040948963, 0.1910769474609975, -0.578034845583783, -0.433282984516432, -0.3339914391399905, -0.52619395504403, -0.6175431129396974, 0.15260399627478505, 0.49119735473808473, -0.35608860969211203, -0.2550654845011909, -0.2568812484409306, -0.14660905798948315, -0.12639611573063447], [-0.27962354881157414, -1.6478964560336102, -0.36812949189493194, -0.8832033046372854, 2.7501563599118573, -0.019465326096073137, -0.6088539844948481, -0.604998492905506, 0.048138339511121224, -0.41943373400721895, 0.2563944972554717, 0.41708244037627534, -0.05343852170016007, -0.12971640460938139, -0.03672996955188784], [0.14469117777298587, -0.25091207448457825, -0.4105884622205922, -0.6809159012808268, -0.9412820888880763, -0.5346843230860431, -0.12411700006457471, -0.6198797168769834, -0.10154196079957913, 0.10476077389696047, -0.19819509183025727, 0.5543407964022269, 0.18088085131628012, -0.29647105566139786, 0.527739520368951], [-0.4480519380823953, 0.44833293245204575, -0.3738255780440771, 0.9871133928249846, -0.22009482859091667, -0.3006761548662832, 0.2671970319719044, 0.20924228482003773, -0.9132036234051784, -0.4424530306382758, -0.3410092017488523, 0.41617793929064817, 0.334731407479815, -0.3358151587310525, -0.2647315211261089], [-0.04904248196657677, 1.3396950640199994, 0.30033777736636863, -0.5138697083455642, -0.2057923401771338, -0.264056149081475, 0.6338043628079277, 0.20254314091424458, -0.484477022569786, -0.037865307061993037, -0.18795199083493355, 0.17059124208385887, -0.11141461414265204, -0.19716047095751582, -0.022329110736542337], [0.4472582307546543, 1.6658404053216926, -0.4005515408165304, -0.24540374439707113, 0.7934693841752831, -0.18576875030746393, 0.5544362917757673, 0.4123511903883635, 0.003088314699314981, -0.35788750083865845, -0.28230989994513717, 0.170069481619068, -0.31083201634019003, 0.15808342769563405, -0.3051691979254155], [-0.9245429418085324, -0.19987849941402358, 0.5906237637844483, 0.5999029177799755, 0.02553072602156929, 0.3772613051899163, 0.149241415898546, 0.029054934357426277, -0.011252742857841351, -0.4166694716047989, -0.4186913961634919, 0.7964661707862262, -0.3824406424918126, 0.03646858498145099, 0.28374058366356475], [0.5718264082899639, -2.3250223656787896, 0.710002452700768, -0.9800875002641435, -1.458528892794867, -0.1204781662107082, 0.16194324846650782, -0.11106707421142474, 0.48974443192679307, -0.3464070035809273, -0.20142843197098345, -0.0321956409713405, -0.36813914357612376, 0.014852482309020788, -0.16681179788887399], [0.19339125004950553, 0.6314853034727014, -0.5512264596988413, -1.099881015760463, -0.029604447165036622, -0.3692360787983842, -0.40612236040102667, 0.43328764640268436, 0.3254083287586246, -0.553336833625841, 0.19811359799032058, 0.319662229637034, -0.14644839321824357, -0.16717943582020425, 0.21328068589910157], [-0.12307137054583449, 1.2222102681479052, 0.47437378789608786, 0.2033297538664492, 0.8856422386842447, -0.5886426721053315, -0.33304652882826774, 0.2794575126459428, 0.1388297854173702, -0.5232490408262573, 0.24346782396730307, -0.3116893266127395, -0.04844415333565688, -0.0645051226769153, -0.25218915953806287], [-0.26993901845365964, -0.7312221286186515, 0.3338479369596541, 0.6021481558671962, -0.23276466406923296, 0.10224942481533021, -0.6215916075038157, -0.6482689031017816, 0.07224113764938025, 0.3701225127129974, 0.038564558129195854, 0.5133137207659516, -0.05285623146350811, -0.11928155200074832, -0.0752349622578921], [-0.8248999484696352, 0.23653299600309, -2.3140416467130978, 0.71252866308892, 0.36266567803452315, -0.08546577193090164, -0.5682456251164942, -0.3296147580112628, 0.051736336721715, 0.28386879661661424, -0.12410221078608175, 0.5104838687884412, 0.002223289200896791, -0.05462548781143665, 0.09688636516679003], [-1.6478436828872272, 0.0959423692402126, -0.9979956361808782, 0.7813675141027613, -1.7667403108496873, -0.04666436967635048, 0.06376539005262429, -0.615072106987787, -0.3736228822959422, 0.03332815884789709, -0.009187728335455102, -0.09352419738546794, 0.49551337544305085, 0.19531695309552535, 0.38186843994202146], [-0.9514933919160063, 0.6390553136947503, 0.8262208142575929, -2.209571084866336, -0.47155404161453224, -0.1782205907415859, -0.19490154972346704, -0.05052369076030591, 0.22100941488457937, -0.5221454186394533, -0.03518447510775193, 0.2471855128623372, 0.5835485597133687, 0.01798871450503774, 0.016052099801448144], [0.24297111725124132, -0.46589067566974923, 1.199786480320258, -1.217683901988366, 0.24729210139724886, -0.4749255934828439, 0.61761910923526, 0.16896245020991732, -0.1367254230904515, -0.08348318380573068, -0.45237278254755653, 0.5970521630102096, -0.2967601244943505, 0.24083062560969543, 0.1922381623683199], [-1.0802258106123699, 1.2225158946237187, -0.18722960900100452, -0.3774379228403823, -1.5003197266279042, 0.2760351201200402, 0.48230103954853815, 0.28077549600716817, 0.2742519096730095, 0.5965488194198524, 0.016275894465930623, 0.08294132197555026, -0.06983793497438551, 0.3926526825404004, -0.06145164181793456], [1.544422645961251, 0.6752490242779373, 0.47966951962009596, 1.1719139628805937, 0.242818878752584, -0.11285357382820213, -0.12356106573782102, -0.14050253195248266, 0.24885608018680017, -0.34011928308980327, -0.009797093195783205, 0.5364117170863484, -0.16085973433701464, -0.171916135491898, 0.28197089889812543], [-0.686889762757364, -0.6259399827121501, -0.8569966266474134, 1.4101353458943573, -1.282952424263524, 0.3091869359400303, -0.4367768482192238, 0.286377575744979, 0.07969577253253603, -0.46872399022398836, 0.30193969141608595, 0.09823463051848501, -0.21171764282407982, -0.12101208667000189, 0.18248995872753895], [-0.6456707931608097, -0.22461475601698525, 0.0246308477307216, 0.5947724173739835, -1.104808098862613, -0.5216789285906192, -0.15533942860833272, 0.3543555180761113, 0.20882494072157853, -0.41802350291532436, 0.40838829479327027, 0.009330665514950548, 0.1939195848176414, -0.14833491328833637, 0.1044667729234596], [-1.7354748232203652, 0.040839232489063876, 0.8753965949120729, 0.7812002956993853, 0.13019441049070593, -0.5897604306189098, 0.14550740718677885, 0.35584368272591593, 0.24955109287294538, -0.1895537418033907, 0.09253838340483499, 0.024169687206808465, -0.059297006763905494, -0.23779172065567192, -0.023431473182094847], [-0.37725459322068516, 0.29022189167772006, -0.3779389711252107, 0.8429109512356443, -0.7214701028293625, 0.13903413638984874, -0.2588565729906388, -0.31483149194415405, -0.2778008229355288, 0.21274229566354774, -0.07752863935384313, 0.020176073674035958, 0.04197061563668343, 0.2733602623680071, -0.03990910901651361], [0.05668477450719114, -0.04827884738422213, 0.29883562044061646, 0.23495314096064998, 2.098430805824315, -0.027698640095660636, 0.15846597859187098, -0.982548594557034, 0.12205775330199149, -0.3995654337204525, 0.12750441816587613, -0.2066489445434749, 0.178374658350508, -0.0007168828183096303, -0.3612729211808484], [1.3683353800825677, 1.298570571314434, -1.9231403315357474, -0.3446746181279441, -0.5647818181077958, -0.0656958977356458, -0.5942639202972338, -0.13735636110346858, 0.28531897758290525, -0.08591936929601407, 0.46539159983233047, 0.2476779929504701, 0.29605056403056584, -0.48655531019371356, 0.3293270291751787], [0.43975647453325695, -1.8649319789532655, 0.8417897764494772, 1.0991747040984863, -1.1494730145241718, 0.1783143354833385, -0.06145559229913058, -0.037181525983153135, -0.4326609698925975, 0.16181612035469506, 0.494897404537787, 0.12835634112905867, 0.4787314438193466, -0.08021489216967835, 0.5015438192905148], [-1.0130703074660434, -0.626719834694337, -0.1313571345993529, 0.662098372759617, 1.675044089972989, 0.13623028050885297, -0.1434568163383132, 0.6587815014242441, -0.01329706553379465, 0.17396117663849273, 0.012216303149151682, 0.2598101399394058, -0.26829049994709186, 0.1432795175198267, 0.688074310517789], [-0.2621737735277195, 0.6875854173641532, -0.03490131587994299, 1.8101142960209269, 0.5741189995000713, 0.10196497452446836, 0.23517073975998182, 0.1965683090374031, -0.26379021269275116, 0.7586248569568479, 0.3075215167772976, -0.12696809877927556, -0.09051564669792767, -0.39864133770670557, 0.5026646774355185], [1.2432624242447163, -0.8583864833393697, -0.3339836932779541, -0.8304266703469667, 1.2172652149072478, 0.3424936521182391, 0.6198418322373707, -0.06275011485307881, 0.639825319023095, 0.0837653965124274, -0.1942787111024227, -0.0024975544160381726, -0.37135833882080965, 0.30993847047597717, 0.41556422554080874], [0.5598439784717281, -0.2111258850409034, -0.5578509581172791, 0.5017327138802996, -0.6430977594354257, 0.14178905267310435, 0.02059186813177001, 0.14900448837853641, 0.08466027759059475, 0.00989202634711677, 0.5671823947632691, 0.044446298102924886, 0.027628047633037677, 0.3562527087488193, 0.6595900274292309], [-0.9669653351245193, 0.4477708257776466, 1.950370475351393, -0.24804549219289856, -0.5203099956901395, -0.5567493410716398, -0.22048734648270413, -0.0685228523531494, 0.4125170848161275, -0.37913394270678236, 0.5334567495186756, -0.1839901149875041, 0.12742745448968887, 0.2052672379360006, -0.1537409577889461], [-1.1982301271750624, -1.0739938232341926, 0.2830270503253757, 0.8773799465331469, -0.043895939366930065, -0.9549967333122288, 0.3208694608383518, 0.7851230411646724, 0.1256341412357761, -0.19688499443647287, -0.21707305029360915, -0.2571125911389337, -0.1597609819667827, 0.023797083684313377, -0.16132536866342084], [0.24735082925247742, 0.1416577316178344, -0.04932209609308926, -1.5613148967586583, -0.4378941573177935, 0.37467559992748867, -0.30685452479025305, -0.004691123487991105, -0.0017222085208298352, -0.09450125970245728, 0.1330182821185701, -0.23144580647818339, 0.05558133870256668, -0.09840619169155891, -0.08949443119545149], [0.034804327053114856, -0.6116342528300678, -0.5784647749820819, -0.8359133169883031, -0.33281942154597915, 0.48726948156499184, -0.2192561627194857, -0.10823502272400874, -0.15108599246520077, 0.2989101105125629, -0.09528917280991664, 0.12765676267621728, 0.0734680957093962, 0.029273795868089352, -0.16198363410214456], [0.7477532597772212, -0.2961134097901965, -0.30097486571251486, 0.8393321366006934, 0.49200657776843265, 0.5680157742452298, -0.7057193052600458, -0.1860414569476439, -0.4139166269111186, -0.03101916568432088, -0.11660969701973864, 0.15068469937858783, 0.13475792086405985, -0.291788619488672, -0.09798403826342027], [1.5572871549686051, -1.7069636078198427, 0.5685318493520739, -0.49032915750795, 0.061933836707424875, 0.16647281590422164, -0.2787902718358868, -0.08801545012609492, 0.31945939294562564, 0.2650138353055872, 0.048109542681067465, -0.10730128294456445, -0.025321972216226847, -0.1780173333316287, 0.33335475704789574], [0.7329594844741526, 0.9521352964267659, 0.7255251683600896, 0.1636154774025675, 1.3055559315624161, -0.4473207755990994, -0.6350725616846876, -0.0016677619061379284, 0.23182098579233154, 0.7985727123500508, 0.43228881360219656, 0.39479803766460425, -0.0613956996726337, -0.39491874384519227, 0.191913264840964], [-0.3443950290444005, -0.0735832380118728, 0.5190592916425203, -0.5612117911426014, 1.7703371058927908, -0.2759240413548116, 0.43480081648261176, -0.12045886487120933, 0.16747869296139317, 0.802896904742844, 0.22533645148180126, -0.1282935429305389, -0.15811352381765717, 0.3168645887063511, -0.156578354876143], [0.9074282517588301, 1.8673313407045975, -0.19147761719413398, -0.3885573855227652, 0.08921496170772397, -0.05757382585984965, -0.4646871401470975, -0.02216479796690125, -0.3177472544956897, 0.7740223422418075, 0.5817041639277799, -0.25636899664722695, -0.3631452316725073, 0.01818208516801788, 0.2919799330377348], [0.6338053101536539, -0.44763534327854765, 0.15804483357221286, -0.01276024126116691, 1.3106309184815603, -0.09796621586286978, 0.40046511578102884, 0.07224154662870858, -0.521492288996497, -0.33764323890471143, 0.4025532832957806, -0.2431049685447663, 0.17504622671044062, -0.03202079837608062, 0.1423529646226199], [-0.7094379125550813, 0.9210584869404029, -0.7225040933457368, -0.9811026304168695, -0.6505207678077297, -0.48569331729123183, -0.13907076123339648, 0.9342418319553527, 0.01082677112442256, -0.03939676992314419, 0.30044148045812646, -0.29300522192762757, 0.1638932208895929, 0.11655760388625076, -0.32700824749067553], [-1.216523270621738, 0.1671565068455061, 0.7185656242987949, 0.17306281331281936, 0.4747682843477851, -0.7270703700483218, -0.019813783329469967, 0.7967225273073663, -0.17402981075395876, -0.28377909300577664, -0.14398798658482442, 0.004651069603345557, 0.009060143312023055, 0.47606309679177455, -0.2693692346356906], [1.496691397296377, 0.2707778276644771, -0.000710021736838176, -0.2777247011624118, -1.4076215382546688, 0.27805751770968934, -0.412084833681518, 0.18006470886628, -0.35180845995264354, 0.09849694378367549, -0.43097436991323335, -0.1727722073176761, -0.07149544106977448, 0.04820236553376404, -0.14627107521907962], [0.6579946661411719, -1.427102931379676, 0.39287848213729765, -0.010211786879761535, 0.89841448616847, 0.36919974039374853, -0.1877100486110721, -0.2048639155492856, -0.05896357682138426, -0.2450172548207057, -0.18164803857266895, -0.049005967414151606, -0.13553138189369288, 0.1701371707542898, -0.027181504402564692], [-0.13751336009309917, -0.6451759951285496, 0.13929814017474582, -0.5703057212624445, -0.2042054049345788, 0.42396595939295173, -0.6026736646711448, -0.22519516568647027, 0.14574894346828512, 0.386981799504263, -0.11356070854044915, -0.07615120887621889, -0.30854436386694956, -0.26886466040771145, -0.27523391055713403], [-0.03211231561790189, -0.06819405395338575, -0.3310256878942373, -0.8495841873224838, -0.21109981055569085, 0.16537575864922555, -0.3067970865444973, 0.02304194021333598, 0.29686097241940973, 0.537930184905954, 0.21875213249100456, 0.2858513406380708, -0.3638040063328506, -0.09920470570912465, -0.05890445883780711], [-2.1280112842030237, -0.08728214707369077, -1.1992627093675632, 1.1538388434289855, 1.0191074827802542, 0.012212112531556747, 0.19050493406186506, 0.39107262549561145, -0.22572029269192023, 0.5236557980688873, 0.4134039116497751, -0.18774008029563474, -0.2691036662277308, -0.2649070098822041, 0.13462032711387031], [-1.9479402356090065, 0.16595539845562535, -0.2773114544182573, -1.0694197128571536, 0.3966318874291791, -0.3810070579706202, 0.19367835032739325, 0.024658792360148462, 0.17542600380551804, 0.7299192586069554, -0.21701439707511275, -0.2419166269434317, -0.3533392287436561, 0.021490761992627113, 0.06596572101891579], [-0.5161991258965153, -1.4364353856246963, -0.39801916681202, -0.14762297581006736, 0.03810573483223161, -0.473026588138561, 0.8915322482416992, -0.06949804062359505, -0.5965659300526278, 0.4425087842166866, 0.09028518978433538, -0.289227497904049, -0.23856614453478459, -0.1731476469260248, 0.09146962864037847], [-1.255983045994731, 0.5603825085223482, 0.46409271279818903, -1.171105416380382, -0.6071458642796391, -0.2568507034366364, 0.13545043364949386, 0.15568944174201715, -0.3063856040768897, 0.28578319341465946, -0.007572799803926391, -0.28587883248021045, 0.3307994989916059, -0.3117595582652326, -0.12304283539588443], [-0.14959442441645657, -0.4296197108178963, 1.331507147297466, 0.2182642739771147, -0.9037041331814557, -0.8236393065837916, 0.40216865433972615, 0.6362062805544126, -0.9274545626454987, 0.18947548330803518, -0.3267888648561592, -0.31661139106843145, 0.16700429421200824, -0.3394242481815066, -0.2785199745433704], [-0.8299953247335624, -0.003613463112295654, 1.8064004675833685, -0.17841360882991383, 0.055850170544049255, -0.6691151242174816, 0.2643377189897154, 0.5630039215028751, -0.7816399580152895, -0.12272795589845234, -0.031199618110853627, -0.1613565093489239, -0.13152390220772894, 0.11126669410739454, -0.42959786494605234], [0.42180249357030397, 0.010918380476494334, 1.7933948662034143, -0.5408488661375208, 0.5758434643557084, 0.2695555634057716, -0.40121010042483335, -0.4181508382397082, 0.35658550234622655, -0.14117551191293717, 0.17118597272989924, -0.20333439951376994, -0.24459683301857965, -0.07243476018277742, 0.043029611280683416], [0.08186967502872619, 0.5650035944842342, -1.180841589855151, 1.8185133188319618, -0.15409755933779964, 0.14256398246234134, -0.688811048135999, 0.16272647609054922, -0.28584936973696845, 0.34429528864538406, 0.05879415353009775, -0.22500233556944907, 0.14865118826083581, -0.40037526436136167, -0.252595286324164], [-0.039521777522232016, -0.7388269812948459, -0.7963430964516224, 0.5833739222262582, 0.7801360458305878, 0.31545826194823984, 0.024622031531628043, -0.1995094195794522, -0.20600020646113887, 0.19818447749722107, -0.10368876883431818, 0.16682756344194583, -0.0985015099598241, -0.044227578571247955, -0.33614758557189245], [0.651761181488661, 1.057466663497556, 0.4460542884789409, 0.033681490084613706, 0.6536855130964044, 0.09668830666303113, -0.2204685969933958, -0.35061721645645233, -0.13244545194608473, 0.2017315287742175, -0.10327575584840586, 0.11035414232424612, -0.14014920389772903, -0.031502259021197666, -0.16749806500755532], [0.4982837200662236, -0.03972875424711861, 0.45601956223908946, 1.323569073364092, 0.14614726925761345, -0.5713437221564137, 0.23580711053411718, -0.0673279675542917, -0.3894074900146427, 0.4630119093078731, 0.4422460349811792, -0.37631925778455827, -0.2034150342503792, 0.013918472167326494, -0.1359301873473981], [-0.4147939388818323, 0.6467059939468351, 1.466542243219696, -0.21155014347027457, -0.1294624914243216, -0.6330583913895825, -0.15162016050440488, -0.3923910285678429, 0.06352384165316739, 0.717602477138329, 0.10905249460286291, -0.2265951252573325, -0.09870402003153725, -0.31975929875862874, -0.43716920662095127], [-0.20348670011015613, 1.0692359969949008, -1.7491016404799766, 0.3798273112203893, 0.9536260447249665, -0.4179175952742559, -0.07227041357246897, 0.1561068679899657, -0.278185126153704, 0.047897082034739906, 0.1552606384935215, -0.18664963475993077, -0.0025943943779076807, 0.059601927188786284, 0.030723844995403142], [-0.8542921707007805, 1.2920691018287713, 0.2919100686222257, -0.5588146187524378, 0.12048893771719088, -0.19025404161824885, -0.18261279653905163, -0.4272785304311318, 0.009661132794865605, 0.016204809638277032, 0.4326141393980093, -0.2728805269674357, 0.7503210320613418, 0.36848294801408304, -0.16188110628862526], [-1.5475146304484233, -0.4293228702216766, 1.4030384378413032, -0.9125368208600121, 1.5036195615466537, -0.03192425912397647, 0.37137283123458403, 0.024622817503550255, -0.2846947345191813, -0.5069329182821067, 0.38129374972856594, -0.26197573859233003, 0.8274161222446274, 0.410308014549777, -0.244303347040889], [-0.15078288997768063, 0.8779104306411373, -0.130840003290133, -2.2952152315326755, -0.5344627201445511, -0.4031392749855927, 0.09742728699208364, 0.8224984366771397, -0.04698345335658469, 0.11931085823273228, 0.2606873799755145, -0.1774312803161499, 0.4765304768631067, -0.033974130231212506, -0.24157258765592066], [0.11014775105047962, -0.9197791311545434, -1.3277490548384767, 0.38017663697598597, -0.5991860457251275, -0.06376547769474711, -0.3104957611587783, 0.5171607504902307, 0.0260341005813728, 0.6315059189268074, -0.10633042114144646, -0.37877316474436745, -0.017270004258072458, -0.23784191656030806, -0.09448065430013262], [-1.7026106316991638, -0.5286444155721759, 0.5718685417139103, -0.4815693975590422, 0.736522146072578, 0.3059880792706968, -0.25128801175268317, -0.48309089555785095, 0.12863131355832336, -0.009353492137599952, -0.2579892268074498, -0.0022773544482463416, -0.010131923161562716, -0.004532957734858237, -0.23394501648938043], [1.395846678441132, 0.07178051993063816, -1.1404433472974893, -1.330887946322795, -0.0737675523019651, -0.1820458525788361, 0.22715896477396144, -0.1831788082288558, -0.03162444095953811, -0.11563978407294825, -0.0949842755477034, 0.3294473038449677, -0.2577149945022558, 0.036924442066000984, 0.41780158481638147], [0.7746198896002761, 0.2699306673540742, 0.3021888058655673, -0.4503754699458094, 0.20166992519435162, 0.19426156058751565, 0.4955958433633568, -0.6588711623462824, -0.484501595430085, -0.26806363947929723, -0.18842773852162065, -0.22434507333594939, -0.08945731314274637, -0.1788248754429502, 0.39970363827192906], [-0.5254463557270954, -0.22827277161523885, -1.280292550855756, -1.6085649214868383, -0.4579935267581361, 0.11340888552117229, 0.18508069811028385, 0.24014818960998624, 0.22360972368658222, 0.4766972039807225, 0.003963837831985903, 0.05410992360766819, 0.2863194839852862, -0.08042656369515244, 0.26346867771404925], [-1.1371305083787207, -0.7587420895153154, 0.40868264042514535, -0.10538148415704858, 2.4054144460884173, 0.11897195349251204, -0.014817255107529377, 0.20888249050699817, -0.00936383793614821, -0.04590233942870335, 0.07806141359053831, -0.1574739976687937, -0.23095869286330742, -0.13403775785713046, -0.315699689623479], [0.8181549871558828, -0.48597504436637273, 0.5006976866560866, 0.37055100949303105, -0.6297638009560543, -0.14621314605200378, 0.1681446995059182, -0.28492922339006177, 0.10428397597096889, 0.506173759222798, 0.19846992679222056, -0.04817843522586294, 0.5079034464713538, -0.12593333293657832, 0.4484754513983752], [0.9875918843592635, -0.6050670834856544, -2.7996563970589716, 0.819168107062889, -0.5720738055715535, 0.13682669986697213, 0.417777782818593, 0.06553904354279379, 0.2252278380450527, -0.29936170938755513, 0.05746143198560931, -0.265606677553966, -0.18001888592291082, -0.16922551548657794, 0.17808242882067818], [1.3562060450971527, -0.4997865675811173, -1.1848945994536846, 1.5931576703561636, -0.9584383201431707, -0.09956949888868266, 0.45126372666799697, -0.08957060855557679, -0.21157426799110512, -0.13079958545481937, 0.016710586270761777, -0.1895584924218222, 0.4099335238256611, 0.2602722188652282, 0.042443586674695444], [0.12316422782798155, 1.2591835299876561, -0.07010422243800032, -0.07819734269455715, 0.03472674179372803, -0.006662772180800898, -0.1297466515187317, 0.061881959138062506, -0.13707396937203425, -0.3190926607521973, -0.11245687836794944, -0.15401376814784554, 0.23433568887718007, 0.4889764766059746, -0.25215272517732046], [0.7342421534616439, -0.6314454020383208, 0.35671639296447744, 0.5965432729806392, 1.9151951859092964, -0.34591671857772205, -0.22648987702570533, 0.24660728228441298, 0.08174975652245348, -0.11208458538554861, -0.423467532904236, 0.20467769006861536, 0.11867238672378294, -0.2623388985168863, -0.32117409641535627], [-0.3958754132085296, -0.7219474300171063, 0.46429052025776446, -0.4029914671269227, 0.19213676835660393, 0.12822698571512314, 0.19322885865162595, -0.02146658095720553, 0.25449051041556575, 0.14907600985417002, 0.0064499275796396395, 0.4633572216769948, 0.2587607790008247, 0.1557758269502401, 0.4520737181333688], [0.055085677364116785, 1.0234700462672535, -0.7336652743859806, -0.0901956803671875, -2.203446098651196, 0.28501156782362286, 0.20274590829143332, -0.20045635160541492, -0.10818554880061154, -0.0009887754355219196, -0.09223731949033193, -0.055168640974861856, 0.07233559071064556, 0.4888626700230347, 0.13495854847537253], [-0.9280555904416763, 1.3317505898856303, -0.7548869389670881, -0.7152146053490709, -1.0785103874495778, 0.6736693103942758, 0.07878937271451504, -0.44544002171375796, 0.01778411943800577, -0.4398740139026673, -0.22750470924556535, -0.07949881743819918, -0.11126462817194359, 0.5496186958567338, -0.10219807204469013], [0.4850472377248763, 0.19366573983869656, -1.1896369694892515, 0.6892653838301893, 0.16767673718231793, 0.14239530961307384, 0.14653961053983752, 0.05107881747870921, -0.4483468358888747, -0.11164247227588733, 0.006181700330989134, -0.07321800495595347, 0.2051829672831269, 0.06263771411834188, 0.3976222395311983], [0.6525097569719867, -0.4929223609452824, 1.3265641270526325, 0.42499286038996, -0.15018703661996438, 0.09355766547625095, -0.020809170962602132, -0.18491447287519971, -0.1044197640334362, 0.4497116998733328, 0.1600092610791302, -0.1271153319763141, -0.04947206904614571, -0.23860742284934325, 0.21383168094702001], [-0.5711339801815352, -0.1605895771856746, 0.5701948062274045, -0.27147163614426834, 0.8574056994915549, 0.49536037564678237, -0.15602659850581632, 0.010410510296980618, 0.12393206479505568, -0.3802035755709919, -0.26268984640173026, -0.041588243144591315, -0.04683525848236201, -0.12201920630936912, 0.25923520109611986], [0.4858565635799993, 1.1726911552798496, 0.5317509814837902, -0.06009341354741577, -1.661492111717091, 0.12295649057977089, -0.13497641706748162, -0.6439534964641334, 0.06639522968372674, -0.0989431828514155, 0.08018250865760132, -0.12367911729136502, 0.04310404274656713, 0.30895274604205875, -0.17003479584641001], [0.21466046715012768, 0.7056606323968356, -0.028471205539831266, 0.5753634293858533, -0.4492782246559912, -0.04474681038495578, 0.09428008982253491, -0.46574246517388324, 0.07313264600843615, -0.46641390259592286, 0.31495073065609547, -0.21060813085377486, -0.13995627061420385, 0.057737870852558874, -0.03848920748100057], [-0.4381277657906824, -0.745037739436195, 1.0030070330580458, 0.1669884323976597, -0.4668713871523869, -0.003002277028863557, 0.512556809566035, -0.43409216564612313, 0.06714177436204803, -0.24686097888326766, -0.2611254196544441, -0.15698909017097376, -0.2546503131628521, -0.24361360291180909, -0.1479602944956166], [-1.3527114296093443, -0.08390997489584384, 1.0724578154956566, 0.4783988111537308, -0.6625121738722917, 0.47111528249810547, 0.38018206313242375, 0.1765784687527496, 0.2380032556600869, 0.5459995969163586, -0.19326546889403165, 0.3689422006784095, -0.2477463640332803, -0.26608210572358776, 0.13507396801191612], [1.3018501073760784, 1.2414069459067771, 0.6751348993560262, 0.813783921725731, 0.9227565123175883, 0.09289667764422528, 0.2547889448287337, 0.25739228272261827, 0.37322904216834646, -0.21533924103592456, 0.22336231006200447, 0.0800828941591051, 0.06787377962528451, 0.0522057238866212, -0.029913283185904065], [0.4498864202903062, 0.6938677915905882, -0.8396408594495628, 1.5429837191401474, 0.14328803375990098, 0.629370759591162, 0.20294366245457146, 0.361822624562156, 0.6234588358410226, -0.5151260061030273, -0.07795733458879159, 0.06150705029504485, 0.31800676451934673, 0.45069257562545184, 0.09533426706570558], [1.8735682585491675, -1.6665484184473771, 0.4382429420142319, 1.0114318234482427, -0.3407753342467157, 0.07250240657226543, 0.43734708936108346, -0.0876456268018608, 0.6968821375634112, -0.5519901929512269, -0.2917761744823606, 0.3125824304501035, 0.4437224535206335, 0.7941575315880768, -0.3099654116887752], [0.36258363944250344, 0.6715187780243671, 0.3281040454290375, -0.5491944336495334, -0.17130652868319934, 0.5594446442932841, -0.5178726923668139, 0.015491515847008853, 0.5848704260206449, -0.40307563943810953, -0.3701962984317237, 0.32716644601133604, -0.02953241777676544, 0.2688481398511663, 0.018445951129675144], [0.9072676151665495, 1.1147331917098469, -0.08345614017117323, 0.08351357781219242, 0.11741694865624769, 0.4930387148322218, -0.5001925883434116, -0.15302195176801625, -0.0893571155236946, -0.38327008194521445, -0.261007524864252, -0.09260307678727919, 0.11847505937412425, -0.08715180080975068, 0.07179135044360832], [0.9251730695545238, -0.8385825875818768, -1.3119673732106572, 0.13202405187387656, -0.9846016466878617, 0.2300395104840245, 0.24071159200055967, 0.008889576515802041, -0.5160572583186731, 0.09970616955064492, 0.10882308865015669, -0.36105454189766806, 0.20668248909843662, 0.08214991897513665, -0.4435400326040318], [-0.6367688571960417, 0.11684007644931035, 0.246483973128021, -1.095454970899742, 0.6242422478043156, 0.030736791687518243, 0.1534492920275273, -0.41029414450723856, -0.2546889434980439, -0.2892684267377505, 0.2176421830034192, -0.032417350046859764, -0.2512268374112959, -0.20100290556191996, 0.054681445885094104], [-1.7774859966852183, 0.5015114721010163, -1.5258887618136288, -1.3035543236217582, 0.4898579909156161, 0.06353386492482435, 0.17048441377937412, 0.3412595660016265, 0.1295366023523927, -0.031951524791165836, -0.38227398474017077, -0.3475165985577114, -0.03497209167973349, -0.0819290710122051, 0.17608825831820385], [-0.4630114049304423, -0.6220164164949576, -0.551234463371156, 0.48159055419972596, -0.09720117904029914, -0.13461477837808336, 0.5136769871166873, 0.20738948537703394, -0.3782594998045138, 0.15977066471904924, -0.12425681966706369, -0.09378226134216643, -0.009151500824250189, -0.09986234783674797, 0.14062594777628293], [-0.10061038336819887, 0.9282762055185366, -0.7848973993967622, -0.47970993591712485, -0.492118589963939, 0.3206257490852789, 0.38924394668576373, 0.6411865530538904, 0.5264104217569282, 0.059327512618869996, 0.05214336855872961, -0.1446230310214065, -0.32916314992044327, -0.19847123007118622, -0.1632716584929555], [1.0513540943186468, 0.8751813820621042, 0.9386378515412719, -0.030146687266321203, -0.18383972307798419, 0.2972937187080047, 0.5055830291540117, 0.25019418097987944, 0.6993653699630464, -0.049480614863666915, 0.01731326065192692, -0.06654088373460329, -0.2816302455524507, 0.23234535759075775, -0.10711752723753148], [0.7474309472528438, -0.2859179567167404, 0.5459989889472774, 0.7475840308632754, -0.6404186350990495, 0.6686901011260082, 0.31369928121868906, 0.4061362727789962, 1.2368736978510948, -0.13504022499755808, -0.4107482295526916, 0.41706633459384634, -0.05155207252639713, 0.2088736266273862, -0.13002150748763888], [-0.15234128110883707, -0.05537610730170943, 1.3225480325612837, 2.6595129009335556, -0.13588529572457295, 0.6653182163310447, -0.715006780725566, 0.16466639439243896, 0.5241490443673219, -0.5495598788333275, -0.30212615174072355, 0.3364372850475297, -0.21562796558306274, -0.02649766457558859, -0.2470408500183494], [-0.058843114814863345, -1.8670751562974797, 0.013372648096723436, -0.0027351612842271165, -0.9562001496080906, 0.6226298794239767, -0.21223438939763598, 0.254943523335986, 0.6934759195577384, -0.34020541864694265, -0.37448964875007124, -0.19264027787144636, 0.26058963729892914, 0.7712298051099535, -0.41604324186399194], [0.6828500992546934, -1.267320438122246, -0.35343646707494464, 0.1469435170263391, -1.1047262574011825, 0.5115600302053301, -0.0764147009822691, -0.3091097461884773, -0.24872626077414756, -0.2581425699527098, -0.38917686061256085, 0.17665665261233673, 0.23282082332171417, 0.382003392689348, -0.08756272445019249], [0.751245254043232, 0.9289342057337137, -1.3613085354153536, -1.439921508620319, 0.45616364357113565, 0.3551323358687389, -0.6942824765793167, -0.314655594899579, -0.06328232144747659, -0.37764002252536083, 0.002811301123326298, 0.006924329088726775, -0.3814783235485149, -0.17528591818223108, -0.003940764594143931], [-0.10168152224098777, -0.9704297014449843, -0.42258012394212235, -0.10582856053783825, -0.1722349246606196, 0.17530937327706977, 0.3566514336722337, -0.2685786977561692, -0.5273993145278197, 0.1957945350989031, 0.08545182190645653, -0.10630857894975398, 0.2370757647805656, -0.06372684206772407, -0.04758757121947391], [0.7231243880654371, 0.36643603671560576, 1.3536241589800917, 1.4145348653534784, 0.5204237421956163, -0.2511031398711148, 0.22331990230447113, -0.40399456311971743, -0.8205324479114295, 0.2571913295417953, -0.10939233993405519, -0.038103540279951366, -0.08010115033998154, -0.26949705182702705, -0.22400099392429867], [0.9630630225902431, 1.1536926113473032, 0.43874703690429323, -1.2530959137338338, 0.6729862111926581, -0.29176901977901243, -0.05471987690839456, 0.03748803196156964, 0.1638110660170207, 0.0743740201525961, -0.26017990660864354, -0.34001893752171225, -0.28827318606365004, -0.4025141890695602, -0.2475152128878208]]}}, {"name": "mean_only", "n_cells": 120, "n_genes": 6, "k": 10, "max_m": 0, "decay": "scaled_gaussian", "k_per_harmonic": [10], "locations": [[47.15280527861838, 25.56637764071808], [48.812185285385205, 4.041801194780109], [30.36779159975148, 18.824329218863628], [40.095060349290364, 8.726390807201422], [43.58176370938282, 27.197070038174907], [45.11075398579942, 23.857676191960316], [21.524813886470657, 39.447335877216474], [49.20764999655607, 18.48628963262144], [48.446643465811746, 46.451319388270974], [8.884629288099056, 30.44258084222738], [35.243237278237125, 47.14018395645836], [33.28287084828767, 6.669787772584657], [24.893379939268723, 24.680991697805744], [25.011309467437293, 47.92911430546236], [17.49686999111274, 11.188557338910798], [26.104350110572383, 32.058546198251406], [46.95535267120044, 29.100790032352293], [13.391669514579425, 46.48873476540334], [24.58626423062383, 33.79004324667629], [23.801945523770097, 10.849001321099754], [34.62760223552803, 38.53152415458719], [9.539425262926882, 22.99580063742408], [18.09075299509546, 8.536490972313743], [11.06758299278936, 48.12537056631892], [44.21115258158906, 19.11459130973896], [36.9736621567522, 2.0984018590635256], [45.75286006200862, 26.85854256070511], [41.01339017589719, 13.796912878258677], [18.806190658953387, 17.402185945591526], [48.62198338556279, 21.47299414613669], [24.98463702659983, 47.79894650093631], [45.1597794175369, 19.750525513006746], [15.36789598645178, 40.352396806751905], [5.373579493464076, 19.609445684831], [43.82169085916375, 45.88212074163266], [11.673813433082591, 3.936007525532742], [39.38637492291026, 31.088903269801182], [11.875240881191862, 25.29465971055032], [3.5709111037608263, 35.00436602614067], [26.33627279830282, 35.23239322200077], [4.4084686504789525, 32.24075116506268], [18.516794157238124, 24.965428299680404], [16.774124987925816, 31.70432631793847], [28.41304675360034, 30.855737854561106], [3.1689810338928814, 11.25708005056168], [3.5952280385695037, 19.164892490689972], [24.050424688784066, 5.617097138126925], [33.37945424463327, 24.367837814651907], [25.016485603243062, 29.873292050140865], [46.74391980520598, 29.44324833291993], [4.674128172533093, 7.323461359237232], [34.69465635161675, 16.130860873861625], [37.764361275092284, 25.531940255517277], [18.98442747348379, 36.972434621408986], [9.14904030232912, 14.24063012047338], [14.597041117208953, 20.765902151314148], [45.355692465329476, 40.62698149890897], [41.08016933806619, 31.55749315278051], [0.41069101682220666, 14.306652693780542], [25.089970134463492, 44.92273751001136], [18.188921254453167, 27.52797317681675], [42.427241906399296, 17.070324603187796], [37.403741806793775, 29.751360716235016], [26.266594637146063, 31.48954577794663], [24.242748397555026, 5.648627765049902], [44.84528908061822, 48.48663658301438], [41.65818283341445, 17.689593180978395], [31.695736397994683, 38.53815474935819], [3.112368992046294, 39.47226732471685], [4.24472284928274, 46.991209344602176], [12.07307433866634, 48.15710609477786], [11.603730459647494, 26.76924324183309], [41.57365834975526, 49.37710648125107], [35.28485522913276, 41.73627398362704], [19.58930652764285, 37.535839912387715], [19.232236663124958, 46.49232470282463], [38.67515164121127, 18.9703695972461], [39.21099595521222, 3.3255798510233356], [46.253818836311375, 34.65629977883282], [16.359964826126223, 32.34735752916872], [39.21380111085127, 31.415752196709956], [44.33019669656203, 20.767850408038413], [16.000533376828898, 18.547686393475203], [14.08684782866439, 23.95356972269258], [37.870044237956655, 43.728274925221164], [31.637560886753803, 39.28769246218858], [48.50355201108808, 32.985334226559495], [4.231631316685597, 31.279580001662783], [0.991132189596633, 33.883370471995114], [49.920652413207875, 24.42958003809132], [46.650924018703485, 0.9791237466384217], [48.25704055432901, 8.419060206971524], [41.97613991964068, 14.914538041759567], [19.66256232886408, 6.628331052370918], [1.8716206918104439, 37.60967446837645], [37.3053831144205, 6.17525488558956], [31.12848111180842, 12.878228441992928], [44.83502945735999, 6.709393761393384], [29.385896098162007, 44.489516974045166], [26.920724696568215, 33.542926911685015], [40.518835260669746, 35.34788457615513], [41.24546914519484, 11.192345633932078], [45.51159117079816, 25.187851404839012], [45.7777275211274, 34.932693654591844], [36.70397383655295, 47.54878558554011], [5.288603142643478, 43.52277552069287], [14.618158563511358, 41.06397992178556], [11.197149778124343, 23.430419981682288], [6.96123964234216, 40.26718648791725], [14.631067073069781, 23.66220298628426], [39.77241159132678, 18.567985863866042], [44.26974355556596, 25.526939160800886], [47.16442633631558, 38.57290888589898], [49.680815223855, 35.63087806716153], [15.635346156315943, 26.50582028216386], [47.020762227632446, 46.227802309187915], [12.530509050282795, 12.79965071058684], [12.633506279130103, 31.274916186248287], [9.72267551072688, 35.263263205981275], [15.986777809085172, 41.89108304313911]], "features": [[0.8382925391554815, -0.5357815089844378, 1.295333980594746, -0.6763912647197142, -0.25179208412346116, -1.8254710649362071], [0.8471222673650767, -0.008751091283308206, 1.0697831154945725, 0.7092646584243003, 0.09947106882979134, 0.16600695337323335], [1.202069671308528, -0.15481203854891207, -0.14227878584071332, 0.08018752414269664, 0.818736303952953, 0.9381846358677198], [1.934497217527141, -0.05894193951479713, 1.2884654366703447, -0.6258324239768248, 0.6350174895697084, 0.15966722635574604], [1.7719189395189767, 0.6483385275977063, -0.40744478373891585, 0.6204893353394123, 0.3898468357353195, -0.27225052162371727], [-0.24905620767605252, -0.8976904193941799, 2.8043319412036705, 0.18290134186419704, 1.0226532132010455, -1.1169905865894318], [-1.0368651406568785, -0.10387420939642665, -0.09927146856704905, 0.8522030185301346, -0.9537264726805303, 0.5900864341051688], [1.5655534503057242, -0.8636458732292807, 0.9604621253114379, -0.9099019851565014, 0.39696248648137683, 0.41418584396020036], [1.7882879160024885, -0.6398277806849743, 0.21922658016656438, 1.0945159177456507, -1.1212269270861612, 0.04168013510434051], [-0.8194099656011558, -0.6514171909737703, 0.7324393207508331, 0.7509714114673515, 2.628106119344124, 1.4274554265620245], [1.3393956530093372, -0.11676380200040161, -0.25091788597956105, 0.18602922978100997, -2.2267565397809213, 1.7047677751212658], [-0.6246207268211226, -1.0151551380348043, -0.414721644524359, 0.9168834151535245, 1.2834435014980463, -0.3383313852927848], [0.47303017539746206, -0.021620125439037064, -0.962156349736473, 0.2026726183568746, 0.05913431606857885, -1.5071538681636054], [1.1297919219231545, -1.54315828186273, 0.2612730471866325, -1.023514407472337, -0.7883965094444757, -0.6774150886909966], [0.7292334231560876, -1.2306690905524644, -0.16769966254406435, 1.5742115977799505, -0.6745728165879054, -0.011189795575854427], [0.68418112970563, -0.5636993991014299, 0.49371721742131663, -0.6430266177294371, 0.7172439574798849, 0.07942344483599749], [-0.9195491696517337, 1.4256374334746589, -0.07857938585982074, -0.2637220050702941, -0.9088499680269638, -0.4542069815799693], [-0.08077348387943, 0.1873017343712804, 1.1133844988399955, -1.3032360616193475, -0.33489386223019485, 1.2104649069395903], [0.19580209601547094, 0.42199900504313625, 1.6066585628255345, 0.3509720553612781, 0.47962821970188263, -0.027718929155257546], [1.7806575945572853, 1.0627810970389353, -0.7088897926970587, 0.5604350668562151, -1.1366224937006022, 1.0983201942238328], [0.6820676743368, -0.15016854176968703, -0.3929110439950159, -1.7868228381220084, 0.7709866409742615, -0.11046920726424042], [-0.3056748375395381, 0.7284855506966182, -0.660247103532902, -0.5830860007199183, -0.6914806092799765, -1.3511924911654463], [2.4107328154241845, -0.19409785981244757, -0.350515950236606, 0.8996481287639838, -3.150962810068764, -0.03327301850577713], [0.00921326453511899, -0.9763487683390772, 0.45315886512250836, -2.0350808735107173, -0.009058926504619405, 0.860968824740586], [-2.254921892315956, -1.491550021523633, -0.2125523666267897, -0.08649378209822955, -0.7290129838619026, 0.26733953880526645], [0.13792045998173602, -1.4635001101370253, -0.22432641960401753, -1.4088387394353237, -2.2176812473298546, -2.560515372904948], [0.8732164923565644, -0.2883062753863353, 1.7932034407381086, -1.6309246504259265, -0.5253295102654808, 0.16670386828735514], [-0.3159458650548306, 0.32897590048263653, -0.024797827106022765, -0.7837550496941335, -2.497628287360758, -1.1147848479180842], [1.5594944669495905, 0.6082985690963003, 1.2233882523452837, -0.7364241490707799, -0.338126487708947, -1.0197584663966615], [0.25239397991881257, -0.07351211225974372, 0.3204063237704337, 1.6324464310546851, -0.9643092974601902, 0.6115328274260176], [-1.528056605878365, 0.9799928626949387, -0.5650072775362897, -0.19473381102391252, 0.014454002985211167, 1.5250083748441063], [-0.15312271871256172, -0.6194479836144084, -1.3061418365796362, 0.15439478723373204, -0.9767105115916423, -0.625129306958018], [-0.1472251885572021, 0.5501624607963658, -0.8369993509375739, 0.5488540249232975, 1.6492625200113638, -1.6116336210579334], [1.2413233827202526, 2.0329701740793213, -0.7120074138687121, 0.4937293390675241, -1.4944211915357009, 0.22011544597662686], [-0.44565012132616116, 0.18508723379763697, -1.0388377193842937, -0.944583123346283, -0.5717085705302731, -0.8385680455394496], [-0.7484551553556026, -0.3347692178533813, -1.2459325074518615, -0.2837437926521366, 0.34184247290082903, -2.4557788779715435], [0.053760878211953654, -0.8923131647885544, -1.269245755517086, -1.4974932265087706, -1.006507527242587, -0.9047656578200861], [0.18334238605892011, -1.4267793287604131, 0.8781826813001551, -0.9830530121886011, 0.521026350167463, 0.9275922918565142], [-1.3804207548204102, 0.9191116264026121, 2.0439451078418336, -0.5717943495912593, 0.4664337790229306, -0.23452316910013452], [-0.013529309233113069, -0.2749499284346996, -0.5803139409341561, 0.6552587748738818, 0.8204806517522729, -0.0556227760708315], [1.4650504403627012, 1.0454494783462798, 0.6644873812895564, -0.7530927400346547, 1.871373588760955, 1.2943223928958751], [-2.1742207012083754, -1.1311861981603828, -0.49832385924316913, 0.9203640869404566, 1.2284717002335817, -0.3029577559252246], [0.23387475840433666, 0.6867866534480366, -1.283640104123325, 0.5840255507920038, -0.31217165901124144, 0.18032720332845115], [-0.0519305338291415, -1.1837236908620172, -0.9972340032797281, 0.04028345313538473, 0.12867140053857926, -0.2641411990994953], [1.062408091378854, -0.35878679813698233, -1.2175036260483232, -0.34569531173147805, -0.17534465987240028, -0.13114113567127092], [1.1635318956357834, 0.5108031182362429, 1.0547807939699048, 0.624442530135642, -0.163892272113936, 1.0390094266386218], [-0.2586887358396643, 0.25090111151060057, -0.9985004237067293, 0.10473381946008772, -0.32048936208817086, 0.3766418969701245], [1.8219403408483463, 2.377447197448819, 1.0256548748313117, -0.022002252889147804, 0.833290849310314, 0.2375800338522262], [-0.5994011659371045, -0.054415937082805364, -0.24147103189254973, -0.5954602450347756, 1.3895484260542814, -0.5312720187577779], [-0.48787842817365773, 0.7128492089892869, -0.6850510087800217, -1.1403285811663615, -0.8414800308767022, 0.49195740791866], [0.38664566516530097, 0.3095939128476011, -0.4535367107292573, -0.902162768692738, 0.9184895570800916, -1.4341644959054038], [-0.20012586156057752, -1.3128064191664444, -0.39295306988657086, -0.13902996020212594, 1.2421635526705244, -2.8529172257040925], [1.3821525689383072, -0.8681005642437856, 0.3127902818627088, 0.8243922356725434, -0.7449975207345899, -0.06737960415239179], [0.5144665957897727, -0.10144988907463535, -0.7133065264239165, 0.21277638352929665, 0.13474139771226104, -1.4728920624694524], [1.3858155927627565, 0.2541366500789375, -2.393120120314613, -0.8004530493930023, 1.7509588722232243, 1.6196867211577857], [0.30309200756382, -1.6515607077076664, -0.20373058192605017, 1.0941352121754067, 0.42923708660390486, -0.2969175739023463], [-0.699640625847377, 0.8631636961114103, -0.17404134609481461, 0.3626221588987103, 0.5317759248926346, 1.6801828157686531], [0.22430631967394268, 0.30007066353291273, -1.7465103682755208, 1.1536921957942885, 0.9306327602709309, 0.02734274010243972], [-2.231272441056731, -0.5222504231566589, 0.11706233203787492, 2.139956371348318, 0.6320170160200486, 0.8352309085313067], [0.8617412709618895, 1.3768413782285087, -1.0956621853412678, -0.8127559402785798, -1.1434449347799889, -0.2471668288856403], [-0.3175815820741934, 0.138612990428419, -0.9912421216284552, 0.12732145622160065, -0.8210197297695294, 2.1509018824786286], [-0.4971640639836149, 2.584930527532546, 1.6686891913186568, -1.16731063075859, 0.990354792271362, 0.6394601084996111], [-1.5062771588222201, 0.6400006038426689, -0.06043462065404458, 0.37895337366161747, -0.8245453039531646, -0.03245260363151463], [0.4424855098052631, -0.15307482440962378, -0.5803561507853126, -0.1301661758302035, -0.9533864855597931, 0.3704303763699912], [-2.536356051821073, 1.5367698417960656, 0.09073319040476133, 0.5015658997693658, 0.8825592494457821, -1.2177195251925819], [2.3076089643451714, -1.0952461277511842, 0.49408662538427106, 0.35185186987285055, 1.3408497212598083, 0.01567969990556346], [-1.3883300589045795, 0.3488327629366152, -2.4476072280816723, -0.17899795200762575, -0.4394744383067253, 1.5836487011308307], [-0.260848565472516, -0.43224502742119403, -0.7404713843634765, -0.8401613173253072, -0.5382840715085297, 0.6154676784843939], [-1.306572067260067, -0.19611572321274862, -1.4536749373797382, -0.1556876055492029, 0.17414464680087444, -1.2265311945560837], [-0.5656226104617175, 0.11167906689940932, 0.7782198349241706, 0.9581094474855347, -0.10823607815317435, -0.999146371333797], [-1.6270428393737675, 0.7823622939495902, 1.398960164215905, 0.3669599799102376, 1.5690036635334341, -0.4551497423459583], [-0.3934612595345395, 1.5737149921870055, -1.0127875713105792, 0.605623326178828, 0.38633772662272686, 0.15290499125624274], [1.736394769263731, -0.8829540911015901, -0.43080557825005333, -2.0989074984131304, -1.0532224318547576, -0.5164453018955212], [-0.3906514049938237, -0.2053364873412316, 0.2990294325783975, -0.6718030749980181, -1.9897387601250038, 0.1518226263745302], [0.4218922336725892, -1.1678737889906936, -0.791799312081196, 1.768003132779944, 1.0307691615134937, 1.0925626159158792], [0.6718865977743702, 0.14615051374557808, -0.5139859940385473, 0.5739297839306022, -0.20073010322927765, -0.4439042012066343], [-0.012523401353315346, -0.08222137409234641, 0.8927301288704423, -0.9659673907714352, 2.5048058433893177, -1.0145426412358298], [-0.4308572883030942, 0.947577595142348, -0.842961451318415, -0.4858073768408888, 0.027048385347677666, -2.985367140406743], [-0.5113680153547979, -0.9716375147686888, -0.24938143730968718, 0.5014220691714657, 0.6430747970961137, 1.511503483204818], [1.452100690326744, 1.040707104127608, -0.03902619607771523, 1.0511815070680788, -1.000842025497498, -0.09575169257871852], [1.4512179423644136, 0.7985697218246638, -1.4054015448359203, -0.5939798902534793, 0.9150710494585778, 0.6251831835608871], [1.0907542569836284, -1.7754568919098317, -1.2700579211944927, -0.24520313601620838, -0.974439079141713, -0.02192410877886003], [0.02338441480338026, 0.36136916618610976, -0.11831995199557714, 0.5811876529217637, 0.8012047553652368, 0.17182984170809695], [-1.2134806585227527, 1.3193887532274282, 0.23831217661962426, 0.446581163752063, 0.19302665629599536, -1.6024587883284391], [0.6033034504548798, -0.6402491663448888, -1.2091223444530792, 1.314775268002159, -0.2882289972954396, 0.3100931176604786], [0.91717684910421, 1.649052859683615, -1.8068283588154765, -0.7302214941200738, 0.6992377719508424, -0.6550879676176417], [-3.2669820945815617, 0.16260836001976217, 0.24436091315771588, 0.8172025744051031, 0.24892168932247405, -0.42660140508523875], [0.23299557146980254, -0.017353766335170398, -0.491285028804495, 0.27561108779185534, 0.3758176762956059, -1.0029607934382712], [1.0515519446927146, 0.8516427157925733, 0.8102356232678802, -2.7475068722255824, 0.13556854993001388, -0.10766950677364213], [-0.9913146990319827, 0.6013715711254413, -1.4985390175616229, 1.2558212896782557, 0.40436125659212946, -0.49357924241406537], [1.448993638451382, 0.4795240739828515, 0.3513450542611719, -1.2969244357638487, 0.544290787183986, 1.4315910107058039], [1.1229468486657215, -1.2870787801730281, 1.4112497246019924, 1.624860443970902, 0.8613985657420724, -0.37917592545694745], [-1.5068439434405143, -0.9116092278903716, -0.5812303869606482, 0.2751570734512046, 0.5537098306657516, -0.7519630852989135], [-1.6557376696974835, -0.4256852758447524, -1.3509543906164363, 1.3267661472798717, -1.258783708722862, 0.4616509448501243], [0.8067646871511589, -1.0158285567720857, 0.9813439264107101, -0.17622924507465637, -0.8347627704359823, -0.9924518453614288], [0.06965366323114365, 1.039332910899628, -1.9587537966319093, 0.572706674812718, -0.19979520394137765, -0.8110481283799912], [-0.15502026768106064, -0.06002044615500408, -0.10828954782246085, 0.7690323172436571, -0.9581045682859423, 1.9421018961745662], [0.855666396896393, -0.6457382577404326, -1.9873558111002052, -0.06323305477013909, -0.4515435302220856, 0.7115729299264841], [0.6936917628650009, 1.897495118243151, -0.1611251626905084, 0.7700633472753682, -0.4530590180003152, -0.3999653076685399], [1.5251184415934043, -0.15826476397454556, -0.12652986403941235, -0.37298292912528397, 0.3148541139351051, 0.5885961182065578], [-0.13075260424385515, -1.1635242623443247, 0.33642087036502355, -0.8347936999905297, -0.36317427339804453, 0.21567034439877528], [0.2511256283114594, -2.341128163757851, 1.7185163160751387, 0.8080207910964916, 1.9559963267360467, 2.544228999073207], [-0.9484394199859282, -0.5719333391814934, 0.24441663569202637, 0.9373209772943016, -0.5268083996692312, -0.33144628848723084], [1.0683927510542603, -0.9123714381628631, 0.19440641045630105, 1.0718391425495308, -0.28999121701184766, 0.7566619264875113], [-0.14852678446902504, -1.636642371638034, -0.5885325163257528, -0.2493143591809396, -0.3885760932273062, -0.028433609947334768], [0.3412699927926941, 0.2284654457079825, 0.11266938480610143, -0.5082536014848729, -0.29868210051896954, -0.45822670143651395], [-0.6787902890047417, 1.2940487668324958, -2.008341788215913, 0.13540701204528657, -1.752883661931127, -0.7146692657062436], [0.6885014479729223, -0.40825831198859025, 1.2808264245249037, -1.0874276486380174, -0.436003933623066, -0.7810027793673632], [-0.13781638964524068, -0.4715798085813686, -0.543380363711099, -0.08022476664399245, 0.9382158888949009, -0.027922208092860314], [-0.12913124960946099, -0.4854349390577605, -0.9107785399344938, -1.659264599184082, -1.2640887663937221, -0.18403888406380742], [-2.144617684062184, 0.4311109489739286, -0.653997740993856, -1.1777422636643677, -0.7862472635332998, 0.42088824150691523], [0.1297361755366147, 0.027185609827514997, 1.5396665273911485, 2.1339764808878794, -1.491404114138618, 0.6958007071774687], [-0.9457076767793718, -1.5497461439207871, -0.683032775677535, 0.88111094864742, -0.4378658545171103, -0.5920458874811362], [1.3152291719881273, 0.4274468780423327, -0.15070554266552552, 1.7647128836462846, 0.44458723044605547, -0.7653193726237737], [-1.1191133547787244, -0.4411645095033841, 0.159340971311412, 0.9414842104475346, 0.8499871123512498, 0.11976394442327996], [-1.1718818057741571, 0.9426450600299335, 0.1000904131133067, -1.0935513665250671, -1.2404360360198516, 0.22070248725538266], [0.3430028524296201, 0.8099763276224512, -1.2384294774892464, 1.9164962684819635, -1.84557319482544, -0.0583896271393143], [1.3295845259489045, 1.0270770098272624, -0.9879002139204223, 0.5883155676180393, 1.2120683875227254, 0.713614023905647], [-1.022437051325962, 1.6464797766883286, -1.6773859983454356, 0.002395205405223495, -1.1230066802289727, -0.47976526014463183], [-0.3855418436502504, 0.44724552970640447, -1.3316494115240423, 0.16037638559254808, 1.246193761592315, 0.017694328320989265]], "harmonics": [[[-0.12419950417972345, -0.04571798662534248, 0.6844807298479905, 0.31533777404984004, -0.35171329380574257, -0.15094800538288794], [0.7029123138106135, -0.39706889580688437, -0.012513465019386917, -0.06738540380672652, 0.15868141466076632, -0.0011054886980832697], [0.30118930653456183, 0.18594894499884398, -0.08662426285897287, -0.027067280332321503, 0.23573173358363786, -0.3062210558072346], [-0.039080741643961026, -0.4301610275428811, -0.2925982030294937, 0.13553361287566063, 0.07904031078637806, -0.2092817490688367], [0.005373762041698881, -0.10466392518761782, 0.8893812687307369, 0.13130363775648227, -0.5526766073216767, -0.17838287924659132], [0.18184843733612396, -0.42358522838070223, 0.42539269215087183, 0.4735923751335556, -0.6663759369785647, -0.2049674362808152], [0.28049395856474046, 0.06484291094911424, -0.668413795915597, 0.4983247896608959, 0.3985932310609404, -0.26349782982248354], [-0.3658208737605941, -0.36847654458411616, -0.16731147695753304, 0.34226241248998146, -0.41324720763037054, -0.07698432151502775], [0.16115937626311155, -0.1272700327042094, -0.23570665348454922, -0.3162395980791551, -0.22941419962452042, 0.0131212791788697], [0.2894089414674382, 0.7436171374113825, -0.30174220336001306, -0.023156415580788327, 0.41044217506065106, 0.09121808041059709], [0.42867009725930555, -0.3273197560759966, -0.5568111515869396, -0.30390959434858905, -0.4646095713091245, -0.09957707742151656], [0.07678681779503733, 0.02066991659841534, -0.3721361559799334, -0.011469171678045382, -0.20854078195220155, -0.6234560635722717], [0.03411666434344176, -0.16703125857914938, -0.18233012444229466, -0.03685107131363136, 0.4618676659082401, 0.24641890461691768], [0.05521241842197332, 0.7297673464440314, -0.6598515182484536, 5.551847779353116e-05, -0.4459101196590518, 0.28806053228000733], [0.5834596258660287, 0.3131413183555992, -0.6246109154411452, 0.6726275729556674, -1.1033165804297977, 0.010135202497271886], [0.37559280868296235, -0.19531184286162767, -0.15446786568287946, -0.08201403559987229, 0.15937837299223978, 0.10530459399584313], [-0.12722645017051337, 0.04046138143425004, 0.4486822829106416, -0.16056605942377966, -0.33242444138564353, -0.11680187599860216], [-0.471446587268372, 0.2429073472515574, -0.09850926079623389, -0.1867571711533755, 0.4488287648224338, -0.23340030180142135], [0.40880887659356135, -0.34118122979078375, -0.292321351660251, -0.05669057121486741, 0.36148576295002116, 0.10693715821099334], [-0.16985165740592675, 0.06419579503191238, -0.35826629400174353, 0.68261036867903, -0.6235344452731744, 0.04242056239056796], [0.29812023179970387, 0.11007427235050668, -0.6914631466372754, -0.35177163425256286, -0.4889059512988269, 0.1248458024701698], [0.0908785561302088, -0.004657950000332535, 0.23689005895353785, -0.2148812252325555, -0.03974180075687193, -0.10845558772647267], [-0.18676435844945366, 0.02787457912225148, -0.7021037417968563, 0.8672608353943978, -0.5936964803073578, -0.03187920645748896], [-0.48659434229018844, 0.3942365995781396, 0.1804288109584448, -0.030182189746109287, 0.34959820762615185, -0.23323124785823948], [-0.2653525528117676, -0.16253846459480237, -0.3355836444650312, -0.258245964226548, -0.14184018089273764, 0.09978788487096231], [0.2801489960691482, 0.049160501993991655, -0.41365820171065476, 0.05078293744665563, 0.24181949636734607, -0.3929590153017493], [0.06110047546784066, 0.06766482687546879, 0.5983067687232521, 0.4020915766694453, -0.4509141060418147, -0.40712203554980114], [-0.6743197512464667, -0.31492967812215567, 0.14690693112607595, -0.20687656325619427, 0.6686137590146701, 0.44336692500003305], [0.1701954846766136, -0.2201371264792039, -0.41183405401695256, 0.702965413780067, -0.2792180340999447, -0.18143074897403227], [0.05513428296672584, -0.6251925171535585, 0.20081653061892313, 0.08760175071449526, -0.18625643763996513, -0.3649825134618313], [0.598996812515372, 0.2588846323030842, -0.5086328637786173, -0.0685942451190488, -0.5354697043767279, -0.0927824989188713], [-0.4743197409684385, -0.6146797792846895, -0.05314679101003375, -0.10137520779449068, -0.3179945868517409, 0.2332227943558485], [-0.16153459258762007, 0.34629262252172577, -0.9333314195104728, 0.33537159295360935, -0.1670490470648118, -0.11039943849773808], [0.24451856334379657, 0.08381747403522143, -0.07636232114172295, 0.08283461178942272, 0.16567457693876442, 0.18438968558810456], [0.7091695160202305, -0.38034389890249876, -0.09340415479603524, -0.14998104075819743, -0.38078260019511645, 0.20122101598456696], [0.44286521467131257, 0.0534937181822657, -0.8714237897374709, 0.5592274965452265, -0.6832757083572343, -0.03559870457155703], [0.36847942815765294, 0.16754000136869684, -0.49839164668733915, 0.20299463626812375, 0.0328221247694656, 0.21086214518273624], [-0.2981215945547898, 0.4279862599502509, -0.12921439234654927, -0.13892841432297257, -0.044562670927520275, -0.5348911413826], [0.3853444490386946, 0.20567146606278633, 0.07878687917909379, -0.6283156727948266, 0.4005117613095296, -0.22375950492780958], [0.4394170114567818, -0.16915415972301034, 0.013467166854015705, -0.13568075145923889, 0.23455000377489688, 0.17746117726965446], [-0.18694628353683312, 0.31347789286262495, 0.27433572344859697, -0.36940911493149964, 0.43698005489514585, -0.2744744180423398], [-0.34017133502506425, -0.04386237811248196, -0.41471775829932367, 0.15143477534713032, -0.033698467664223665, 0.14008354058492256], [0.20386035932102586, 0.3270816614176617, -0.534021865025112, 0.7249065463829548, 0.17843206422470534, 0.3600940886081067], [0.46798281158125726, -0.12243763290460358, -0.02314344311722715, -0.22560537234736938, 0.3469900600766255, 0.06865488446963636], [0.09572792209773712, 0.3030922277155039, -0.5476331830427918, 0.4114077752763577, 0.22674206308394826, 0.07050067877309377], [0.2596040636880756, 0.4106951424813402, -0.5809415798721608, 0.26436732587831013, -0.21938803365187626, 0.1637036547244981], [-0.23246091520058254, 0.2562799147049771, -0.4809955415517803, 0.7920595999745836, -0.6356703665220881, -0.05559095928379798], [0.1656723424030718, -0.29381928453113626, -0.31919795189500694, -0.13049747952071541, 0.18282650870088615, -0.37158773553183133], [0.43550136334818884, -0.30890337039191473, -0.1364672059885442, -0.07208296161224934, 0.10518292489782871, 0.055358628888945084], [-0.20173912276218192, 0.1663582976692105, 0.6128684781005933, 0.061807928542339075, -0.3601546498150454, -0.2525296587440848], [0.2989315922244985, 0.01077575772295168, -0.9148478167479751, 0.5259048703060054, -0.21228050829924852, 0.04689929357605431], [-0.30172679850422496, 0.1724453157415839, 0.035563207910884014, -0.2630510254961785, 0.24514077121864825, 0.501895545614703], [0.23046886371277558, 0.5052550673918954, 0.025114531870237333, 0.02314980889189248, 0.17468999951522654, -0.0941032295346878], [0.03967836972457675, 0.12482501325238035, -0.6309534293599071, 0.861286350181925, 0.20943651102162045, 0.13322839780500878], [0.3836201888291597, 0.2655479226706013, -0.47527489900391934, 0.734121409411922, -0.44104001236850543, -0.06127642681465367], [-0.24490681168982553, 0.08485797562305933, 0.06191008624666474, -0.2519679914595702, 0.033232801251245184, -0.43687419326048005], [0.09788494434258185, -0.5964423829442611, -0.26541261973813596, 0.39542771881504235, -0.28856516322017306, 0.007236782031681792], [0.2472545570686788, -0.05049813225083472, -0.46771538676217667, -0.4586191316785136, -0.2331926276070764, 0.10100311765719698], [0.8483534356342017, 0.41437681017317407, -0.6247772835626906, -0.037842965712442854, -0.10711791012352685, 0.0082314976615209], [0.046270334087475336, 0.22995562198394814, -0.4212977621382378, 0.08550243317851279, -0.18325457894086694, 0.15419730911045687], [-0.5603255283555327, 0.013594555756145332, -0.37084859244758295, 0.4111769766772891, 0.33264421129772925, -0.1114987723323163], [-1.107432694982919, -0.42903016319306725, -0.8646596139265359, -0.2866119298737299, -0.3885470192636675, 0.1395011304951015], [0.7972108161911944, -0.012928991877517402, -0.5292608220178959, -0.0858988114893726, -0.01110772706327996, -0.013722278805749279], [0.3547462448369762, -0.354416168960169, 0.05164031168717849, -0.24260467263953783, 0.6443599030645452, -0.030178312654070574], [0.27391764167422883, -0.027822987016433303, -0.726084880522089, 0.7013042137457834, -0.8922920672023134, 0.3114451359919211], [0.27755779360242666, -0.21727723598889315, -0.3746108470110829, -0.4157644419135585, -0.8427249799219476, 0.015884303949865276], [-0.9404148829744545, 0.17918057168693438, 0.11012268499563742, -0.6085306761848288, 0.047957352576781166, -0.06658626780250604], [0.5312205169908186, 0.3559995174827126, -0.5395387521048558, -0.43274627471873556, 0.13645886258154583, -0.13817768789070306], [0.10012806661722216, 0.1283033748362757, 0.48980770877518237, -0.4460947173414969, 0.13828068665164686, -0.3409105340670574], [-0.3213418246474263, -0.04525233115543083, 0.13059775614319669, -0.5247295805560149, 0.15073782159276458, -0.19506651852574858], [-0.10747692693721886, 0.024707609320729046, -0.04856660448609829, -0.5836220833801485, 0.002138640205971416, 0.10097139632849762], [-0.13043093285909513, -0.2520723008585307, 0.2293185194372584, -0.29381370855927613, 0.29762964579419265, -0.0011344636494214837], [0.5283467643980044, -0.44385526404209896, -0.2923771789115189, -0.024566231793314703, -0.4043495877918145, 0.13183166351204137], [0.5444181556940468, -0.032639139221698435, -0.778542193897601, -0.3261889832801215, -0.2200009182879573, 0.16343833333886987], [0.01677476630878683, 0.3113789389893243, -0.5588023131706703, 0.4637428883595777, 0.0036730470230766704, -0.42563797015416194], [-0.2898153116834915, 0.33336829431366105, -0.3154788478680349, -0.34769604190645276, -0.07069059525514439, 0.09545700740029245], [-0.9565937092456572, -0.031953108363410525, -0.5644160629395321, -0.4456438434847432, -0.3397725986285269, -0.02971829646820145], [0.527784095444448, -0.44870014920100576, -0.26724663217333305, -0.17351031431747319, -0.20462711226400584, -0.38696290770703545], [-0.3822154659910148, -0.16384536034635447, -0.21523434854872517, 0.5850790497487478, -0.1111657351293123, 0.014018641001580845], [0.0018418528914557033, 0.2846623591460037, -0.8438640520763695, 0.617258403689605, 0.3409503241536093, 0.37902097686308855], [0.02549284304430351, -0.23051819640264848, -0.5212302630143844, 0.08484940587144836, -0.32642886226114143, -0.04069710386396049], [-0.7395433942904673, -0.32986516261507254, 0.12365047666050628, 0.1459973551164131, -0.39117299492480656, 0.08799404718838312], [0.1426017203574224, -0.286793200410405, 0.058657108665032626, 0.07934728812987667, -0.25089377778123184, -0.5427418694014748], [-0.1834007042362089, -0.520624158762969, -0.0986730174580302, -0.3932286159899922, -0.08914596929766426, -0.03507919396895325], [0.39309020940249007, -0.3261574838514621, -0.390635788746816, -0.6357105858950962, -0.7475577193493149, 0.23741631362979307], [0.3433321074997177, 0.06542910405846304, -0.3328630803640317, -0.3987389443842727, -0.3797044045295148, 0.21161838869200647], [0.18336871431254334, -0.0827998155591416, -0.1418200080364913, 0.4306232805520037, -0.10179606615482605, 0.19374000660675822], [0.10159442884532018, 0.557464946464148, 0.4601480373870602, -0.540085178081326, 0.811089876752078, 0.27809702349821425], [-0.0654128725960317, 0.20109699228184288, 0.3376137770755509, -0.20678831120017008, 0.49063443993117717, -0.240651488480593], [0.1434253546479075, -0.22023221034013982, 0.8482413598644134, 0.11799972410253283, -0.4730020763912509, -0.31315958794086296], [0.5742876900983377, -0.3778025711281891, 0.0057637725648123535, 0.19956203439436265, -0.025152959505469957, -0.4498701271265714], [0.5802316137615328, -0.2382835037085262, 0.2090523073638989, -0.17626367401928789, 0.18745371551280238, 0.36015194129487893], [-0.6355734664407966, 0.16226271750293667, 0.023380247327929246, -0.5077557999637028, -0.22003659191472297, 0.3998977366530185], [0.44181686533705816, 0.23761114853964926, -0.4783626029382927, 0.6661668580589408, -0.910692975691131, -0.1730216847967919], [-0.2584585442334331, 0.4029403984478762, 0.14687844558745147, -0.6529814294681668, 0.43278917282158524, -0.3200396310498017], [0.1857087288321216, -0.569886670021971, -0.04000004533627692, -0.20280790002448026, 0.003763748100441156, -0.7558605029808001], [0.18426965381237664, -0.030188359768946713, -0.2914802163982342, 0.09163601437617043, 0.4475618851644853, -0.5347281958196196], [0.6968896506620919, -0.39456188792558905, 0.620221808484873, 0.19781686479870936, 0.36621395672923274, -0.06752604695472882], [0.3318720672705256, 0.1605594340699588, -0.6283575717695895, -0.5681126173091756, -0.6583865367769635, 0.23601688378185948], [0.21136938421780604, -0.2882649416346094, -0.002160460845166898, -0.0059031439770480644, 0.34562590626902207, 0.0017802114396432115], [0.15906284539068324, -0.16198548067352367, -0.7697100761872405, 0.0010503704822543386, 0.10009031553674154, 0.27563070001745743], [-0.06358669587778472, 0.17643031206115004, -0.22610172069586745, -0.294022671358158, -0.26462315303462225, -0.23384758977653797], [0.40009197673739016, -0.16380657443737698, 1.117488728835404, 0.1387565272198153, -0.3041369299382611, -0.3812746845064655], [-0.6317663212546678, -0.17009321737354263, -0.3276721026400312, 0.47156493888522466, 0.15163014075264986, 0.25125354485789847], [0.8180867539718139, -0.14766558252509768, -0.47465670987487024, -0.2641617717514173, -0.844721981079149, 0.24532590128677748], [-0.5400147467789725, -0.010814086520272884, 0.07779882904841724, -0.15636125825708563, 0.067194776386087, -0.42476248755146817], [-0.21444690940157557, 0.223935094193703, -0.5482733080385684, 0.3023216139265564, 0.6652832870120577, -0.2884929816237057], [-0.2987670185101587, 0.08374834343973732, -0.1860733068639492, -0.25803327874352516, -0.043813271332171486, -0.36568402518407467], [-0.31015913730090416, 0.3987392308915564, -0.15220589353265057, -0.25505461205867136, -0.14701388357775447, -0.6487083501832214], [-0.5209040695102065, -0.11993564421251086, 0.12594855479625502, 0.2605214418661487, 0.3267595882517476, -0.3715219163103411], [-0.6174820987897194, -0.02074925051443201, -0.2713903007076696, -0.44333689317002084, 0.31928526251051215, -0.150191038471652], [0.27950347100520767, -0.23339625120783697, 0.7685343475907387, -0.0757826380457156, -0.11134955706360154, -0.5165748750442412], [-0.1934949408020465, -0.06490506460286596, -0.07363022519202707, 0.5262740504172276, 0.04164443329805186, 0.4969488228095894], [-0.8102483849126194, -0.32928824603541695, -0.13880344657279148, 0.42402987708869255, -0.04943856025507261, 0.36018153259831814], [-0.49608448584628195, 0.003232054435048922, -0.40503832423201364, -0.04172359548614908, -0.01607752484254371, 0.14855539042937504], [0.8588868443321857, -0.49279246839331914, -0.2264396581441542, 0.11619688289359864, -0.19909283799027203, -0.03898645551186158], [0.7565883801860938, -0.25453049953833073, -0.7100286936392111, 0.2697787121125428, -0.02672474766396865, -0.023443280512214358], [-0.18506698872529137, 0.45065815099416623, -0.3931654386514915, 0.4385378642006232, 0.17812941906581742, 0.3406565781241147], [0.06414583178481123, 0.4003202270544312, -0.13787714060789097, 0.18780879509823942, 0.9065585733605598, 0.10577925338823299], [-0.22320408111097836, 0.3552978593961475, -0.6650473533686214, 0.2634793922493432, 0.001825018143174373, -0.41894161110455685]]], "banksy": {"0.2": [[0.6017828228213842, -0.5012500244397129, 1.345801267659872, -0.6770370144513761, -0.1791599136701605, -1.605234257456545, -0.1944161374936004, -0.048312311202849484, 0.9552070348793905, 0.34761157583683056, -0.33605289468729455, -0.17299216764801045], [0.6089522272854573, -0.001809112273167973, 1.1424325772346475, 0.6296335129411891, 0.12621208171931964, 0.20700861968228979, 0.7052878660249731, -0.5816518115079512, 0.19309524435722333, -0.1117457065039274, 0.2586550869036596, 0.08026609576516135], [0.897156058925258, -0.14022391772678963, 0.049572917931681414, 0.0364151409825433, 0.7515081260586883, 0.9096894889263951, 0.2683072908592496, 0.30335071946208103, 0.11206054815103722, -0.06335453319687799, 0.34843352482131495, -0.4354289177464803], [1.4918594512407322, -0.049372520724030367, 1.3396082221026615, -0.6293601373894493, 0.5917914564703263, 0.20123947484372456, -0.10182685299510842, -0.6318846145060154, -0.11315677718713185, 0.13180454974267375, 0.1658578863231194, -0.2715856973827564], [1.3598520548130109, 0.6208825343695223, -0.18951488921951282, 0.5459185759952443, 0.37865138999055353, -0.19180521612911092, -0.053470761266666125, -0.13779037030636282, 1.1792506750084164, 0.1267275907615195, -0.5702137991253029, -0.2193615737778898], [-0.28110312502318624, -0.8442133720291563, 2.7063943160043165, 0.13327404811161683, 0.9287840883883687, -0.960517776194156, 0.1384923668480013, -0.6219027606168852, 0.6719133578785411, 0.5375540921977824, -0.702695381960775, -0.26429380594440094], [-0.920774103209322, -0.09195263204527172, 0.08835060911350306, 0.7644240762148878, -0.7893893187871088, 0.592920495802114, 0.2457955977390869, 0.11951561331570208, -0.5240834341230282, 0.5672387713087556, 0.538198486794784, -0.36321970597071607], [1.1922911033911585, -0.8119510231782867, 1.043862941513415, -0.8972371168928555, 0.3848374087874279, 0.4328511459805461, -0.4572436159786073, -0.5382495321479174, 0.02383502538237221, 0.3799274361177202, -0.4077517369421169, -0.04798149279784171], [1.3731430429711367, -0.5998495797980388, 0.375525437927292, 0.9929246141359834, -0.9350064937183472, 0.0938713473781743, 0.11598751239959468, -0.1721057222000808, -0.05095006010317074, -0.4104289140909081, -0.19355093249132643, 0.10431165110028998], [-0.7442087474279132, -0.610832296263165, 0.8382654186221519, 0.668962890519241, 2.3244908493477157, 1.3549253877291032, 0.255493011842473, 1.1498732907859917, -0.12315506772634276, -0.05866058125509146, 0.5520047850442781, 0.23630796760420694], [1.0086595483723189, -0.10416746760574037, -0.048381889354913665, 0.13622363962681291, -1.896102984917032, 1.6072793297754964, 0.4069765436640805, -0.4757748367836272, -0.4020541665586039, -0.39563002723841945, -0.46759876734121164, -0.08616693077090318], [-0.5860472723617385, -0.9555289322982582, -0.19607609503747758, 0.8254175498155207, 1.1555031451578999, -0.25193873173834136, 0.024209923215494596, 0.05246241345672901, -0.20012566757948516, -0.04463315645347781, -0.16922938705425367, -0.9716077602938091], [0.3052036349774212, -0.014004465599215418, -0.6896724243748146, 0.1519183189225793, 0.09114516799762086, -1.3155659471773034, -0.022205213234170944, -0.23246199789339791, 0.007413241083277985, -0.075097369523997, 0.6119253707340894, 0.49862264362814257], [0.8384692673506827, -1.4558916493696783, 0.4134367752705602, -1.0043733844945135, -0.6456590688403333, -0.5605045409451713, 0.0007420279838476089, 1.1288497487918525, -0.5147212144490231, -0.030800834148217614, -0.4458103103623281, 0.5690037780416535], [0.5132309563840618, -1.1597609489236753, 0.026652099595092276, 1.4452765990328926, -0.5467059964273097, 0.04575976672847036, 0.5753513093984138, 0.49642469501186604, -0.4761882121624422, 0.7764428578946042, -1.2118152529772015, 0.0992646950591631], [0.4766502025813064, -0.5277064414461843, 0.6230208372807454, -0.6455742247711411, 0.6632753578372919, 0.12821771906391594, 0.3492408808560265, -0.27539102495835954, 0.0378785678643285, -0.1293034843800858, 0.25946717738126057, 0.2601164703381125], [-0.8255179836248747, 1.3574906342788389, 0.10700769455837827, -0.28789079846918203, -0.7503757540082585, -0.35738540103370675, -0.19770874602259617, 0.08250522732175886, 0.6973788091622982, -0.22358427601701028, -0.3135776724726512, -0.11527964638586154], [-0.14446393493998266, 0.18398054765739674, 1.1817459100731127, -1.268150297105024, -0.25140476937879314, 1.1574642458149027, -0.5721396617736679, 0.38981176169021675, 0.0990651787132161, -0.25501973276925116, 0.5967325436567829, -0.31234998055308055], [0.08010494759904647, 0.40639165527172477, 1.6265081164557578, 0.2917643660732214, 0.45670318716936886, 0.030718272763109806, 0.3853721857537397, -0.4968161128166344, -0.11285406061606748, -0.09890940727062902, 0.49496115087392467, 0.26287576981590455], [1.3669475113156884, 1.0136294574508282, -0.4613137877952756, 0.48928753118791213, -0.948390689748237, 1.0554126765987701, -0.2440749915124633, 0.11853331194433553, -0.1849599955777192, 0.7884245464333771, -0.6527768059296715, 0.15383221275138698], [0.4749341569685498, -0.13582350327410103, -0.17641049426458655, -1.724171577524383, 0.7099967698564089, -0.0445843922452469, 0.26496885612045146, 0.18817538068085068, -0.5492862006284424, -0.45307566379668907, -0.4959087220957503, 0.29314429603602804], [-0.3270753053731849, 0.6968339424467946, -0.4174549447370487, -0.5890503530567606, -0.5614048521102927, -1.1736412600981005, 0.039538435178357215, 0.014015517881483038, 0.46579961925335966, -0.28877517220348975, 0.027453885197717694, -0.10117305954715027], [1.8785446968639563, -0.17745316626363355, -0.13818481645894726, 0.809164712166414, -2.6995653194557976, 0.025664057365333927, -0.2624720504205875, 0.06339886191869736, -0.5609209073290237, 1.010048272094205, -0.6180098390602123, 0.028253499534491404], [-0.07139810771671457, -0.9187540365280162, 0.5864512635433525, -1.958278365950453, 0.031861105944497474, 0.8394231829812081, -0.5886168726428832, 0.619524751491252, 0.4040634052052008, -0.06709315266348224, 0.4811098630070305, -0.3120642518492344], [-1.9097899942476537, -1.406985028891268, -0.013789490763174816, -0.12076496895278331, -0.5940337686972639, 0.29922116457754055, -0.3479576057701252, -0.22564207958390156, -0.1601581897958218, -0.3408229963390901, -0.09151036064397078, 0.25079233321312117], [0.03310725413469193, -1.380403501794169, -0.02440560493286593, -1.3677333930317372, -1.888213343942096, -2.2741237954031366, 0.24542035931110487, 0.09571021552922972, -0.2455269648227206, 0.03008392712545267, 0.35552693910921246, -0.5820301994093536], [0.6301397484299025, -0.2667298672427212, 1.7947069283280355, -1.5771599249676809, -0.4169607445640507, 0.20764281151241662, 0.007146855459271842, 0.123799191899776, 0.8609821585564845, 0.4517364193523267, -0.45164091673860246, -0.6059680108667804], [-0.3354149902163419, 0.31823821548182957, 0.1555000165360817, -0.7782808306052986, -2.131586397730612, -0.9585105563507893, -0.7928181648097645, -0.4569670926965658, 0.3674096998388646, -0.27916770658797446, 0.8528243253932334, 0.8314968820514745], [1.187371438675544, 0.5829386269110479, 1.2809311616228858, -0.7336478940685314, -0.25421506497767365, -0.8720366503025241, 0.1258166826992151, -0.31307501556015793, -0.24353239374126592, 0.8128553589383886, -0.2515819766715447, -0.22451297013293747], [0.12605541124367214, -0.06317995976692617, 0.4667544914941678, 1.500191920388472, -0.7985895388860614, 0.6124366908987685, 0.0006570349026536897, -0.9279362099182035, 0.4263558742810266, 0.07427511015347703, -0.1432638407678787, -0.5347453537653298], [-1.31960294594162, 0.9351751028468194, -0.33158163770869803, -0.22283508125050203, 0.052302163127393275, 1.4436984668405521, 0.5922521306994496, 0.41406477200820196, -0.34937475910259297, -0.11319659866864938, -0.5501644483971823, -0.07468298622514989], [-0.20320876998725698, -0.5805366443452988, -0.9998280868392793, 0.10639242898021047, -0.8093705828775378, -0.5129245352157267, -0.5752649802982598, -0.911978208343988, 0.1486656966599213, -0.1525414170604641, -0.2967641171552544, 0.4763190675639664], [-0.19842019914802161, 0.5278458846632978, -0.5768241986232568, 0.47836663378655336, 1.4735293391825828, -1.410642411113724, -0.23502797229233482, 0.5467473198760263, -0.8137513337203625, 0.37165684181231134, -0.12088353726728299, -0.10445848401516412], [0.9290285840071553, 1.9330301245406936, -0.46412480133157713, 0.42638417469520884, -1.2594443866334402, 0.2562472903639075, 0.20666279077824584, 0.14831839631810248, 0.12328122521543597, 0.06855342903286603, 0.26680346570598246, 0.3937831585495691], [-0.4407299276467436, 0.18188197393309796, -0.7588124372865978, -0.9299413549162413, -0.45728056193821587, -0.7071535601627623, 0.7120942370093657, -0.5562637983891908, 0.10464723592871006, -0.2108797791663641, -0.3699242265061823, 0.4222308488410234], [-0.6865961322661994, -0.3107605219986724, -0.9455401442474445, -0.3067713006933905, 0.3369186094728092, -2.178813696484406, 0.4224175078580513, 0.10228789982198314, -0.7460599025424266, 0.6403362567504826, -0.7223868653543898, 0.02196694179388069], [-0.035227134751608, -0.839117611224875, -0.966560612187026, -1.4513343818812168, -0.8352747349341343, -0.7673933168842653, 0.34150318832405174, 0.2754065287960639, -0.33817674288949484, 0.21277354812693627, 0.11200481209847378, 0.4385259277818457], [0.06998813561309204, -1.345605015918912, 0.9696754061649757, -0.966218376579938, 0.4926928137481371, 0.9000504671495908, -0.38360265086124584, 0.6707556620366639, 0.06549138002686952, -0.19761404367982593, 0.02183664442084462, -0.8219186140532913], [-1.1997282335487829, 0.8774809372608975, 2.0207889894687665, -0.5784023505555768, 0.44523254857746414, -0.15747336548573362, 0.35984838237890776, 0.33328887887513897, 0.2929254428076337, -0.7849931575417901, 0.5404339434577022, -0.296055463294898], [-0.08986421516963605, -0.25407271144925686, -0.34538294185630697, 0.5787060819949768, 0.7530245816380826, 0.005325801767899515, 0.41866667009998754, -0.23568449427999166, 0.22150315079567462, -0.19371608903961127, 0.3470565823536829, 0.38207285079716113], [1.1106864706058264, 0.997205131342783, 0.7769963255776343, -0.7493663391614792, 1.6666224652104622, 1.233774468785907, -0.2626699423209275, 0.4969356044038773, 0.5067436940043006, -0.4742447637121648, 0.5829265181466722, -0.3817719282122168], [-1.8442636874295149, -1.0654858846152553, -0.27145631100987816, 0.8286998157543778, 1.107713194799749, -0.21974876666188567, -0.4293429232465993, -0.04549555652497966, -0.24668551187360913, 0.15088966191137185, 0.034495530351933666, 0.31889855576595905], [0.11101850566227926, 0.6573179399947676, -0.979539324657381, 0.5115333063265783, -0.23165113317106797, 0.2200400319005484, 0.16243618424269624, 0.517585692204449, -0.37713576104783486, 0.8391898472241176, 0.28166839159204704, 0.6907522229206452], [-0.1210445532853056, -1.1152730930885382, -0.7213003077842319, -0.0012143113492643566, 0.15159750425788568, -0.18442574126279115, 0.44973957242914053, -0.16477029306913024, 0.18147214663128325, -0.3016466557171681, 0.4780708695787278, 0.1981724907883779], [0.7837561522872228, -0.33352080641868337, -0.9199071484319602, -0.3651914486941292, -0.11270004650316667, -0.06339582509458702, 0.04481340995276301, 0.48117049517787663, -0.39201873428091105, 0.46291803552144684, 0.3379588300226541, 0.2012921838518284], [0.8658648465136028, 0.49054696359485433, 1.1289056839529268, 0.5496464301060647, -0.10274386842877092, 1.0014399412204606, 0.22307228313419625, 0.6445082959146635, -0.42843901171504867, 0.2864351227072028, -0.18186852115402638, 0.3588203965155574], [-0.28892437260603504, 0.24425056218566463, -0.7224421799896549, 0.05956224417908162, -0.23888216086157324, 0.39868619417746226, -0.31217920507822383, 0.41011089357525177, -0.3191553838443233, 0.9197892098535075, -0.6669174878587081, -0.011823225524160593], [1.4004675357742782, 2.259474126620366, 1.10264420173686, -0.05994959691382904, 0.7641611769705088, 0.272140046743206, 0.12089656292402261, -0.42492218694890255, -0.14224164243366894, -0.18749495102375385, 0.28678876443543927, -0.5459092550926505], [-0.5655699453034309, -0.04508344990917687, -0.039864101832970816, -0.6007192385823187, 1.2477458761701672, -0.42751450284547593, 0.41440736174161974, -0.44781934931654, 0.05756096276984185, -0.1173838740151521, 0.19631905885064024, 0.17569965281978653], [-0.4750177114194872, 0.6820161473006974, -0.43981946870062455, -1.1145288966950946, -0.6918074357435268, 0.5036231864107539, -0.27876108790120796, 0.2736127401815393, 0.8769043147069251, 0.04331649374424834, -0.34588869766665203, -0.3446817100694798], [0.23506268855370044, 0.2998708551570366, -0.23107382904906168, -0.8899390525686575, 0.8382290066802895, -1.2491456961046614, 0.2658514262960994, 0.03744339511158934, -0.7935408761579319, 0.6003413154578441, -0.1735868873783401, 0.16140199806616948], [-0.24137353952046145, -1.2375984720496227, -0.17644838704999302, -0.17030647085352127, 1.1196162602482445, -2.5402091702481377, -0.3875242686597787, 0.2828526399291455, 0.2456635434320946, -0.34659019313824896, 0.35939686297472667, 0.930419785542342], [1.0433765426732355, -0.8161725156557211, 0.4598874618850827, 0.7381985683548445, -0.6079299883239175, -0.005372899273571312, 0.19138000708283662, 0.7880472530733744, 0.23423868614553064, -0.0030822869161906117, 0.27730816662607266, -0.07691523612056436], [0.3388484369785765, -0.08965522242291865, -0.46529615050352346, 0.16144614754582345, 0.15687448003331636, -1.2843877404603385, -0.016155379960169285, 0.21056653600776176, -0.48312328375218355, 1.0028774931882691, 0.3177945341030786, 0.30731224772534965], [1.0463507791090156, 0.24731672360566187, -1.979905684793349, -0.7940270080715022, 1.5619394605906205, 1.5298556612201835, 0.3579727909777407, 0.42417943476310366, -0.3129002827729045, 0.8502498370105608, -0.4401356988727337, -0.021432591846973454], [0.167220287114125, -1.558619318640114, -0.0058352991398978255, 0.9925656096097203, 0.41289545859126137, -0.21425220744961, -0.3257174264591695, 0.14989784462013434, 0.27447191338842136, -0.3332879614216883, 0.1124833291706821, -0.6562540041970397], [-0.6469605854565486, 0.8244618241319965, 0.02093409945248818, 0.30275038841771107, 0.5020379985641796, 1.584907042930301, 0.04715974512432515, -0.884294421005204, -0.0834313451661257, 0.44373823212194463, -0.2624731795005524, 0.09436589230279574], [0.10324929626879528, 0.2908461382436105, -1.3968878434298655, 1.0487277158695631, 0.8487857478517724, 0.08082433318568154, 0.20963891136356072, -0.055568420160200624, -0.30463451319770024, -0.5813176383679026, -0.19795352766290258, 0.2528462745903335], [-1.8905875366627738, -0.4884272771722829, 0.2834087025692537, 1.978772692327718, 0.5891829830586703, 0.8160017066235338, 0.8634937539529869, 0.6500969503218094, -0.47637012344367013, -0.07628787467698729, -0.05105223828714989, 0.09604712376217457], [0.6208223038222861, 1.311249002821266, -0.8100484067015237, -0.8056286074681512, -0.9543218055749995, -0.1689790824339431, -0.008984866131988303, 0.3701514548522272, -0.2538802611903832, 0.07175543835439774, -0.13976609814173419, 0.34275312378893985], [-0.33674313040618786, 0.13784060986569246, -0.7158977076919596, 0.08086233660949535, -0.6740201929802687, 2.013260892651801, -0.6688191401529071, 0.04172224083305499, -0.1987178117375332, 0.4626410232489475, 0.46135519711977985, -0.10631653728346498], [-0.48255729556606625, 2.456095915716291, 1.6824382397000077, -1.139972910885005, 0.9007053298727, 0.6378504869528357, -1.2639436414136465, -0.6301679984066076, -0.7386637747458968, -0.3748687862064184, -0.378971267778138, 0.31791418783617675], [-1.3019188608550951, 0.6129810924300696, 0.12336798267491027, 0.31815068848555933, -0.6770851646811109, 0.02641063402774826, 0.8078625581914507, 0.001460339492856592, -0.37192991136113435, -0.133966123588659, 0.0608180872330531, 0.05894166513485273], [0.28040252483539413, -0.13857764497817043, -0.34542100050950225, -0.16194794143326338, -0.7890937496544134, 0.3930337170422396, 0.32656470026727513, -0.5169063293457771, 0.26324267168824006, -0.322049789981567, 0.8245639193219525, 0.031128287147743284], [-2.1383038591824812, 1.4628053742238563, 0.25966894412687985, 0.4337740344245892, 0.8069928532579942, -1.0521810031175822, 0.23864210469726793, -0.021148271207597328, -0.5871425153527822, 0.8108615305597507, -0.965931116159263, 0.6085275678024874], [1.7948120404640842, -1.0314272402834985, 0.6233539152036579, 0.29259402924763744, 1.205409466754772, 0.07021097901945508, 0.24260173771420754, -0.30873379279633256, -0.20283155986184104, -0.5298819925409765, -0.9081759279865328, 0.10898161307604794], [-1.2061502885274553, 0.3370555914125006, -2.029034167394041, -0.2079962003592539, -0.34232230208032755, 1.4970611013507868, -1.0822673663870896, 0.293076544141285, 0.32718883732965715, -0.7612465364858378, 0.12964026291898037, -0.03040708812036621], [-0.29067807236256643, -0.40313357222426366, -0.4897894353432957, -0.8314718185286488, -0.4282228430304718, 0.6160174011740435, 0.5185273898593774, 0.561482077557646, -0.3831680705296265, -0.5502641617376242, 0.2327615404510708, -0.15140825072736272], [-1.1397658997494569, -0.17936539657032022, -1.1328517996535215, -0.18601459425359076, 0.19112984868742608, -1.0601996128601416, 0.04959973696941707, 0.21584657821216846, 0.7423464318088191, -0.5662854133404502, 0.23488431581995906, -0.49405978712297294], [-0.538143039212254, 0.11231664979858885, 0.8795435720457271, 0.8642936088066618, -0.05435893860425388, -0.8532796657326948, -0.40886082457193934, -0.04760546101647727, 0.34957681881966696, -0.6606656316114105, 0.2493992734681228, -0.247559642021358], [-1.3999760137708805, 0.7478902930692103, 1.4392361620347587, 0.3068409442145687, 1.403755988507213, -0.35824331232737994, -0.1762258887666674, 0.05859150253158224, 0.1536737931094852, -0.7313504022569917, 0.07625265230873293, 0.25279266037724296], [-0.3983545509848492, 1.4978164836240824, -0.7353242343183598, 0.5318999616295591, 0.3756007322635974, 0.19508584810019858, -0.20119447291152892, -0.36155159410467486, 0.45752069873974033, -0.3835126041835254, 0.4205564951907238, 0.08021712337721199], [1.3310077757180225, -0.8302484755122906, -0.21057822757076594, -2.018466734671665, -0.8758865199047778, -0.4140222062808428, 0.5154014198796968, -0.6526720297672036, -0.11291510360141366, -0.06035269028181146, -0.3973842988645363, 0.3049515392341099], [-0.3960730556534625, -0.188103463088928, 0.4474799461930175, -0.6727103615043568, -1.6900506514804419, 0.19410089720979715, 0.5328833307612214, -0.028459037007330063, -0.6445007219447336, -0.42237050219245265, -0.18258264960956416, 0.35837196015145173], [0.26368156555659733, -1.1002529174355018, -0.5360694327068934, 1.628021595834193, 0.9358397197855509, 1.0501732864663018, -0.04106913797931611, 0.49374945921200236, -0.404231355021536, 0.5257324055618051, 0.07804053130904968, -0.6372629567013882], [0.46666750888798536, 0.1449835515149036, -0.2855781271296468, 0.502013020093263, -0.13476898093753908, -0.34800988185918336, -0.37456735987504913, 0.527128600902663, -0.13817507624128741, -0.4481840002331628, -0.008607411683749833, 0.24347244476260704], [-0.08904745611741162, -0.07143330061382781, 0.9827921608273222, -0.9501066726748718, 2.2172992723666716, -0.8672902549573509, -1.0998661413674788, -0.027417663993651305, -0.4103695767160578, -0.5657442593118993, -0.3221396886727367, 0.03190578944116932], [-0.42871870820777885, 0.9044567415324837, -0.582199946333632, -0.4973168219218285, 0.06325113867575177, -2.6607384516615906, 0.5147893677977905, -0.6600264112762942, -0.08543670261547137, -0.23912040785828986, -0.16466920928933607, -0.5718958007735506], [-0.4940903654353489, -0.9142894122831646, -0.04699654528292772, 0.4336384024830125, 0.5987961082708882, 1.4314090298220064, -0.4750770938046204, -0.22762590574990557, -0.028565103261850966, 0.6713641638930897, -0.05576873279442399, 0.10582833876612222], [1.1001717646587585, 0.9927110155838862, 0.1426709601572695, 0.9520603589420743, -0.8303494088410479, -0.031191469545218908, -0.05731265148443447, 0.453194541119744, -0.7159253602895751, 0.7099869111657761, 0.47103341581885005, 0.7227417473715378], [1.099455006789031, 0.7632492786038755, -1.089325934125766, -0.599323267237271, 0.8352571137138366, 0.6248585004534758, -0.031585911683523864, -0.3288331493828357, -0.3631490868634143, 0.07097165292821211, -0.3065916698741633, 0.013349816430876267], [0.8067721638112678, -1.6760296637996872, -0.9672929040811368, -0.27042754515394973, -0.8073959041963394, 0.03599155313822546, -0.8637662174120541, -0.4796386829162201, 0.3419804806509989, 0.14436348653282452, -0.38203103438472197, 0.23085882624493687], [-0.05989167109911654, 0.3489357267214379, 0.07117548044473977, 0.5088571747957585, 0.736267005749064, 0.21230744186973693, 0.09580112774021882, -0.4142568148205606, 0.2709150221151191, 0.06436782541235037, -0.21857877145420082, -0.8351876233343601], [-1.0641792060794417, 1.2568039642178697, 0.39273402967851073, 0.38192354772710424, 0.20754499746693825, -1.4022933230946248, -0.25881318218018257, -0.7692047692007826, 0.09888612287078506, -0.5028337332494175, -0.030111471314989677, 0.02284499934357417], [0.41098059408372023, -0.6002489063478793, -0.9123501379041894, 1.200628703264972, -0.21083648659735588, 0.33812687583330636, 0.3682739561139498, -0.4740105445297784, -0.22035365277045815, -0.7938687819654539, -0.797287769253977, 0.48340679828556715], [0.6658338910385424, 1.5692104904962372, -1.4512737609467141, -0.7277988039154119, 0.6476216100469887, -0.5401868845310914, 0.3141487912744692, 0.12040543580328486, -0.15718345342999374, -0.509447415467928, -0.3686679212243807, 0.43980410250897023], [-2.7315444990068105, 0.1605798463005616, 0.39818789316926956, 0.7314187333877453, 0.25613756296705, -0.3322643558040159, 0.14014607225081496, -0.10460134759675524, 0.05170806817887912, 0.48598113384661096, -0.044851266700909935, 0.40958672429266935], [0.11030463921208049, -0.009961446048731806, -0.2651097260486428, 0.22069913725702187, 0.36645508538039523, -0.8567507857880907, 0.05119479574929732, 0.8673001882095043, 0.7099157667697769, -0.679095938308406, 1.0188363999680405, 0.5521638250870011], [0.7749413728663045, 0.8135439553976045, 0.9084107144772124, -2.630094536126905, 0.15759356804782165, -0.042036667778513434, -0.13047004624111536, 0.32634497323342465, 0.5759335826798753, -0.2790617834901279, 0.6454441941706898, -0.32460566730128615], [-0.8837888719797633, 0.5763742502281378, -1.1733036473095702, 1.1450352296892248, 0.3912695585109409, -0.3932141164889813, 0.09669704900801683, -0.31321934983553174, 1.1342672162666998, 0.11075978433077167, -0.4773776495966313, -0.4471561673794773], [1.0976489563619958, 0.4609053454473596, 0.4946505011172119, -1.262198447625251, 0.5129178430278065, 1.3586887648984551, 0.5653743907391484, -0.5524061436917286, 0.21308005680425327, 0.20865362344163377, 0.044452690613313854, -0.6782192495438064], [0.8329113274454183, -1.213217648751393, 1.4503170851804548, 1.4930383510369485, 0.7885967301460791, -0.2891072198170349, 0.5718399880139873, -0.3406206387844711, 0.43536108925652384, -0.24242508315131894, 0.2921803501589405, 0.6908500033858287], [-1.3023790684714691, -0.8574035450782412, -0.34620925847526707, 0.22027100271941183, 0.5211063253052797, -0.6283431385172162, -0.7506712787383826, 0.26739577980870777, 0.2323423737981017, -0.6402931269525604, -0.18262421624459763, 0.7580268723618856], [-1.4232751278245968, -0.3969172169610997, -1.0402334757746134, 1.2119360763927534, -1.0545920196540681, 0.4760443372734439, 0.42127714923591675, 0.38177230056827005, -0.3162764594919593, 0.768688489702012, -0.9873717129469991, -0.21030028178802945], [0.5761834025972374, -0.9561670982505858, 1.0626910871797726, -0.20538531573207325, -0.685967759116225, -0.8471876542227992, -0.3404585385541718, 0.6327368412244334, 0.3673785530014807, -0.8145978316454063, 0.5780433346463157, -0.45878456103254706], [-0.022322796004316012, 0.9914087599716409, -1.5882578390937194, 0.5008596308503561, -0.13395622258633164, -0.682110464837002, 0.14269146017269418, -0.8439836937803548, 0.16304069426929566, -0.27428435958153746, 0.07814621550552113, -1.195392832346052], [-0.20474950779057577, -0.05039456864018707, 0.08021942784975818, 0.6859942854577231, -0.793195433319163, 1.8232531273401644, 0.14112608348665673, -0.024738831780784766, -0.11193434119038566, 0.07911716963430547, 0.5952563852409543, -0.8216432095070764], [0.6158897364532788, -0.6054506494000433, -1.614046940914975, -0.09883015357930501, -0.35281461432471234, 0.7034730777018787, 0.6987366186256377, -0.5778462533160409, 0.8849446396145533, 0.20655901195985032, 0.5004704058335896, -0.03199546798310232], [0.48437247604323014, 1.804647049882941, 0.032580019334281424, 0.6869665445393548, -0.3541321095499742, -0.30802553550352074, 0.30168295068263706, 0.2648102497551823, -0.48028490476615204, -0.7127354173354662, -0.6933861944061229, 0.48104153386731313], [1.1594594096984896, -0.14349589649333003, 0.06377298584504268, -0.39092361265756725, 0.3134561740868025, 0.5915643099205157, 0.17060424521729192, -0.4164908711687399, 0.20441549150791816, -0.0379526220461216, 0.4764813680732421, 0.08514339909522395], [-0.18504508536109954, -1.0961310840786516, 0.48119406088907574, -0.8264101670345597, -0.27599045539838685, 0.25220225265896784, 0.11370697767817438, -0.22480266758710735, -0.634843452068008, -0.02960677917705086, 0.1903851896628838, 0.5479953366261093], [0.12502555783709834, -2.2120886207580246, 1.7273650330637995, 0.7227603316605362, 1.7401895733273047, 2.371188150136259, -0.12848359354052244, 0.28890173754140447, -0.04044777388711384, -0.3837634083912619, -0.23457613371130653, -0.31310597009683544], [-0.8489757713163557, -0.5355093431501304, 0.3982381355783371, 0.844690126546196, -0.41824642284936664, -0.24567330097307058, 0.37589023962712864, -0.22756702997422845, 1.428669373373487, 0.13567280037395058, -0.2806172820962536, -0.5622817769200061], [0.7886154689925989, -0.8581258544193535, 0.35314624905623054, 0.9715404643552469, -0.21236847919774635, 0.7445040165843596, -0.7465299961555039, -0.2371099539130954, -0.15150750181241754, 0.53512069474752, 0.250438996877687, 0.506793973226362], [-0.19947704566912997, -1.5444819422679414, -0.3527932477924322, -0.27430441967320196, -0.2980736267830553, 0.03006791400295169, 0.8305706907436655, -0.2030655178507016, -0.31222433851470216, -0.3479233483028622, -0.9105028183475287, 0.4967752899436179], [0.19821936332937798, 0.22298938063489185, 0.2794477870336998, -0.5184835630324054, -0.21992393275430122, -0.3610433418249893, -0.6467257652287974, 0.00467069852978898, 0.2918450827992425, -0.2185375316637334, 0.1520555609125973, -0.6357832484816373], [-0.6300309026295533, 1.2327905002994555, -1.6329690172342999, 0.08848699819822921, -1.484139745808929, -0.594405802379562, -0.29258418444830125, 0.3610124852372, -0.39271866379292386, 0.3319891409108107, 0.8489436850778788, -0.4054655843701148], [0.4801581371786685, -0.3804025369117391, 1.3327204813020632, -1.0646434321639509, -0.3393052052646003, -0.6547692292126653, -0.38430472100941887, 0.14821345827386298, 0.0033203469406502036, -0.34056772404013536, 0.022709839055040558, -0.5359310228562532], [-0.19078061123322262, -0.44040921765702806, -0.3120816586657676, -0.11485330098889675, 0.8553781703695563, 0.03053328914624032, -0.3966966789788946, 0.6263596025532567, 0.04035186772567129, -0.3369926276976134, -0.09753871914792646, -1.0142882384104008], [-0.1837286068831958, -0.45353904616578744, -0.6433474506634336, -1.6038844351231853, -1.0592039922819585, -0.11153271983291549, -0.6259378228071343, -0.16097235384672096, 0.3444932597468543, 0.2818191628431615, 0.45449847968904056, -0.5457980098859988], [-1.8202271601163293, 0.415026598219147, -0.411820186142823, -1.1498099180690327, -0.6437906135043254, 0.43895032061471945, -0.7309921065263967, -0.010410564280765429, -0.08996749881045903, -0.5629753796401717, 0.44578945292683403, -0.1717127702537174], [0.026461925530767934, 0.032246339139551425, 1.566104524081326, 1.9731336686053191, -1.2568214786021092, 0.6891203717865935, 0.2447181791804787, -0.33320194499866496, 1.047113471962386, -0.12182435060592219, -0.055982920695865517, -0.7909611401153466], [-0.8467576994261583, -1.4621346435593785, -0.4379997220867365, 0.7916841915590164, -0.3409238734735808, -0.48281865870232626, -0.2697933481664625, -0.07743768504828877, 0.12626857080803058, 0.600784417894271, 0.12228449801796934, 0.9220590181518379], [0.9890372822275783, 0.4115543376686053, 0.04197490451137038, 1.6249188980439822, 0.42624016615646654, -0.6404973457677912, -0.94067669281314, -0.4787629419055365, 0.05500645584874758, 0.4780675083556097, 0.016155295746282886, 0.6909000175092361], [-0.9875565340486336, -0.41158612850481674, 0.3215293787998726, 0.8486160463716964, 0.7786761385242379, 0.1649275307540971, -0.5989399268728774, 0.025992293557896888, -0.23610176399937818, -0.08094553757737319, 0.055027317154144474, 0.33321736211660524], [-1.0304025151647642, 0.8997824196089343, 0.26810591521723187, -1.0704180848374074, -1.0386413986539287, 0.25678149730278943, 0.8749516363942026, -0.7269571488118866, -0.04081728358417425, 0.10859595343120097, -0.15822071554849834, 0.016241090820470854], [0.1996263796408301, 0.7740587602068933, -0.9387750122359109, 1.7680503004361852, -1.5647197536283717, 0.0028079702403296146, 0.7636748588846405, -0.3652830614818029, -0.56958625817822, 0.29293005120402066, 0.042621255162037706, 0.04251158864331522], [1.0006932852581025, 0.9797944428365786, -0.7128844654514443, 0.5155787828802958, 1.0934529107608522, 0.7053304710505881, -0.2606257095715466, 0.7051708712316562, -0.2231196385310904, 0.49548048441129244, 0.28131575178486473, 0.6578996637193999], [-0.9090590418165249, 1.5667721057748172, -1.3345616245394756, -0.036942846706886835, -0.9365537290715337, -0.38064340732596746, 0.01045949011268095, 0.6287595044218933, 0.05601930316179588, 0.1945469887402697, 1.1300757896469302, 0.26091872203602196], [-0.3919242856079404, 0.4303165500849276, -1.0228270769343215, 0.1120330632470712, 1.1231199381317245, 0.07204428873333094, -0.30210993692224464, 0.5604169829086942, -0.5204024772713663, 0.2853693947808579, 0.07588722229769539, -0.6259450190317919]], "0.5": [[0.47575109422028233, -0.39627293861113966, 1.0639493209367747, -0.5352447564766708, -0.141638348149211, -1.2690491079229524, -0.3073989041861183, -0.07638847121393673, 1.5103149336173873, 0.5496221603423679, -0.5313462807522744, -0.27352463356870327], [0.48141900611364485, -0.0014302288315438789, 0.9031722543094283, 0.4977689980168151, 0.09977941161608761, 0.16365468337089933, 1.1151580313593008, -0.9196722647640317, 0.30531038875780087, -0.176685475648551, 0.40896960150217687, 0.12691184075355275], [0.7092641407060124, -0.11085674061217893, 0.039190832731179154, 0.028788696705244674, 0.5941193396175982, 0.7191726871304824, 0.4242310759722523, 0.4796396016754721, 0.177183284002124, -0.10017231249944163, 0.5509217757980844, -0.6884735695904948], [1.1794184536924064, -0.039032404827950395, 1.059053288533282, -0.4975528756667894, 0.46785222556865524, 0.1590937739105817, -0.1610023912158405, -0.9990973001282404, -0.178916574297759, 0.20840129157990456, 0.26224434434117355, -0.42941469182737024], [1.0750574435173128, 0.4908507420063667, -0.14982467511203765, 0.43158652928517377, 0.29935020788970806, -0.1516353375172138, -0.08454469691288749, -0.2178657049030698, 1.8645590326587989, 0.2003739145960569, -0.9015871792468426, -0.34684110212859937], [-0.2222315331160852, -0.6674092716958044, 2.139592571276783, 0.10536238625589292, 0.734268293457598, -0.7593559764633477, 0.21897565889363924, -0.9833146033479098, 1.062388300594016, 0.8499476484445704, -1.1110589541390226, -0.41788519912942795], [-0.7279358441601032, -0.07269493852761146, 0.06984728936547491, 0.6043302947772976, -0.6240670519940024, 0.46874480953274617, 0.388636963849024, 0.1889707770147836, -0.8286486678957893, 0.896883247245519, 0.8509665257637861, -0.5743007809620614], [0.942588880167842, -0.6419036454368886, 0.8252461150563811, -0.7093282226560405, 0.3042406851513924, 0.34219887727814075, -0.7229656360318797, -0.8510472355537206, 0.03768648414811096, 0.6007180218600578, -0.644712104313455, -0.07586540138807242], [1.0855648922508137, -0.4742227314141819, 0.2968789257956057, 0.7849758313783822, -0.7391875367994739, 0.07421181618597655, 0.1833923596598706, -0.2721230402502303, -0.08055911842424654, -0.6489450930584229, -0.3060308949610399, 0.1649312019848627], [-0.5883486741232955, -0.48290533114559003, 0.6627070016501314, 0.5288616010426653, 1.837671371039526, 1.0711625712026807, 0.40396992183929376, 1.8181093097384202, -0.19472525970376875, -0.09275052281773385, 0.8727962000257845, 0.3736357034372884], [0.7974153891333279, -0.08235161393148653, -0.03824924196594545, 0.10769424309467462, -1.4990010276454282, 1.2706658795498644, 0.6434864161207314, -0.7522660688155606, -0.635703454542945, -0.6255459984139307, -0.7393385679426927, -0.13624188011105123], [-0.4633110492980349, -0.7554119490628315, -0.15501176375751685, 0.6525498695231355, 0.9135054455467817, -0.1991750557768278, 0.038279249669375195, 0.08295035903636556, -0.3164264639064447, -0.07057121677781651, -0.2675751550628272, -1.5362467574116734], [0.24128465917282094, -0.011071502176748873, -0.5452339251086606, 0.12010197652480192, 0.07205658214779259, -1.0400462013092602, -0.03510952487484702, -0.36755469138820057, 0.011721363333546205, -0.11873936699157268, 0.9675389647813322, 0.7883916233996873], [0.6628681582202032, -1.1509834096068574, 0.32685046958253683, -0.7940268790636766, -0.510438312369726, -0.443117747063462, 0.0011732492582705383, 1.7848681711455812, -0.8138456988334417, -0.04870039487072996, -0.704887992565761, 0.8996739679262639], [0.4057446969700427, -0.9168715349792549, 0.021070334786535756, 1.1425914754714621, -0.4322090397955438, 0.036176272014989526, 0.9097102962296149, 0.7849163614959626, -0.7529196726784059, 1.2276639519586994, -1.916048151370549, 0.156951263814509], [0.37682507183439945, -0.41718857272805543, 0.49254121888807506, -0.5103712372435749, 0.524365211657264, 0.10136500715839168, 0.5521983177742696, -0.4354314430183465, 0.05989127447826895, -0.20444676001853815, 0.4102536292898533, 0.4112802515960321], [-0.6526292694210469, 1.073190576666944, 0.08459701049202027, -0.22759766014178287, -0.5932241209080799, -0.2825379674398021, -0.3126049753835799, 0.13045221860335593, 1.1026527144443816, -0.3535177806067562, -0.495809834193931, -0.18227312521906022], [-0.11420876854018136, 0.14544939394063242, 0.9342521728548887, -1.0025608385677778, -0.19875292146658524, 0.9150558317460272, -0.9046322354615813, 0.6163465128319263, 0.1566358007726957, -0.4032216019191565, 0.9435169959506483, -0.4938686828285172], [0.06332852156535583, 0.32128081318615614, 1.285867570187648, 0.2306599842166343, 0.36105557152834833, 0.024284926929435235, 0.6093269269296551, -0.7855352473858682, -0.1784379373727392, -0.15638950449620304, 0.7826022950299214, 0.4156430871442001], [1.0806668944140911, 0.8013444472463374, -0.36470057136816414, 0.38681575731861845, -0.7497686728256326, 0.8343769823667013, -0.3859164465328248, 0.187417622173671, -0.2924474310201319, 1.2466086649573278, -1.0321307552337349, 0.24323008489899017], [0.3754684186581369, -0.10737790753237411, -0.13946474125804104, -1.3630773154756575, 0.5613017310271581, -0.03524705689733215, 0.4189525471750366, 0.2975314012603673, -0.868497740643045, -0.7163755249951147, -0.7841005366830203, 0.4635018292802588], [-0.25857573284359336, 0.5508956022616393, -0.33002711146719865, -0.4656851930464227, -0.44382950553462786, -0.9278448844650224, 0.0625157551412673, 0.022160479546152134, 0.7364938650399182, -0.4565936379351862, 0.04340840392278501, -0.15996865300841925], [1.4851199821301675, -0.14028904585040838, -0.10924468951564918, 0.6397008731701069, -2.134193775470096, 0.02028921881891881, -0.4150047507318062, 0.10024240236279823, -0.8868938271839747, 1.5970265432675887, -0.9771593539121826, 0.04467270519974994], [-0.056445160252715516, -0.7263388412255173, 0.46363043237016566, -1.548154982259039, 0.025188415889135576, 0.6636222947422271, -0.930684993378383, 0.9795546407810767, 0.6388803397859851, -0.10608358890899824, 0.7607014859369011, -0.4934169060799965], [-1.5098215586056134, -1.1123193312635549, -0.010901549646371486, -0.09547309086257866, -0.469624929034247, 0.23655510104828067, -0.5501692817062714, -0.35677145373105373, -0.25323233284216734, -0.538888473697377, -0.14469058456919023, 0.3965374963306787], [0.026173582534913375, -1.0913047889354754, -0.019294324815524285, -1.0812881884626402, -1.492763718794981, -1.7978527186651663, 0.38804365980000183, 0.15133113820899194, -0.38821221791391847, 0.04756686533947626, 0.5621374485665531, -0.9202705485677731], [0.49816921231100086, -0.21086847512033374, 1.41884040650029, -1.2468543993095338, -0.3296364119255179, 0.1641560560350672, 0.011300170679653885, 0.19574370944577993, 1.3613323229033605, 0.7142579936011588, -0.7141069907102249, -0.9581195517703448], [-0.2651688326116834, 0.25158939985751017, 0.1229335571119662, -0.6152850209901067, -1.6851670115655761, -0.7577691298459164, -1.2535555855768055, -0.7225284143332216, 0.5809257429648058, -0.4414029009917963, 1.3484336561195953, 1.3147120073055198], [0.9386995437114155, 0.46085344928250915, 1.012664999153396, -0.5799995864606237, -0.2009746552142876, -0.6894055045249343, 0.19893364248811066, -0.4950150638313776, -0.3850585241276675, 1.2852371712595079, -0.3977860322647141, -0.3549861749347194], [0.09965555272980059, -0.049948143835321916, 0.3690018253088147, 1.1860058489523913, -0.6313404646158899, 0.48417371647415575, 0.0010388633973063344, -1.4671959733428253, 0.6741278282602243, 0.117439260772443, -0.2265200215850914, -0.8455066430454699], [-1.0432377290608918, 0.739320834019541, -0.26213830136206523, -0.17616659983506708, 0.041348490509059525, 1.1413438524273045, 0.9364328410489964, 0.6546938891921252, -0.5524099978684195, -0.17897953758845786, -0.8698863722926343, -0.11808416946722716], [-0.16065063842024935, -0.4589545153305636, -0.7904335057551859, 0.08411060034379261, -0.6398636282577745, -0.4055024497662355, -0.909573797937195, -1.4419641574032886, 0.235061105690519, -0.24118915771036667, -0.4692252690098265, 0.7531265732348821], [-0.15686494077298743, 0.4172988122706405, -0.45601956928771337, 0.3781820298482915, 1.164927227724939, -1.1152107457877471, -0.37161185314736167, 0.8644834177004466, -1.2866538317780631, 0.5876410640559028, -0.1911336546912304, -0.16516336520810465], [0.7344615842159224, 1.528194494816884, -0.36692287269523344, 0.33708628757199766, -0.9956782120188488, 0.2025812704491162, 0.32676256323304936, 0.2345119756343678, 0.19492473220847994, 0.10839248857928532, 0.4218533196287644, 0.6226258426159227], [-0.3484276010912309, 0.1437903257389908, -0.5998939046723318, -0.735183192979586, -0.3615120263616158, -0.5590539764028098, 1.1259198488146824, -0.8795302914032728, 0.16546180818786482, -0.3334302073195172, -0.5849015587177838, 0.6676055903619501], [-0.5428019026558542, -0.2456777640946665, -0.7475151187365202, -0.2425240077408763, 0.2663575480077148, -1.7225034695153816, 0.6679007241817584, 0.16173137025629922, -1.179624281478657, 1.0124605198589474, -1.142193923154625, 0.03473278464850401], [-0.027849495314187785, -0.6633807190575695, -0.7641332577794263, -1.147380573314314, -0.6603426585963194, -0.6066776856364066, 0.5399639516567118, 0.4354559567381563, -0.5347043796139777, 0.33642451895828607, 0.17709515756518035, 0.6933703724145714], [0.05533047943152898, -1.0637941703127232, 0.7665957186325507, -0.7638626967757242, 0.3895078695603086, 0.7115523713228162, -0.6065290465999442, 1.060557822744997, 0.10355096399628355, -0.312455237832126, 0.03452676641253871, -1.2995674358486398], [-0.948468447806147, 0.6937095912809369, 1.5975739693278288, -0.45726720793769504, 0.35198723548658695, -0.12449362643676644, 0.5689702503222744, 0.5269759880247085, 0.4631557919427552, -1.24118316273972, 0.8545010930964966, -0.4681047888741279], [-0.07104390001987612, -0.20086211486859798, -0.2730491903088585, 0.45750732872407135, 0.5953182030179371, 0.004210415988278474, 0.6619701289571378, -0.37264990555484995, 0.35022723270903483, -0.30629203039257574, 0.5487446385957194, 0.6041102203163545], [0.8780747533620171, 0.7883598773626393, 0.6142695306017675, -0.5924261084031267, 1.3175807474174492, 0.9753843600819458, -0.4153176452995929, 0.7857241801743263, 0.8012321314905005, -0.7498468108694053, 0.9216877529274795, -0.6036344199324498], [-1.4580184645545284, -0.8423405525358914, -0.21460505700456436, 0.6551447285864302, 0.8757241724472477, -0.17372665391610875, -0.6788507673670541, -0.07193479101793547, -0.39004404164255785, 0.2385775035063454, 0.05454222250379006, 0.5042228893793262], [0.08776783508027562, 0.5196554593183382, -0.7743938309051144, 0.40440258675715185, -0.18313630084488963, 0.17395691930546048, 0.25683415831683665, 0.8183748358404581, -0.5963039960060842, 1.3268756532584713, 0.44535683115354474, 1.0921751616268023], [-0.09569412168479573, -0.8817007968151935, -0.5702379623946633, -0.0009599974130668995, 0.11984835026299819, -0.14580135038882955, 0.711100701393175, -0.2605247084159537, 0.28693265761745373, -0.4769452403194515, 0.755896415423041, 0.31333822024000574], [0.6196136428493528, -0.2636713488347863, -0.7272504562288963, -0.28870918997249295, -0.08909720983922537, -0.05011880036113862, 0.07085622258479489, 0.7607973538165782, -0.6198360428920046, 0.7319376811092518, 0.5343598291186409, 0.31827088808057163], [0.6845262652137722, 0.3878114260598598, 0.8924783062003614, 0.4345336567289273, -0.0812261599628954, 0.7917077885304495, 0.3527082487790122, 1.019057092982066, -0.6774215577455586, 0.45289369481228803, -0.28755938076661897, 0.5673448619569536], [-0.2284147722425574, 0.19309702407082371, -0.5711406916361573, 0.04708808853925098, -0.18885293017632557, 0.31518911131623545, -0.49359866309399514, 0.6484422584723553, -0.5046289702266838, 1.4543144351918362, -1.0544891365156044, -0.018694160973092813], [1.1071668005425153, 1.786271138585011, 0.8717167815666672, -0.04739431776417521, 0.6041224546754539, 0.21514559756330473, 0.19115425006288875, -0.6718609695492032, -0.22490378410682496, -0.2964555475083906, 0.45345285148074077, -0.8631583209293251], [-0.44712230082392296, -0.03564159662277754, -0.03151533966727024, -0.4749102570505563, 0.9864297274450352, -0.3379798904365599, 0.6552355711224203, -0.7080645620674172, 0.09101187333242734, -0.18560020123106752, 0.3104076870343305, 0.2778055435056756], [-0.37553447425153863, 0.5391811066207756, -0.3477078200947777, -0.8811124579077524, -0.5469217997975315, 0.39814908788238557, -0.44075998039711195, 0.43261972790676845, 1.3865074622514857, 0.06848939024212995, -0.5468980507679942, -0.5449896358106752], [0.1858333721881211, 0.2370687265496712, -0.18267990186285374, -0.7035585962123196, 0.6626782154825527, -0.9875363822718125, 0.42034801315002784, 0.05920320594111844, -1.2546982925523353, 0.9492229651742191, -0.2744649680273447, 0.25519896639559386], [-0.1908225379453312, -0.9784075001052607, -0.13949469813523413, -0.1346390870405519, 0.8851343719360726, -2.0082116778076355, -0.6127296687779538, 0.4472292921837937, 0.3884281676565586, -0.5480072124972644, 0.5682563354597873, 1.4711228511996015], [0.8248615830098233, -0.6452410282753785, 0.36357296172768355, 0.5835972103692014, -0.48061085525578706, -0.004247649835787369, 0.30259836050046024, 1.2460121117754948, 0.370363882172602, -0.004873523528649429, 0.4384627101519401, -0.12161366645531835], [0.26788321061008136, -0.07087867674635571, -0.3678489055249091, 0.1276343864261014, 0.12402016591497171, -1.0153976646629679, -0.025543898569787626, 0.33293492639819283, -0.7638849836583596, 1.585688546297465, 0.5024772778588918, 0.48590332783900203], [0.8272129233690548, 0.19552103751105557, -1.5652528790655962, -0.6277334672987123, 1.2348215656902921, 1.2094570951896777, 0.5660046799285171, 0.6706865752271066, -0.4947387870365624, 1.3443630325701512, -0.6959156439939214, -0.033887903198595554], [0.13219924456698498, -1.2321967630106234, -0.004613209027624664, 0.7846920133800569, 0.326422521172031, -0.16938124231491572, -0.5150044706096845, 0.23700930267482087, 0.4339782000259376, -0.5269745374034328, 0.1778517594889071, -1.0376286884341723], [-0.5114672515996749, 0.651794302028571, 0.016549858758586618, 0.23934519747515687, 0.39689588685378757, 1.2529790338255045, 0.07456610423294405, -1.3981922462781442, -0.13191653948831822, 0.7016117492009182, -0.41500653596398096, 0.1492055765554931], [0.08162573575472944, 0.22993406137850342, -1.1043368052597622, 0.8290920568734328, 0.6710240521752427, 0.06389724580777163, 0.33146822305350354, -0.08786138684172631, -0.4816694578006785, -0.9191438906363297, -0.31299200913996006, 0.3997850627969057], [-1.4946406829453642, -0.38613566680469485, 0.22405425220801395, 1.5643571698747953, 0.46579004626944953, 0.6451059918787182, 1.3653035039102308, 1.0278935314731252, -0.7532072996687857, -0.12062172091638097, -0.08072067631852346, 0.1518638368982761], [0.4908031255778705, 1.0366333571349384, -0.6403994950418046, -0.6369053369472738, -0.7544576315953432, -0.13358969435415233, -0.014206320724395047, 0.5852608382790114, -0.40141993916003105, 0.11345530985185064, -0.22098960490125363, 0.5419402731553458], [-0.2662188196246638, 0.1089725703105661, -0.5659668320000092, 0.06392729015230572, -0.5328597496909709, 1.5916224862308601, -1.0574959127992813, 0.06596865505926737, -0.31420044836757355, 0.7314996862487934, 0.7294666166272294, -0.16810120537897996], [-0.3814950388799603, 1.9417143113751067, 1.330084215004087, -0.9012277173221925, 0.7120700857627575, 0.5042650863546188, -1.9984703704771236, -0.9963830917571193, -1.1679299766272988, -0.5927195940574966, -0.5992061869702474, 0.5026664670224579], [-1.0292572322584832, 0.48460410367430445, 0.09753095389822711, 0.25152020369126843, -0.5352828225756263, 0.02087943949420779, 1.277342860127651, 0.002308999477261011, -0.5880728249228604, -0.21181903992188628, 0.09616183929562779, 0.09319495545453513], [0.221677660035444, -0.10955524772830329, -0.27307927831605233, -0.12803108932616647, -0.6238333840776629, 0.3107204357739036, 0.5163441281273936, -0.8173006688448949, 0.41622320994138035, -0.5092054281603139, 1.303750030726346, 0.049218143523307535], [-1.6904776311361482, 1.1564491890205868, 0.20528632526298582, 0.342928484655497, 0.6379838679433236, -0.8318221201530717, 0.37732629822986696, -0.03343835279548359, -0.9283538298175864, 1.2820846517895197, -1.5272711949459727, 0.9621665666292025], [1.4189235049401998, -0.8154148300094076, 0.4928045401067555, 0.23131589054711432, 0.9529598570185235, 0.0555066526129434, 0.3835870277458336, -0.48815098794944795, -0.32070485526410264, -0.8378169937689188, -1.43595222428725, 0.1723150601997503], [-0.9535455280540044, 0.26646584173964794, -1.6040923548171313, -0.16443543444899372, -0.27062954211150786, 1.183530719177166, -1.7112149575275801, 0.46339470412866873, 0.5173309754720203, -1.2036364581048593, 0.2049792536435234, -0.048077827736902695], [-0.22980119363323787, -0.3187050723771663, -0.38721254739314726, -0.6573361891981808, -0.33853988252226297, 0.48700451650191506, 0.8198637905688645, 0.8877811152227368, -0.60584191476283, -0.8700440329270844, 0.3680283097573999, -0.239397464420156], [-0.901064060649855, -0.14180079664539144, -0.895597984581469, -0.14705744896835388, 0.15110141267390254, -0.8381613877666977, 0.07842407008430764, 0.34128340615206365, 1.173752768707369, -0.8953758559428614, 0.3713847123206954, -0.7811771138032614], [-0.4254394277190068, 0.08879410813075822, 0.6953402472562251, 0.6832840927389039, -0.04297451429467414, -0.6745768062056108, -0.6464657258309334, -0.07527084293721137, 0.552729482333081, -1.0446040838428978, 0.3943348754752346, -0.3914261627617108], [-1.106778218279809, 0.5912591915073865, 1.1378160907272488, 0.24257906577867566, 1.109766550695985, -0.2832162058693993, -0.27863759559507506, 0.09264129976566078, 0.24297960145173125, -1.1563665194062214, 0.12056602946224648, 0.39970029128274387], [-0.3149269243514486, 1.1841279012990984, -0.581324849791342, 0.4205038415263933, 0.2969384511950147, 0.15422890481556498, -0.31811639351874005, -0.5716632645177395, 0.7234037423446541, -0.6063866703012804, 0.6649582047901682, 0.12683440860936407], [1.052254038665877, -0.6563690516253426, -0.16647670619122157, -1.5957380657113056, -0.6924490936843765, -0.32731329343388343, 0.8149211980523141, -1.0319650895747898, -0.17853445480717428, -0.09542598210461682, -0.628319745400499, 0.4821707199769934], [-0.31312324392189295, -0.1487088447816061, 0.3537639593048819, -0.5318242369872556, -1.3361023549324045, 0.15345023276629513, 0.842562526171164, -0.04499768847909252, -1.019045117484112, -0.6678264016986463, -0.28868851699733783, 0.5666358218088443], [0.20845858103946296, -0.869826305335343, -0.42380009783703637, 1.287064080694536, 0.739846259844021, 0.8302348807744986, -0.06493600877718204, 0.7806864422931669, -0.6391458917620982, 0.8312559206673393, 0.1233929143731394, -1.0076012058148247], [0.3689330595207262, 0.11461956151186278, -0.22576933291370188, 0.3968761396386464, -0.10654423442560952, -0.2751259687302831, -0.592242997180559, 0.8334634993351524, -0.2184739783949429, -0.7086411257911153, -0.013609512839697198, 0.38496373646968607], [-0.07039819529372872, -0.05647298268079997, 0.7769654236932126, -0.7511252764441645, 1.7529289887281823, -0.6856531495333423, -1.7390410640109875, -0.04335113317056324, -0.6488512724309717, -0.894520216295263, -0.509347570471696, 0.05044748258992295], [-0.3389318983654263, 0.7150358370842148, -0.4602694710105185, -0.3931634689973337, 0.0500044157036355, -2.103498441310113, 0.8139534587395781, -1.0435933877500663, -0.13508728801967723, -0.37808256193031076, -0.26036488092662946, -0.9042466573651528], [-0.3906127311801587, -0.7228092458478822, -0.03715403131332349, 0.3428212581907837, 0.473389889045199, 1.1316281993923563, -0.7511628402980344, -0.35990815831425976, -0.045165393952677116, 1.0615199486583702, -0.08817810892585334, 0.16732929574641978], [0.869762148432104, 0.7848069668959968, 0.11279129751502656, 0.7526698010536026, -0.6564488464280166, -0.02465902183266703, -0.09061925871712162, 0.7165634865466133, -1.131977386595861, 1.1225878740957427, 0.7447692240183763, 1.1427550408920364], [0.8691955015823067, 0.6034015357171668, -0.8611877665319905, -0.47380664480088647, 0.6603287277984964, 0.493994019187585, -0.04994171144642946, -0.5199308611080765, -0.5741891223493607, 0.11221603628005447, -0.4847639942183927, 0.021107913133354396], [0.6378093976165191, -1.3250177909033178, -0.7647121853537935, -0.21379174618362776, -0.6383025076878833, 0.028453821110943377, -1.365734306465141, -0.7583753459692739, 0.5407186170881493, 0.22825871420338484, -0.6040441027629122, 0.36501985444352875], [-0.0473485233867221, 0.2758579133614555, 0.05626915794053799, 0.40228691901825586, 0.5820701760498322, 0.1678437701280415, 0.1514748830359156, -0.654997535539784, 0.4283542611193318, 0.10177446816754705, -0.3456033829783346, -1.3205475816596852], [-0.8413075324501852, 0.9935907748143071, 0.310483512110065, 0.3019370757174184, 0.16407872724235043, -1.108610212156353, -0.4092195720827402, -1.2162195288693047, 0.15635268862747453, -0.7950499407168496, -0.047610416527096425, 0.03612111553537295], [0.32490868785841936, -0.47453842677110014, -0.7212761148364896, 0.9491803316229379, -0.16668087787880212, 0.26731276643754803, 0.5822922521204869, -0.7494764778253836, -0.34840971674626, -1.2552167571572184, -1.2606226507186669, 0.7643332594959856], [0.5263879097535424, 1.240569819549529, -1.1473326482575847, -0.5753754746797435, 0.5119898374234675, -0.4270552293171566, 0.4967128523080766, 0.19037770990178285, -0.24852886166489305, -0.8055070904823739, -0.5829151656542876, 0.6953913441072603], [-2.1594755367412666, 0.12694951515738448, 0.3147951697796736, 0.5782372802051798, 0.20249452332516849, -0.2626780374073194, 0.22159039671954792, -0.16538925236436328, 0.08175763442626646, 0.7684036414132185, -0.0709160793592707, 0.6476134740661268], [0.0872034740983238, -0.00787521457571929, -0.20958764104424557, 0.17447798784157878, 0.28970818248838, -0.677320967557346, 0.08094607945744302, 1.3713220049173733, 1.1224753849286855, -1.0737449574118783, 1.6109217934926552, 0.8730476644128723], [0.6126449478388324, 0.6431629689297164, 0.7181617271622214, -2.079272298931257, 0.12458865490596294, -0.03323290385597824, -0.20629125627470726, 0.5159967091821533, 0.910630951124654, -0.4412354218687883, 1.0205368780556772, -0.5132466250354534], [-0.6986964515417544, 0.455663853848185, -0.9275779781202832, 0.9052298317380012, 0.3093257459957733, -0.3108630540589881, 0.1528914589411293, -0.4952432763586832, 1.7934339393307805, 0.1751265958171335, -0.7548003383915579, -0.7070159793553168], [0.867767693352669, 0.36437766934009375, 0.3910555573185134, -0.9978554884061349, 0.405497159127146, 1.0741377820900382, 0.8939354027328587, -0.8734308037680586, 0.3369091517297497, 0.3299103460613319, 0.0702858752304295, -1.072358790764271], [0.6584742209204592, -0.9591327668921346, 1.1465763296566682, 1.1803504558146942, 0.6234404556556946, -0.22855932565519965, 0.904158409643793, -0.538568518310208, 0.6883663233312387, -0.38330771235693883, 0.46197769702389613, 1.0923297661171278], [-1.0296210583245577, -0.6778370190875236, -0.27370245095494933, 0.17413951777062112, 0.41197072277133057, -0.4967488674632696, -1.186915507442209, 0.42278985045618983, 0.367365549086114, -1.012392325660719, -0.2887542396180252, 1.1985457221386493], [-1.1251977852482544, -0.3137906120330729, -0.8223767704503414, 0.9581195949822308, -0.8337281960859781, 0.3763460932523683, 0.66609765888408, 0.6036350086790642, -0.5000769911442863, 1.215403219306622, -1.5611717550672406, -0.3325139415127003], [0.45551297554826187, -0.7559164635464628, 0.8401310711621607, -0.16237134891654112, -0.5423051300622507, -0.6697606482298029, -0.5383122153417162, 1.0004447888847665, 0.5808764954907837, -1.2879922625169355, 0.9139667618806395, -0.72540208409169], [-0.017647719779236123, 0.7837774434383888, -1.2556280707883434, 0.3959643053795656, -0.10590169253132485, -0.5392556711802802, 0.22561500840045845, -1.3344553901940033, 0.2577899725930682, -0.4336816514191434, 0.12356001575990666, -1.8900820244266627], [-0.16186869860415234, -0.0398404046511714, 0.06341902615019486, 0.542326100976532, -0.6270760497331916, 1.441408158354984, 0.2231399305384561, -0.0391155275395196, -0.1769837332760109, 0.12509522903515816, 0.9411829845600262, -1.2991319830266375], [0.48690358867829864, -0.4786507657330487, -1.2760161459296344, -0.07813209670371156, -0.27892444326499016, 0.5561442995366365, 1.1047995997107236, -0.9136551489366572, 1.3992203321694296, 0.3265984745135439, 0.7913131919714815, -0.05058927681479856], [0.3829300650479876, 1.426698762583399, 0.02575676682716301, 0.5430947392699669, -0.2799660146945462, -0.24351556742104644, 0.47700262769869106, 0.4187017684922111, -0.7593971124290502, -1.1269336439253659, -1.0963398362198258, 0.7605934480808676], [0.9166331472903877, -0.11344346695167291, 0.050416972115003185, -0.3090522517848355, 0.2478088641891365, 0.46767265045364265, 0.2697489966902652, -0.6585298887804863, 0.32320927109391434, -0.060008364420632135, 0.7533831928722402, 0.13462353443481367], [-0.14629098489033898, -0.8665677099495169, 0.3804173072388068, -0.6533346023373519, -0.21818961288150407, 0.19938338735689884, 0.17978651765847772, -0.3554442268284839, -1.0037756330894185, -0.046812428190563145, 0.3010254160489287, 0.8664567054445983], [0.09884138212458644, -1.7488096069339463, 1.365601963753417, 0.5713922126165006, 1.37574065304772, 1.8745888288079695, -0.20315039877567423, 0.456793755305506, -0.06395354588338102, -0.606783226572881, -0.3708974336219677, -0.4950640072512857], [-0.6711742789144827, -0.4233573081637751, 0.31483488989162045, 0.6677861792354592, -0.33065282985547245, -0.19422179784174093, 0.594334653724104, -0.35981506753918535, 2.2589246215928678, 0.21451753285751402, -0.44369488111507543, -0.8890455509369578], [0.6234552700146263, -0.6784080547608062, 0.2791866235406942, 0.7680701765950527, -0.16789202437274162, 0.5885821048875873, -1.1803675647440681, -0.3749037551314678, -0.23955439416466415, 0.8461001092469327, 0.3959788225306441, 0.8013116299208483], [-0.1577004513089693, -1.221020185641845, -0.27890755153806396, -0.21685668460450458, -0.23564789276535578, 0.023770773184849533, 1.3132475702646567, -0.3210747753248985, -0.49367002532294624, -0.5501151158945616, -1.439631360990369, 0.7854707007561862], [0.15670616611732283, 0.1762885842091255, 0.22092287353003998, -0.4098972471354698, -0.17386513487132493, -0.28542982355142493, -1.0225632198191632, 0.007385022809066492, 0.4614475927830177, -0.34553817714428203, 0.24042095168913938, -1.0052615816913817], [-0.49808316215028897, 0.9746064646911919, -1.290975360736785, 0.06995511440440497, -1.1733154906848884, -0.4699190474848373, -0.46261621509972384, 0.5708108585537321, -0.6209427286217699, 0.5249209218603745, 1.3422978250313982, -0.6410973797103656], [0.3795983376370419, -0.30073461108684246, 1.0536080513175912, -0.8416745353942628, -0.268244317646773, -0.5176405265262202, -0.6076391169726635, 0.2343460540178676, 0.005249929477213282, -0.5384848527532549, 0.03590740835488707, -0.8473813504847594], [-0.15082531622402212, -0.34817405758226333, -0.2467222143367626, -0.09079950697844576, 0.6762358197888375, 0.024138684539654353, -0.6272325228989728, 0.9903614891930544, 0.06380190492747988, -0.5328321291048014, -0.1542222562814628, -1.6037305186483748], [-0.14525021727014714, -0.35855409842603625, -0.5086108177398136, -1.2679819796704574, -0.8373742805885995, -0.08817435707636186, -0.9896945968587173, -0.25451963923710264, 0.5446916696880301, 0.4455952214331421, 0.7186251944505725, -0.8629824268134272], [-1.4390159212169, 0.32810733498102157, -0.3255724436614582, -0.9090045543374341, -0.508961168727706, 0.3470206982009188, -1.1558000041139243, -0.016460547427405707, -0.14225110581476993, -0.8901422331304638, 0.7048550140646054, -0.271501728669478], [0.02091998898774668, 0.02549296947080418, 1.2381143374977523, 1.55989913018917, -0.9936046211508104, 0.5447974892169182, 0.3869334155297552, -0.5268385334969656, 1.655631770024001, -0.19262121119281397, -0.08851676973375677, -1.250619371724036], [-0.669420739117728, -1.1559189298715198, -0.3462691840787114, 0.6258813082188854, -0.26952398722589394, -0.38170166458170696, -0.42658073888441705, -0.12243973074167926, 0.19964814032381217, 0.9499235716421586, 0.19334876813356447, 1.4579033172291738], [0.7819026256654799, 0.32536227198870604, 0.03318407570600187, 1.2846111827174764, 0.33697243882576305, -0.5063576119796571, -1.4873404455620332, -0.7569906778521849, 0.08697284324776638, 0.7558911008626523, 0.02554376541594181, 1.0924088453896998], [-0.780731991443827, -0.3253874048514935, 0.2541912929166634, 0.6708898913754073, 0.615597539340344, 0.13038666151260367, -0.9470071752664917, 0.04109742462733791, -0.3733096669107903, -0.12798613258562366, 0.08700582786777566, 0.526862910100789], [-0.8146047136717111, 0.7113404611353961, 0.21195633656261248, -0.8462397991803887, -0.8211181229723398, 0.2030035981162995, 1.383420006748577, -1.1494201757937645, -0.06453779201349588, 0.17170527876008626, -0.25016891707743605, 0.025679419339170364], [0.15781851017962223, 0.6119471812649729, -0.7421668122794796, 1.397766491780835, -1.2370195803307926, 0.002219895390352994, 1.2074759729415692, -0.577563232480909, -0.900594949887942, 0.4631630784572271, 0.06739012152362403, 0.06721672353251176], [0.7911175051630503, 0.7745955195348092, -0.5635846548445449, 0.4076008167897907, 0.8644504280362829, 0.5576126979098287, -0.41208542952181704, 1.1149730463486698, -0.35278312423585556, 0.7834234334516186, 0.4447992586613753, 1.040230704606074], [-0.7186742749276174, 1.2386421071666684, -1.055063602849801, -0.029205884711053308, -0.740410733747575, -0.30092503586931996, 0.016537905960041507, 0.9941560672259474, 0.08857429546337349, 0.3076057981731921, 1.7868067119488145, 0.41254872290709765], [-0.30984335321386036, 0.34019510328357355, -0.8086158039011823, 0.0885699132766111, 0.8879042725109112, 0.05695601120103322, -0.4776777522220462, 0.8860970527155642, -0.8228285640857623, 0.4512086310056389, 0.11998823388211693, -0.9897059750889534]]}}, {"name": "harmonic_two", "n_cells": 120, "n_genes": 4, "k": 10, "max_m": 2, "decay": "scaled_gaussian", "k_per_harmonic": [10, 20, 30], "locations": [[40.25014618726901, 40.39703948682469], [25.7662780521071, 14.29006900440708], [2.6965351190828213, 19.16844403927591], [20.42366027099993, 2.2637596951222583], [2.4378855363584027, 49.95880575325357], [32.61845557939939, 11.725510083491198], [21.7473776112571, 48.70930966296277], [44.88388040542744, 42.21155188043705], [19.620233216738907, 24.65115093658713], [33.8344675915533, 3.0401356479028028], [27.779805846036172, 13.572580226505076], [43.98255866674611, 3.2107218656095506], [33.95907665106825, 43.50442511637517], [11.365926258045405, 44.7724119707063], [43.60977340121675, 0.9258608835105375], [35.37477836685887, 0.05998417934143241], [25.168198277683224, 21.833352608782636], [10.16264180572824, 16.247132228780302], [40.31076655135218, 15.822604370224507], [7.45192917667779, 34.925599515915536], [22.427205038018812, 39.9469745481567], [11.775822865308571, 15.989232715914314], [39.99397630274767, 25.353406946169564], [25.319250071078546, 11.809706419793176], [0.7268140181906635, 46.66119501127169], [4.291289554341499, 42.2463400736805], [18.394036945575838, 47.55114905978997], [19.97126307894032, 46.82210309210015], [27.807988776694852, 12.006766415138792], [37.07108350139064, 33.719485744338144], [34.21026061922991, 23.191218004168363], [11.094427958222736, 32.04700707406555], [5.3544748068643235, 34.61111373224149], [31.76933999453554, 18.82562627938461], [39.92616729030527, 9.701273800352228], [19.52294568988608, 39.896694304851046], [19.02376853216618, 35.662893206222606], [30.625890208265595, 47.05004876213009], [49.58383584950982, 36.18381273253981], [40.442190451733495, 7.643251157283642], [35.64451312832842, 42.381219012726696], [20.06128739963157, 27.662501989677047], [23.974387588043104, 47.92614998996857], [15.863892013835784, 20.104226346888293], [0.04598945554328826, 21.009226734656522], [31.571805306614504, 46.748054709332514], [46.183829237886734, 16.367490666204894], [49.44305128095096, 9.38374701172594], [41.162600901801575, 7.862974354202229], [20.254932643057977, 3.6736655903638784], [42.901946559900864, 41.439903548826116], [6.989464927135813, 26.35532382785413], [12.90707484581532, 24.588785000941808], [27.66030029746244, 5.31310255993786], [43.218778155056626, 13.934815951715601], [22.356166078718665, 2.862929835787437], [0.13726032041189162, 9.757976079849312], [17.083759205917033, 46.405671050728685], [44.48641442547737, 24.025050832307322], [22.737990929129065, 33.34965219269404], [42.9377451229927, 16.86487528743495], [39.6827263879328, 19.949362654402194], [29.70269411938537, 36.87334913951135], [25.067860220856307, 34.53878856033497], [34.86567411794005, 0.285634496395909], [1.9532766627907205, 7.451915540777476], [10.681756717461626, 10.160730354726594], [2.4482790876474816, 10.860570112488993], [30.047368470014845, 44.303758071517656], [17.47519038364156, 18.320239945319113], [20.83708665723845, 34.01708915230653], [39.26369761044059, 47.04790411547972], [18.78500207398558, 35.338710223696154], [17.081700498708496, 41.20008993214214], [11.532445186941914, 43.5506855920608], [25.255262655018605, 36.26720158343988], [26.749650737385405, 15.806067464280977], [24.715094961922663, 2.522520682901047], [2.1496282452306836, 26.49816632013648], [23.85872379514078, 41.65686630915559], [1.0061308956280435, 27.8441905349168], [24.53185521742412, 29.899856877532876], [36.478931206386235, 26.237030440164823], [28.151911017818588, 24.589193980423335], [30.760349945525277, 12.40636075264291], [27.630671455576504, 33.61934092056394], [9.555639045136893, 49.51835402819679], [37.32297396647785, 47.766563340093974], [14.697318559412714, 22.174643829741274], [13.07192772390075, 2.3345807685962394], [0.8338419135285491, 12.337392057987401], [43.06312661251376, 8.184708030012617], [34.481130009453295, 12.469094519589552], [3.2791468328669082, 9.624328120737458], [33.89631715352234, 25.0828102391763], [27.45155205552613, 22.658213916930027], [13.717396337417059, 24.41739155232282], [46.1223063644518, 10.074746404074087], [36.63670526814936, 12.556483962545311], [9.670802397315349, 16.192269082664403], [4.63895843089216, 46.76871463361106], [18.256699904582785, 8.791883657191985], [6.800628709613399e-05, 3.021375422433925], [10.73257291015835, 20.88268262707471], [30.078511561980875, 49.051530869552224], [44.52386048489054, 12.112704102821825], [30.577261865882715, 46.0770915243952], [5.080117395688488, 42.70194676932734], [19.80353471257518, 39.08437179793252], [16.129858584685103, 31.286142241060073], [25.3507914638429, 5.221060286423701], [37.99010478278556, 41.147212260723876], [24.14924257592058, 19.400516423612014], [47.37458350371517, 18.71548178641697], [43.980940723190535, 20.928702627472063], [18.675809595640924, 18.071381764776127], [2.9998743180051246, 13.8659304653739], [11.474006320070862, 3.117218024554813], [27.078432048425586, 22.110055791597034], [1.2554169661498693, 7.795955356138773]], "features": [[-0.6653426856286421, -0.0538756638943387, 1.325155927345223, 0.3490261125780868], [0.6389455936428303, -0.1506815972085555, -1.2918162500762125, -0.7108435355871252], [0.6512365658972803, 0.10321610258141592, -0.9038398688268016, -1.617870425602848], [0.11068190035142705, -0.339531008698164, -0.350530218612727, -0.3294499574610804], [0.28390511348310316, 0.29444772495280114, 0.9621285502204014, 0.9284215804413863], [1.3320930804934341, 0.8063630567820633, -0.3356080333276904, -0.05426894624359061], [0.4942150948314312, -0.31029227000142345, 0.5494387802798892, 1.1536094769949883], [-0.8012460099660716, -1.770384050846499, 1.1936549552915572, 0.01775991033501458], [0.7086698231113021, -1.3323053543858547, 1.7329925604781644, 0.7386198894684642], [-0.12607417369146828, -0.3519880388050872, 0.11389588045524304, -0.16673134056534972], [-0.2786901272438552, -1.1195999755255746, 1.262809438921045, -0.039577684569559124], [0.07463563738960281, 0.09291598860047003, -2.358217336741871, 0.5271414581243252], [-0.32915493062535894, -0.2892284645923461, 0.06978787257481246, -0.9724756053284209], [0.8433808099877073, -0.6958646238070096, -0.9036580547128793, -0.8621896009823745], [0.15875269513992676, 0.7457794743624686, -0.5950532355462611, -1.510186675915287], [1.062490693153603, -1.0650835950433684, 1.194830368529916, -0.05429587697711575], [-0.6983498940240875, -0.6400399491357172, 0.4618661736925272, 0.8893717949967992], [-0.19817022758122477, 0.946934382371629, 2.08697820766597, -0.20830834526001082], [-1.1494466412305686, -1.0544003485304514, -1.3903353550011621, -0.639665450940511], [-0.7237792369318543, -1.3251033289662522, 0.5301842547135, -2.6113390049731797], [-1.3207989716931114, 2.0152518061838767, 1.0378024284634166, 0.5227916833432323], [0.45725905895534386, 1.7709371728004815, 0.5356296362853685, 0.0775770872272132], [-1.2301601607845671, -0.07366681732892769, -0.7338839983148214, -0.7061752749030227], [-0.7142389333341079, -0.04464686469247794, -0.32971081974207533, 0.8711105109344268], [-1.3261814419117322, -0.16947019674286637, 1.8594974964345012, 0.0388973371949769], [1.198615221448642, 1.1368634972033143, 1.3166478203373606, 0.7381191695252466], [-1.3804460312528912, -0.2673877057870027, -0.38033558246862037, -1.5488553043334206], [-0.4638816211751379, -1.2500798351337994, -1.6655514460193832, 0.21089625656145172], [-0.04359127244566091, -0.6878149095751852, -0.9505863626128569, -0.541273442072544], [-0.39409036937385966, -0.4081102825826052, -0.052707747928468524, -0.43554067396098334], [0.3869719823711992, 0.5228708948391112, 0.35786967764803124, -0.6631035145259176], [-0.6165061466820784, 0.4348641034709542, -0.197042778476594, -0.04315170860457781], [-2.4919952503112044, -2.700103979886236, 0.33714819206874613, 0.3295586563507561], [1.3934318714435818, 0.7211631188958838, 0.22173880016804176, 0.01636245608868217], [-1.426740428209398, 0.8831758896325703, -0.6035860153728927, 0.5024844545833684], [0.20004164543806374, 0.272097020758701, 0.8926752155435728, -0.48986611197868063], [-0.3872351816195507, -0.8558614733519333, -0.37715202345150317, 1.6659407140512403], [-0.3633186666203786, 1.1856163121936107, 0.8260114337421408, 0.7292817915893176], [0.8030151370721609, -1.0142765548969686, 0.37344767888543307, 1.588412097484749], [-0.6957959363309963, -0.0471070855877405, -0.6891591571615298, 0.31701151121305016], [-1.0785301318658582, 1.6096797942508279, -0.37683478895943645, -1.542661572000243], [1.790790910814277, 0.970522894800899, 0.518511481410699, 0.5325875434742989], [-0.3577980078127549, -0.22329559977220623, 0.7240192298296324, 0.9176249577098493], [0.9326124031440995, 0.2125509856107767, -0.466388093105908, -0.19208732917753973], [1.1095997115146592, 1.4399181149572342, -0.34131239008610353, -0.47730400254445376], [1.2475496699476993, 0.7236490231334424, 0.6972581900253083, -1.3123336629533346], [-0.3737574414663936, -0.5149955292041763, 0.20790465904469757, -1.6849419797309495], [1.2717528081338776, 0.30013179535055773, 0.43483702547979786, -1.1841403768848728], [-0.026420371368168806, 1.3346502881568998, -1.5696956024589206, 0.3057680573775562], [0.6988049143143882, -0.6919471030872025, 0.8147412282685731, -0.33006903056415593], [1.2297665530315567, 0.5275117754251525, 0.22436588572838914, 2.008915981414082], [0.8318964583740944, 1.3086357086483342, -1.1895196722305454, -0.6466070677186754], [0.8365690029317673, 0.9056118633317605, -0.05574002999013012, 0.7797265342256705], [-1.0583537461465884, 0.21383522572037922, -1.1472838649378465, 0.3405705337781045], [-0.4861719071399926, -0.6409975166442754, 0.05629903018263689, 1.8174600636946423], [-1.011761734455417, -0.6017506161418752, 1.067664145735261, -0.4235666699986711], [1.7692642772096374, 0.22252970384637974, 0.09063191415105347, 0.35688413886287884], [1.741179596515403, 0.6553615344906699, 0.5167121329088065, 0.2518577631500006], [-1.562418833300465, -0.8852720281451512, 1.4833441210372633, 0.8218783319217637], [0.5060648618402573, 0.6370627277466291, -0.5435930521122606, 0.33796426767211185], [-0.900794630349013, 0.39136232136016047, -0.7141351107069186, -0.21381982915618122], [0.4534148448314499, -0.32678770337045643, 0.6475819228802786, 0.45603827622850734], [0.35945813704442325, 1.3244113828426742, -1.4738846764712352, -1.5962822788262483], [0.6162417919107772, 0.9407940950142847, 2.0116404277145703, 0.7562567989915012], [0.8302149983209312, -0.8830800515074957, 0.7526217774690592, 0.6738389380752741], [-1.0558651891629185, -0.896317509048086, -0.11103120279927593, 0.2882537511901322], [-2.944785538646996, 0.0703055101868928, 0.23085449610631834, -0.17683635976985834], [0.26682489806649157, 0.4559062316030521, -1.011638037208477, 0.4161801684774495], [-0.25130719973217774, -0.9458787787894589, 0.20914079384282933, 1.487644239755298], [-1.4601155833251631, -1.653109915764168, -1.653166149925423, 1.9773117527941952], [-0.25158374870191025, -0.05948675368658991, -0.7865757190025763, -0.9404477838814673], [-2.0268601600545053, 0.1704062939055249, 0.2595598209214102, -1.9765340524052937], [-1.043149176525692, -0.7441137561592083, -0.026002454439472283, 0.24412916699413742], [1.1257929683514525, 1.3644560191461277, 1.068454512203335, 1.341528531502859], [-1.1664166902953155, -0.5544917649796093, 1.1436098002700195, 0.2886610787245648], [0.018721718675669165, -1.9789881677034367, -1.8592429271083921, 0.7308894225311937], [0.34157639490844327, -0.29605762418597315, -0.41297173199761555, -1.7261026268818427], [0.3712151390391477, 1.034420799017549, 1.6421709791918642, 0.04913795013614401], [-0.20419668212000805, -1.0959970457174089, 1.2232436651983958, 1.706855529223571], [-0.6131700061123667, 0.2907587696302524, 0.0906701056389038, -0.5738273234080787], [-2.4974495618193604, -0.3659991054773752, 0.6074441438068976, -1.4433020292385828], [-0.8388812655122865, -3.2835604878882627, 1.2845277165004347, 0.5002763718002052], [0.04547852895218472, -0.2704733880742747, -0.637283176318838, -0.07880625474327216], [-0.31031493210381433, -0.24835672044910614, -0.03381111303746043, 0.1256509655342884], [1.54897841817735, -1.4494324054647152, 0.26196862488829153, -0.6245608174151475], [-1.1394811867949461, -2.3681708051255725, 0.6068921428382499, -0.9903792389515337], [-0.7596859730023938, 0.45987869267679876, -1.0934730110875337, 0.016045130164280344], [-0.08488040408826328, 0.7918433900417065, 1.0006409423733347, -0.8768518458101385], [0.9071777346550384, -0.10674565894923128, 0.11279756399596276, -0.2225136131382745], [0.765539634412858, -1.2222004081820923, 0.250084266960452, 1.1657797884877044], [-0.29366991481397603, 2.017772471985153, -0.7459058475973274, 0.2036961304237924], [-0.49260852892014195, -0.6287503105652976, -1.1257709935845257, -0.5500664691168721], [-0.06223707311992144, -0.813097176129281, 0.8723957394787941, 1.5103266276144978], [-1.5388961513985318, 0.8248433607793892, 0.1780600818362494, 0.23332070694060292], [2.4504993275728366, 1.1943246457946253, 0.3243098464303824, 0.17311415244634476], [-2.1657171481499815, 0.7723909164870639, -0.7486869461197863, 0.1757326242531968], [0.0976306297693364, 0.9603515134967532, 2.0305028814674015, 0.9836022675228114], [1.2729486704011452, -0.2345432028281203, 0.4557735137751234, 0.7692489297752649], [-1.4396281852276858, 2.0415429191664223, -0.714868246010375, -1.2775433055562428], [1.6340442221712168, 2.11843861535627, -0.7031057381505373, -0.6133099552415482], [3.1119129382202093, 0.11261711124014562, -1.9840581343909514, -0.6122687481297199], [2.0021187846260236, 0.659124064155549, 0.7520990806911315, 1.2245574277845088], [0.6757786896026271, -0.3332044808876784, -1.5943117200745838, 0.4463708390586508], [-1.116034915943622, -0.05623851864069769, 1.7589710766812527, 0.5406502875557727], [0.059491529994791854, 0.0656800558330705, 0.7307927491415821, 0.9212337664614076], [-1.3168137745000827, 0.18547932372329412, 1.715647072880231, 0.7543686438915898], [-0.7651259000530994, -0.6796276894565825, -2.061922492127639, -0.793378841071178], [1.6069652687673104, -0.06952390178003978, -0.8550109597366835, -0.5761205222847363], [-0.11074551402067748, -0.10654617191788289, -0.3539737132397008, -0.7690944405035621], [0.636570086422678, 1.538534566643514, -0.5679570038398728, -0.5412718676392838], [1.1893530639173242, -1.4637436480554302, -0.591394697898987, -0.37809709746053366], [0.16778159182906616, -0.27493880956242583, -0.8866033394203041, 0.3105063468104034], [-1.1877104022986131, -1.7425136392104728, -2.0282575532960294, 0.7486985378512533], [-1.7368555460158381, 0.44705728629242797, 0.670709123171108, 0.8068993146395768], [-0.17468272255542663, -0.5482001218387921, 0.0856713362219482, -0.5937349097040746], [-1.286202262300972, 1.2554399352377776, -0.8944374586353495, 1.795889000036988], [0.5147645516042764, -0.4545567548775306, 0.4376476468228372, 1.2301494746406227], [-1.378469250276322, -0.926772947442875, -1.0492675511760912, 0.16503139897918395], [0.4042508713136647, 0.028968342989254353, -0.7282098404051072, -0.5284513163621615], [1.1870432673580795, 1.116942674442043, 0.13135528984481942, -1.3106089423110556]], "harmonics": [[[-0.17394616908844862, 0.021360772162485758, 0.0815649648876809, -0.07663421457164775], [-0.011191507285900838, -0.6129768404491684, -0.20409031500332925, -0.2570427684624019], [0.2095198057166279, 0.6867397525254636, 0.15416511827968482, 0.13026109492123178], [0.2221064757617315, -0.3543936389694292, 0.5225298765495153, 0.04605007062766762], [0.603270073998456, 0.055721592126083734, -0.10079686917146054, -0.17446798838909197], [0.07937822077952211, -0.29651677734538934, 0.0191024853741767, -0.13427566061295723], [-0.21276134288508655, 0.07197274662888904, 0.10096018443172726, 0.11355423116597813], [-0.05141352134390177, 0.14712864874282708, 0.29878664377321135, 0.25390543042214686], [0.18486730086091294, -0.08055640819074585, 0.04047099348334608, 0.7073002402158302], [0.2651703744463448, -0.1975984452764073, 0.09383827574356284, 0.30914728966014643], [0.3623690022034685, -0.4283010448573555, -0.5849230192376103, -0.48367825925926167], [-0.026521940375293755, 0.2255080772343923, -0.3782796872988929, -0.2155455475220029], [-0.33906534897907914, 0.40103350167308105, -0.07660486977212863, -0.4279760179537854], [0.3206806992797796, 0.15643153053140732, 0.04569484219473553, 0.05019082734843644], [0.10100006261783936, -0.03827657531717192, -0.718861457737534, 0.18754037267606574], [-0.05293512598861049, 0.005948752797620556, -0.3351309326228053, 0.09026829497243051], [-0.3488412561400473, -0.17810211720924685, -0.5832372646799544, 0.07963204688120998], [0.03397787745912855, 0.6940329835786506, 0.013381842389359891, 0.11562599604181735], [-0.6765397429610023, 0.12232749530925209, 0.09713978394640502, 0.22054781344355126], [-0.45346941023892645, -0.32733409885024073, 0.0930128544615277, -0.03657010653164577], [-0.05805896619658846, -0.04954808636985928, 0.013445217949478038, 0.02651580520819194], [-0.12067376779712682, 0.6539348495343792, 0.3764683808335943, 0.1632622396303246], [-0.010063124701045008, -0.14791889402884895, 0.2442393627022582, 0.039081868213985946], [0.36439517765194424, -0.596284130189908, -0.3949660375786664, -0.4366362195465361], [0.8808700482546311, 0.056726360743520055, -0.16259487304502848, -0.024914093131197735], [0.36307133034659805, -0.39487039933162676, -0.16503729271160728, -0.37091830288432803], [0.3370260794611794, -0.11497319831903115, 0.0857923439686778, 0.34511369031731337], [0.06503624408695106, 0.20158529320184507, 0.36111437344453245, 0.06707399274604842], [0.30351338882633716, -0.5249077869288258, -0.024407618174802585, -0.2219539357897272], [-0.04408546974238321, 0.1537024522664416, -0.19455722610201975, -0.297897251117448], [0.44756670260551024, 0.2743220710716998, -0.14804296867023367, 0.002708130637015585], [-0.19975948915693145, -0.09333303531984671, 0.03787313017368302, -0.2899889605736386], [-0.16860537458132277, -0.14003179705887084, 0.21485523088843175, -0.719588699641498], [0.3006644954958617, -0.023813626588467977, 0.04421276623075343, -0.24338820379432818], [-0.4826246949028521, 0.2468432360707704, -0.5317237149592932, 0.19512511609271627], [-0.2227505812772787, 0.33894712068606236, 0.11878368517284324, 0.2763240704580382], [-0.17448582693769676, 0.1590997554489109, -0.0602795728704812, -0.10086981091985393], [-0.09942166211914559, -0.03913299413881971, -0.018234614821487444, -0.23198890105976014], [-0.48604824080403897, -0.2980209337206227, 0.4079862766664692, 0.12922170175026887], [-0.4722077833955318, 0.43617876783035353, -0.6882419811366353, 0.22348693156276375], [-0.2182149304519834, -0.0023798330850943778, 0.08976385710593503, -0.24091066404533001], [0.1400687161797683, -0.42331728069458774, 0.5057448586889081, 0.27256856447109806], [-0.08316108028106232, -0.18757053798801415, -0.10953244714880692, 0.17435823691053393], [-0.18865300065426469, 0.16774263169979917, 0.14607761092387073, 0.827039648904008], [-0.08138935664384891, 0.23333121849756222, 0.049954911173273726, -0.15843352925275098], [-0.40416063353168674, 0.05986887263106026, -0.05005950432608687, 0.11778807238506478], [-0.7454708435672434, -0.10503588884131715, 0.24805205663260474, 0.4329665611603888], [-0.301617319425453, -0.02048841604823202, -0.13178833835915083, 0.3718691757139291], [-0.6303573213995279, 0.10648863206172395, -0.5796678541406717, 0.1840212398205463], [0.15313433107579197, -0.2627017724790338, 0.2839388713717061, 0.054702228168764785], [-0.5467816703220915, -0.28138511260557847, 0.46634225213589003, -0.2869512066243864], [-0.5290374311208293, -0.15284066223731288, 0.6447370779152765, 0.09073113444005769], [0.26718216645860143, 0.29107237204371345, 0.5663998823247501, 0.3158281505680643], [0.34977479170679815, -0.4157080072736782, 0.19542310775728133, -0.19485764224202728], [-0.7783845524293238, 0.0517804255904466, -0.11232411924332998, -0.1273950872655984], [0.4278568590025167, -0.23019560519340385, 0.21923820504119795, -0.015568870545385522], [-0.13102369571995506, 0.640930645954205, -0.29962675429780244, 0.012692826016988097], [-0.2621866483965325, -0.260418215781551, -0.15350859988609603, -0.07590133040972213], [-0.5864184547459987, -0.1950972296474335, -0.09725405621808644, -0.23205482824057275], [-0.24101270338639408, -0.7236815280055843, 0.17323591361097204, 0.2079874512454468], [-0.6475041381666133, -0.42999054572981105, 0.10093217778891084, 0.06002120459050576], [-0.507085523988186, -0.26205965272651416, -0.23944495353133255, -0.2545270559434696], [-0.3673815148613572, -0.36732136088215883, 0.12810171450195298, -0.02126090320400117], [-0.31683231072681467, -0.8793398649171393, -0.4227200345143491, -0.04287603411444723], [0.07804956761428271, -0.07955670627672429, -0.19360660868065224, -0.05093301846562677], [0.3795170521921604, 0.6643862145238247, -0.27263805578777256, -0.03536524185152515], [0.19738712832072244, 0.5545919185162242, 0.2015728690625235, 0.2865428272541769], [-0.048407234316084645, 0.6341487307491499, -0.02926082038647199, 0.2043427935043551], [-0.14818810426524726, 0.3378069873047107, -0.08911433956764027, -0.4610524262429796], [0.0001290019760458447, 0.3677998421470648, 0.14719857465296599, 0.5515595530523502], [-0.15530506420742535, -0.21816287923930155, 0.0075249799702111955, 0.4549580839180683], [-0.13662312521641987, 0.301098392960789, 0.32302709471583607, -0.31980613035638794], [-0.02094550213669091, 0.1239243678830993, -0.18236585859302323, 0.21818367450137183], [-0.21285085228094985, -0.03463345364235588, 0.11420847702904761, -0.09735035654663717], [0.8368679015699833, 0.14676502640788722, -0.3422028809258093, -0.18591592257858452], [-0.17769613452424843, 0.11724972032615558, 0.3689893096328166, -0.10827411736518505], [-0.017930355941043842, -0.5897006918351071, -0.4096552347758557, -0.07110769173209203], [0.040399223742671686, -0.5411890532022312, -0.00440571638700892, -0.127068216486338], [-0.47143500378200665, 0.1378433481363834, 0.03085832292296929, -0.6842549316348651], [-0.1872831924559657, 0.16630666060441962, 0.26322142830639816, 0.43732299758385645], [-0.09426594112486228, -0.16977368909091517, 0.17872975407996589, -0.01685027292001789], [0.09339513928230014, -0.22021776636169765, 0.1667562442762172, 0.1301509815656824], [0.1630493721878024, 0.2017225713247774, 0.1360297318173145, -0.15035121378063576], [-0.2208865241734011, -0.17212620674352025, -0.1512839736913692, 0.14843895911222188], [0.16748381616090452, -0.1024149873416079, -0.13135797236327584, -0.10374644875094456], [0.031349085555424955, -0.2478481198907998, -0.08593812651062742, 0.12132194356919598], [0.6685580332251898, -0.08814772300605557, -0.09573038194980277, -0.16544077038239502], [-0.5882432628788054, 0.23961126092081028, 0.06480697728857039, -0.6720842646402977], [0.07620663736988822, 0.30752033776943266, 0.4922279200772886, 0.7278869991873183], [-0.49154499636065613, -0.35551116980678554, 0.05415696419109347, 0.04220996658011213], [0.34913531251593766, 0.24015160117562745, -0.127035942703324, 0.26639799047999535], [-0.30417362182491164, 0.42474937501599974, -0.4821094102953823, 0.43496542444376507], [0.037942880036692384, 0.28437847527190807, -0.38592229412912704, -0.35047454662510225], [0.3408244412936835, 0.3829270749179329, -0.2983902873245569, 0.1162661172639691], [-0.10515956779976651, 0.09654811408094362, -0.16441188298711473, -0.19351881548561173], [0.06796685460500616, -0.387547883704443, -0.14666679207992359, 0.07330700966642759], [0.4232409020067445, 0.2507087524552102, 0.11034766976748912, 0.38622697945391704], [-0.3821485094248145, 0.08333061892085851, -0.1497334283700268, 0.056690919323778656], [-0.16609603854785018, -0.1412473538979961, -0.3428319828511055, 0.36864425195219275], [-0.25640065420505365, 0.4276825340209709, 0.584003066935955, 0.11620739542111085], [0.1769906921518942, 0.1387108089844138, 0.4615546503919829, 0.1357472257003455], [-0.3404608957356123, -0.38157401256749524, 0.147725209965781, 0.1266413650536934], [-0.023138327889882723, 0.296371782928362, -0.14548780412670156, 0.0476232408471355], [0.5959038519596038, 0.8464503622768051, 0.32805421787031597, 0.1042391816102644], [-0.14255107312444518, 0.18069234810157275, 0.09824381038980978, -0.14863589451368028], [-0.18627170717049507, -0.13541675962624358, -0.34343584660907056, 0.1771346082437073], [-0.009449035962952722, 0.2955379756899486, 0.5102511717268945, 0.08176335981159023], [0.384695942950049, -0.058356638847453464, 0.2875420629465578, -0.0452250214998652], [-0.22441952499067533, 0.3754135199311806, 0.3984628707377847, 0.3425153144693049], [0.019087079259873272, -0.09113404727770366, 0.14241345657166335, 0.4172536916380191], [-0.19589299209205305, -0.026588255813976547, 0.3018720197164192, 0.02289367467282557], [-0.45426650815246117, 0.24573497808281147, 0.4333274567801891, -0.3652868787181557], [-0.42771485028550227, -0.203620676331798, -0.3023465062009325, 0.13536380746050303], [-0.49891021164655913, -0.3743672996990071, 0.23229334420522885, -0.16491593754646006], [-0.9240339800468751, -0.2652373309036267, 0.2649277996710615, 0.12745487532330832], [-0.07702529612116427, -0.5207844144078436, -0.4044596143781569, 0.5052356109700231], [0.18265932844082206, 0.8503932284186871, -0.3396117849339862, -0.11647788826238469], [-0.08967646020208037, -0.30001555095896293, 0.20563191644675166, 0.25260283166424424], [-0.4583383764783887, -0.16936088526352466, -0.29894310404671304, 0.1797080554941849], [-0.10042327064992274, 0.19556115674398322, -0.32190118628423237, 0.3531268696852263]], [[0.1681380997568105, 0.2715356815551678, 0.3075033307664072, 0.460336328396652], [0.28535595840024064, 0.059813247685638934, 0.28900168627378425, 0.3581295823524785], [0.06730868419882842, 0.09425686089305228, 0.235291251672176, 0.1058509105131314], [0.09710547998240639, 0.08925224774144402, 0.12061894135797692, 0.20865252816942148], [0.1405101824193748, 0.044055474708658324, 0.2865436461388141, 0.035536307394724666], [0.4455465339089624, 0.44640531047752097, 0.1319124485352624, 0.25669775767668346], [0.04576793182273639, 0.05502240523514426, 0.20925686687873551, 0.241591006215114], [0.1694578131923932, 0.2169650306769866, 0.054607985736176506, 0.35261789586480524], [0.45023024171875753, 0.35022297016068077, 0.33471387631230753, 0.18335809823254984], [0.2584178503025052, 0.2704640788235608, 0.3680746643620289, 0.04096600534803543], [0.2621577469108466, 0.067133594392076, 0.25443618416578606, 0.10084861104693582], [0.21791255776183022, 0.036611156750576614, 0.0851732068952747, 0.30397917973110894], [0.18662567125031337, 0.18474497607064982, 0.19212772679742865, 0.2676532549342516], [0.30634238254071366, 0.1314710834526273, 0.3143520289074677, 0.09170525835972386], [0.1550108049173956, 0.17368475005835193, 0.30400980980980347, 0.029282408809795924], [0.16420581834259004, 0.26765780821777496, 0.4099614545920213, 0.09322956042575503], [0.05504070055151861, 0.30418747347864933, 0.3436241190498563, 0.33255851707058404], [0.29839717466337495, 0.15890546341061326, 0.18951041812620906, 0.28660141551735135], [0.2328383183504099, 0.23905553029376764, 0.17306682198638848, 0.156168664389278], [0.44827998208868697, 0.43230878084545754, 0.12117383285349023, 0.03221072727792556], [0.09906101951533214, 0.2170174434919021, 0.17886490484582548, 0.06324566230842255], [0.30248772978883837, 0.40222447463507427, 0.2689049732219179, 0.4071489055578612], [0.4974835592148, 0.2685103404701164, 0.22224062866934385, 0.11658244919705853], [0.13236458560789335, 0.11825767506455749, 0.21915944757189065, 0.2266534716423121], [0.23078774775991917, 0.14829200457263353, 0.1601606768995398, 0.1477737026370563], [0.5937310849850624, 0.30778527445429915, 0.2494608450402828, 0.16791217128714792], [0.24924147319328313, 0.2134537245952298, 0.09506559821214965, 0.17790667517784176], [0.09639983895420352, 0.15033213358630018, 0.09104497224339203, 0.2954055236753461], [0.23954658748037044, 0.08525487566722416, 0.17150783173927958, 0.16461039709130265], [0.1479361494720784, 0.0672687445373568, 0.12763846061883247, 0.22000732672621418], [0.18184718894594123, 0.13631110962583853, 0.0588328236744324, 0.06518503470078965], [0.5240837065710892, 0.5486883193136027, 0.12711721326409697, 0.33354504249328026], [0.3654468873990854, 0.09597299985594215, 0.07015213597107228, 0.12419198672102925], [0.1740750675026429, 0.28020837050910063, 0.14967469265563357, 0.062444550366338926], [0.1651168122396784, 0.10586945674714723, 0.27058198881263046, 0.07745469214990372], [0.259830465240103, 0.1687634154737786, 0.17252419095734756, 0.14808632807316388], [0.01830448448913669, 0.23398688108432245, 0.18142713950766276, 0.03250178514337845], [0.10857026554450006, 0.23278200543274655, 0.3404358080763282, 0.5008446955755357], [0.10339616590043635, 0.05899938966550981, 0.09850762531309344, 0.02297687920869176], [0.30259688657540645, 0.09972056871746135, 0.23796986541756712, 0.10892939850114305], [0.08333878084514576, 0.10334090492721643, 0.19267356762145962, 0.23079315280593465], [0.27361663415076753, 0.4181713407357799, 0.08380037171269598, 0.20403808080983596], [0.1037746851038761, 0.17334407970836993, 0.07843875016772592, 0.1015450318574774], [0.4706482329386186, 0.4388606312979524, 0.6091013132907858, 0.35088338560616805], [0.36872826167326, 0.33053553329387303, 0.24600972442885977, 0.05688478189653874], [0.07954494959448727, 0.1890140856229711, 0.29885188138538915, 0.4709395387696803], [0.263271051922577, 0.08724961747589101, 0.23063064791698606, 0.08723654478289693], [0.1707373230863794, 0.09919233101073509, 0.3501549272920393, 0.07374396490045956], [0.2860541803627989, 0.1310720185651544, 0.18415827867222384, 0.1208877735738662], [0.11660320169984775, 0.0785808627469433, 0.14316183237551572, 0.2820775311242242], [0.10047015960021234, 0.4125928788263865, 0.24213887358578903, 0.3214913227654711], [0.5171144323211335, 0.5031324582932448, 0.04076211070410045, 0.21224335219919818], [0.1493733908555803, 0.09980375236558071, 0.16969583134825128, 0.30413288065289174], [0.04125560457084256, 0.06577953071066965, 0.30452848671677935, 0.061616221227558096], [0.17320058888173603, 0.18502398783817414, 0.37234022528049815, 0.23901086937985966], [0.04854790788314238, 0.10290083172369713, 0.1124486758893899, 0.05544271407441699], [0.16349306614906542, 0.28279419806342243, 0.12820596798391304, 0.07714867628075932], [0.24380908528321546, 0.20659594226473885, 0.21460250346424364, 0.15939439720191714], [0.23237192423369332, 0.04904903921648013, 0.14565094577418433, 0.08233368630173911], [0.07472245816148602, 0.42940248493561495, 0.31425897272703257, 0.028205326173052065], [0.03423103115219052, 0.10515514004692086, 0.30241072429044247, 0.17833945209148191], [0.4495927950819008, 0.21372198019424768, 0.15657289813127856, 0.08369705078282809], [0.04408794959463734, 0.4300904674494318, 0.1709793098541942, 0.20870637922109417], [0.1265602445197041, 0.4582933613180644, 0.27589558578419865, 0.25198128560065314], [0.17224065181068915, 0.1265999143201506, 0.23425899139173037, 0.06065707525480574], [0.4481065205319491, 0.3040834721561964, 0.2071614540756444, 0.15388691042723163], [0.1449345620915683, 0.4567245568079832, 0.17275279681765277, 0.18924763124970118], [0.4181754764273374, 0.22549639096296192, 0.17600191707654186, 0.06270846487556514], [0.08570971474270078, 0.09984894375661084, 0.09330279068990388, 0.37868151445834247], [0.40603186415851217, 0.34419190185256676, 0.49231595901129127, 0.2483493037378367], [0.23846232363974554, 0.13325535382992595, 0.1183182781981127, 0.06425887249016045], [0.05000714867818685, 0.24410943768515828, 0.1518099556469688, 0.3335535414376398], [0.16517944530972406, 0.2312780454477562, 0.13898812073362415, 0.17798626754579877], [0.12559624009046227, 0.16153027232492595, 0.05160343215625882, 0.07401123786030936], [0.3001003038035725, 0.08999793378029304, 0.31054358695328077, 0.1659933764594002], [0.15228348836434843, 0.37503009654689745, 0.20507738627501104, 0.28681330409454703], [0.3795423810750092, 0.10505880929335867, 0.35454393084999153, 0.24742170166683947], [0.057813906277683194, 0.03513957843689292, 0.23666571468339975, 0.03280158303130128], [0.6735389789166408, 0.5015125921588489, 0.1476743361467198, 0.25884231584687417], [0.052534187432741214, 0.2248496747430844, 0.19207457533955113, 0.09338089894240183], [0.28880052404109874, 0.37512726713132094, 0.06070802611353968, 0.16203721149423822], [0.18429716147209627, 0.160701161168453, 0.0347020983580471, 0.1526570738929801], [0.46130600676820277, 0.2354369036450581, 0.019585209445720272, 0.06736082670094337], [0.36456693182911165, 0.3893003042079751, 0.3491583435394377, 0.2012670628307459], [0.02803251115457479, 0.3837188662859177, 0.11540005599621615, 0.17295930816988442], [0.047037248026691604, 0.25650858342329286, 0.26352837375130783, 0.23886682940263165], [0.31751299321656434, 0.0775531026218753, 0.037639660917444646, 0.08178650904558728], [0.33559962116255326, 0.0860282528573987, 0.1218750783696068, 0.19308736766039328], [0.25354597955771285, 0.4045895491011331, 0.4581757926236072, 0.19385362710556786], [0.27942841201763247, 0.16497875249006466, 0.3211721446149524, 0.07493322641532779], [0.2417160580866308, 0.09175155522822201, 0.1399800100683596, 0.11087417818702737], [0.35266059907378616, 0.20253448144050837, 0.4844159699514241, 0.1310397501997503], [0.677115615227597, 0.39075022615205046, 0.2015566092816583, 0.11881348544942377], [0.3506905099959072, 0.28834571111124235, 0.17485271446595776, 0.09339620789131237], [0.17335461569428057, 0.21492978018649944, 0.04825988691006704, 0.08584585079167018], [0.33792411604375255, 0.30913606934191706, 0.3187025737757766, 0.2676357861558508], [0.10947736279120195, 0.3583098555546138, 0.06094923874378029, 0.09767129061713943], [0.38570466660954794, 0.12771909956210745, 0.4901261778963096, 0.29126673678700965], [0.5427328637959892, 0.20978165878838823, 0.28342852260498047, 0.09063393080228108], [0.24665564395541306, 0.08641467722444135, 0.289468437829677, 0.12790267443856138], [0.14001333378587114, 0.10857759672109676, 0.3993436277291312, 0.17900349069908003], [0.2523766620855199, 0.3099398873253627, 0.23609124481303842, 0.18031751919598366], [0.18462284801866888, 0.23210028917380593, 0.043060760983835766, 0.06920326939754941], [0.09383353873122084, 0.2234071052753522, 0.022277917943524943, 0.3057814505162757], [0.030258923652811222, 0.18833658438414327, 0.10520772324315733, 0.3663446028382683], [0.45866362589493115, 0.18110138689467076, 0.32420538353054174, 0.1504116524144656], [0.12901577799092018, 0.2528093099126352, 0.2661703624126162, 0.48382622711804324], [0.4372372741669166, 0.24861175586051967, 0.3677154769613909, 0.16052524103910398], [0.22421994666427425, 0.23895981280595688, 0.2777675527517522, 0.13449208777741722], [0.3498002506197108, 0.22914674356097425, 0.2220252420220094, 0.17034741809050488], [0.12469728189619322, 0.11148932394922091, 0.43905718190383514, 0.022861953170817094], [0.11782175129082006, 0.2625630900396566, 0.3698330035155108, 0.5012023199372856], [0.1477595446371724, 0.058217719744246256, 0.21027884250212342, 0.4447019971417029], [0.1364722003869889, 0.10949692615772463, 0.13175827419469752, 0.03589201928474177], [0.2672752955212523, 0.09038036642109448, 0.24899563913922246, 0.07326336767297813], [0.1354331645668198, 0.2938249834532531, 0.22678438324921427, 0.18473435946720035], [0.24957996443657723, 0.08390583604354837, 0.24526722231235124, 0.2598386869305495], [0.2662140791255928, 0.4373815541214417, 0.2560845739524389, 0.09420384234023041], [0.26313074275681614, 0.40165520959331785, 0.20254843061116215, 0.30832097257838664], [0.4292648743348032, 0.39017793043145377, 0.21739169967825525, 0.05660903102842937]], [[0.1750656736320863, 0.18904123819294377, 0.09537264236288899, 0.29180480950940846], [0.2766526910532769, 0.22024325804064313, 0.21807702842082946, 0.16963462387964046], [0.20095238170501106, 0.2805194843716815, 0.17195415371855416, 0.07139592854161592], [0.16235997692672877, 0.21863628235184493, 0.20563267688919293, 0.14346776848569745], [0.2871233643899127, 0.09359329320964122, 0.26781330765813793, 0.10268391112977071], [0.234180736319028, 0.09358240485828247, 0.11781511426296878, 0.1322986253505446], [0.1204176245155927, 0.07122418927300654, 0.057825215333974764, 0.06858267310609503], [0.12448224944402933, 0.13094024599217577, 0.10732290534563939, 0.1389557655321934], [0.1232107837602339, 0.1044673463114437, 0.3435830704994891, 0.1202545079257539], [0.35959660429840784, 0.310409280514056, 0.2831366247834346, 0.0964834262104541], [0.15684184729473347, 0.15731515950218838, 0.20826298896352197, 0.16123077994400012], [0.35873559113674136, 0.19361246957327352, 0.33384668190092537, 0.11771796372930443], [0.12841163079475407, 0.10202107572721604, 0.04298173982697569, 0.2904563643957774], [0.4189394333560526, 0.22826618622075495, 0.027372754683920385, 0.1616924998211684], [0.31152594550358503, 0.21544635712441534, 0.3521361345432825, 0.048477019643545456], [0.23476092769885426, 0.24499247296856133, 0.24802010548660014, 0.08138089187061479], [0.42945835707921515, 0.3965807147007948, 0.344326343179916, 0.18590492987507357], [0.32922188327025576, 0.21528080221321125, 0.340533171247497, 0.1201721774751275], [0.21212684305745755, 0.08925430869507016, 0.16402720220832542, 0.21759513644125356], [0.512516307379324, 0.3363349651527904, 0.0372190616681654, 0.06543356697582602], [0.17205676501939932, 0.22109700537527452, 0.07495043103055317, 0.13546363635931502], [0.2096299818780774, 0.20136287448711915, 0.30861960812593764, 0.10861240099370598], [0.34576728019288344, 0.14786578430485234, 0.09285089892099435, 0.0424542500320835], [0.2618462250114853, 0.06591133250960861, 0.29899273577833657, 0.24381949649131845], [0.2582580038025805, 0.08974622294416174, 0.25651770998489115, 0.08886964325357641], [0.23033562460528473, 0.153937327444655, 0.26809199516064175, 0.08490860322926928], [0.2976921294388995, 0.18447312652246248, 0.2472995364578845, 0.09413976199860824], [0.28601272768190106, 0.09304093480240738, 0.19839732040467153, 0.3048584741574583], [0.20589369390260223, 0.1497830121778494, 0.2670816614767625, 0.18664360759797333], [0.12474498287510391, 0.3040289743694555, 0.16078861904402397, 0.23398046432594868], [0.5023588814367742, 0.17641876763622288, 0.1278388679704729, 0.09001611823520751], [0.22815510458565902, 0.274793627191653, 0.18348813656485372, 0.1337387376232012], [0.3138938245916376, 0.24680114632898978, 0.021583772393263565, 0.21032319157467538], [0.4891949970275665, 0.1527836479266113, 0.19541329604482088, 0.21039366999653814], [0.21549122774702828, 0.24399347565873677, 0.43182508455021923, 0.15354808126991726], [0.18598165839797545, 0.277767192213769, 0.21034541223229553, 0.024208708746781632], [0.23065715144110563, 0.31309551529810536, 0.13715881210064818, 0.05797302030680961], [0.07876502717317882, 0.17201873823819253, 0.2857961761687155, 0.17486903341144505], [0.17854702546950776, 0.11492795722865504, 0.18786557010097338, 0.06745356945325705], [0.2854494218510402, 0.18834951925311122, 0.289460661283672, 0.13479016261768895], [0.14397350396102246, 0.11169586086129764, 0.02651871643727808, 0.39294564781719893], [0.14872880863438523, 0.1829923384124834, 0.3057272044423781, 0.1116852510250721], [0.08960928267473522, 0.09238610583073689, 0.09247552898737277, 0.05331358114645727], [0.25608552044204375, 0.15107101670699188, 0.3544552555295273, 0.2155804341381103], [0.24405214904104544, 0.2670093395619492, 0.11999661210648807, 0.0719664144200459], [0.06699378471735688, 0.15992040430434276, 0.22266766516005654, 0.016503283503478166], [0.2753934477856392, 0.09488735672285963, 0.23313417279383145, 0.28504382567156206], [0.20288738938139575, 0.10232753338794845, 0.3352732163464874, 0.15342705915094365], [0.2209607899096392, 0.26283913452837887, 0.3443299261713216, 0.11499193706621978], [0.13533334177809533, 0.29087860637346, 0.32922063685317066, 0.09649227644914075], [0.04884564577834904, 0.18241455592520064, 0.06437332882317062, 0.09608947078305537], [0.171798635957032, 0.08309586177159042, 0.27360188353789777, 0.34093667561803614], [0.19272813009494685, 0.24713207895000192, 0.24000301754262596, 0.14308824682231505], [0.06496339185006986, 0.16175537888820543, 0.14203817355758236, 0.12449765927176788], [0.2480345417547834, 0.12988150801911288, 0.16902714710083244, 0.11484995698840895], [0.04260121324646935, 0.19925968954437273, 0.3532020704504989, 0.15452465305197538], [0.3157193066782794, 0.23155036129141357, 0.16093969598398686, 0.1843549210628486], [0.0505165729513534, 0.249010426183424, 0.16477200445710713, 0.09136184845957833], [0.24270011526752347, 0.12370661586456344, 0.08670515084704306, 0.12807700251498855], [0.24993507720546984, 0.20857446426985332, 0.11663108225130583, 0.15137844292456282], [0.3232233989865078, 0.0357987841983099, 0.1893948075541595, 0.300842682044917], [0.21412419262619437, 0.0869507826093279, 0.26559757185768007, 0.04776876833275772], [0.0024069786820169713, 0.21350976234551663, 0.10177972529604835, 0.11762682641815174], [0.18012794338763133, 0.1848892814501462, 0.20278674336908353, 0.20663445861022595], [0.27234455294922155, 0.25134971207263973, 0.2714889202294271, 0.11752024903604703], [0.2771589769270468, 0.15134441405760493, 0.17063020626196096, 0.1116999675946604], [0.16304036202258398, 0.07216604612724549, 0.2041560358019268, 0.12031029666263049], [0.3820690852643266, 0.13117774531079437, 0.17265661653352768, 0.1018546637832852], [0.11624826092711595, 0.06760790881847376, 0.11753380914494017, 0.11548721476829067], [0.36320736499972317, 0.07626138224104821, 0.27677459420110057, 0.06319409716617731], [0.16109368171242178, 0.3513886020512712, 0.16999931149772052, 0.12666988076420474], [0.12973987028338183, 0.12107891915136239, 0.2824680021765967, 0.31546639344817196], [0.21400593935673212, 0.3284061003189868, 0.1650496621778757, 0.13008114409062954], [0.10583818032130103, 0.10175567346998426, 0.15916050135767407, 0.07844141448373827], [0.2358322737831877, 0.2670756969249118, 0.21436412238355246, 0.2457869009033845], [0.17556288561211844, 0.14692003213160898, 0.39645661023706935, 0.17780647908557629], [0.19595533058115971, 0.29353916979881606, 0.009362799404403425, 0.1503854532327188], [0.1319761009061993, 0.04105755765342854, 0.36473396421506143, 0.09352581860722846], [0.13605477226472126, 0.18820959332240264, 0.1601043807522723, 0.2070839682286876], [0.14227585585637845, 0.32028685589030753, 0.19732447427224803, 0.17406605159838098], [0.18899369892288323, 0.23900423039218116, 0.13313728721682921, 0.2877817349917791], [0.2819616866495183, 0.19862847444168433, 0.22523523121107256, 0.07132386449656232], [0.368584681450211, 0.27035257990767203, 0.05978394004329366, 0.07261692200077513], [0.4187914797249255, 0.1695988670744111, 0.3429004693179429, 0.18239013943023594], [0.08398309360647536, 0.023428549780944226, 0.09887522897524705, 0.0756814165074587], [0.10334603829767225, 0.1410306855445888, 0.09165766169770971, 0.1854732671772085], [0.28015387896697685, 0.10923495783577289, 0.03859674935520179, 0.1693658626633347], [0.019306313963893863, 0.10433262219800293, 0.22381212863683914, 0.21609981899990743], [0.1694299875896199, 0.27530710354828797, 0.3981399096839152, 0.23250625945196152], [0.266843439904508, 0.3084300242353637, 0.07971144879942028, 0.13706064611971566], [0.3659731129342865, 0.12489259883903146, 0.23249333596410415, 0.20003103916554493], [0.26092433045589436, 0.20557106845074766, 0.255873035923745, 0.06592301858091952], [0.16645474691205533, 0.08804895918225088, 0.08908481442711857, 0.07798569080707066], [0.08200534313166478, 0.08117224536274918, 0.21909048541352144, 0.12216721391877804], [0.2872546479240965, 0.17578140780049947, 0.16189173576700952, 0.1646755973814125], [0.25099583089005334, 0.205677200783621, 0.3331581948224676, 0.22622582877886319], [0.18365950690407526, 0.25144109922784175, 0.29480259653570184, 0.12948893208766382], [0.1704680312686977, 0.15613299508122663, 0.3139440031976997, 0.08810713915782886], [0.057959108196155254, 0.24281265235206761, 0.1372663613660115, 0.06457216212161707], [0.24093286301519112, 0.14406111767395646, 0.11951731415325985, 0.14099807352792817], [0.13918542435190442, 0.04202143324293965, 0.04314905314243304, 0.06405223585488277], [0.10675591095162495, 0.2938603296859097, 0.32404151020911703, 0.18471560511534588], [0.22670692065369985, 0.3058381510136324, 0.08656470701965215, 0.1160726452161627], [0.2585741004613565, 0.4009034641793814, 0.31835662472083437, 0.13900417765850073], [0.03050551368668606, 0.07839028346813341, 0.1941124307874521, 0.21314725021257697], [0.2619939479578855, 0.21611489039877563, 0.1674778195271313, 0.09819617318880011], [0.10318554280770842, 0.047020863209767345, 0.06437151986321038, 0.24172719847960683], [0.09203842510956149, 0.1819740997103418, 0.1728455385030328, 0.14538658491513706], [0.2595936164773057, 0.2049915770326482, 0.10900564638425501, 0.030722556114402323], [0.1467713382165519, 0.2671878799607893, 0.20251326289700197, 0.22076771905296963], [0.04212618198400329, 0.020373469005438533, 0.05229953412388343, 0.21900737294175857], [0.1101904899963656, 0.16345069056739936, 0.03271666840371481, 0.3334529725146415], [0.3393097678304443, 0.29732678061588774, 0.2007235122199738, 0.24314435928156158], [0.12951300984650677, 0.08889366197522221, 0.20784250733424545, 0.09174995236876178], [0.2744433569391535, 0.12401911169114141, 0.09774527735153918, 0.1427533541540938], [0.3714557754426444, 0.03781382637703512, 0.325303629210114, 0.07933167428548746], [0.24639287045882907, 0.2888972193928288, 0.18624676065639795, 0.14175820025641303], [0.2688724492499996, 0.3127114444130616, 0.045082465401754764, 0.06464176490708343], [0.4000577522804543, 0.17808577451386032, 0.3463530129482156, 0.2497120466133795], [0.35206421279497196, 0.3306597707618387, 0.1904457032189283, 0.04102341468692445]]], "banksy": {"0.2": [[-0.49918599263368924, -0.02561856126905011, 1.1869411016672236, 0.30996882079957067, -0.10166811725264428, 0.01676472642300486, 0.09001080944118713, -0.135066960589724, -0.10859126241998046, 0.09807776249428853, 0.19121478443118903, 0.5732679105042169, -0.0663902203503499, 0.010766833568553708, -0.17072895958269713, 0.32647962387953505], [0.5729617064840223, -0.11221650142127047, -1.1926976331558998, -0.7284475774457915, 0.06140190656593998, -0.6221452602461099, -0.24336151321723232, -0.356380418463957, 0.08302049831399641, -0.3017203240917131, 0.15243760859306404, 0.3642094246311679, 0.09575594674001155, 0.07163101140143997, 0.03516003154885164, 0.05196623980325359], [0.5830650999070537, 0.11490819082080486, -0.8399068648844176, -1.617114969584377, 0.28254088144837836, 0.6869398303764876, 0.1747383935799586, 0.11873872308953222, -0.27341343262881695, -0.23668002390359946, 0.03986713045426315, -0.15181323721938314, -0.025071648359906745, 0.18920875080468333, -0.04223078100168126, -0.16877367775899774], [0.13871974303851795, -0.2811521180107696, -0.3367769167096538, -0.35477394088381387, 0.2951519400891551, -0.3616981631079165, 0.6046363289402822, 0.015434125964800954, -0.22470569670531898, -0.24613029672329084, -0.20047195630046982, 0.058462027030155746, -0.08667017416024111, 0.06849636644660863, 0.014279319257726599, -0.006830036782543339], [0.28111224348837277, 0.2859748188918056, 0.856836710087997, 0.8776365108214935, 0.6770541010155645, 0.05137322288988913, -0.12281350176265599, -0.25508305912535906, -0.15375361180688019, -0.3314759214080357, 0.147285858186828, -0.2956380338364795, 0.1124685109188728, -0.17541857127393498, 0.11861387279924573, -0.09847035508727255], [1.1427410221359264, 0.7439096969623846, -0.32320802575282714, -0.0851629797352789, 0.15214712731291352, -0.30340411881118684, 0.01711433827368125, -0.20577773047926082, 0.34487819287900134, 0.4282862423771696, -0.176802151499208, 0.15673599937509486, 0.027965151776114302, -0.17543981062179262, -0.13307213209306112, -0.03192682503295013], [0.45399071382933565, -0.25499654616613665, 0.48157381257285176, 1.0982662881459497, -0.14055850137705866, 0.06774151747043078, 0.11264588690355962, 0.09824383131102009, -0.30862531534093074, -0.310766931056486, -0.014697744434300252, 0.12583593935702897, -0.1536156545460082, -0.2190528336264101, -0.23373079773148378, -0.17509499311016027], [-0.6109008940143952, -1.561124552225056, 1.0673659646192906, -0.014592088354843978, 0.021101956212278474, 0.14343915144806205, 0.343518098539643, 0.27041753679389563, -0.10643397497263413, -0.004968671490567909, -0.33882281664749697, 0.3529355618352434, -0.14712798151911552, -0.10256778831924773, -0.150677291762825, -0.016968395772044394], [0.630276238390368, -1.1692403831532598, 1.5577909937892163, 0.6916766725883882, 0.2578406085991353, -0.0858870839792602, 0.04205233060771778, 0.8266127446909238, 0.3525344793065526, 0.2466639413330921, 0.2482447478868916, 0.006723610259321074, -0.149157407054463, -0.15420711429189107, 0.24574999670533154, -0.05898965886141732], [-0.05589787644896003, -0.292295579064673, 0.08553033758217031, -0.1953489772792398, 0.3382992816549562, -0.20377277271565616, 0.1043343050485334, 0.3381846499584222, 0.038985754946513886, 0.09605424182221464, 0.318164864707765, -0.28453187424524723, 0.2281452811016289, 0.24751324124081564, 0.14432527892800778, -0.11240269127340023], [-0.18135085034307732, -0.978964363512914, 1.1302488218965765, -0.0707690898266117, 0.43568624659926697, -0.43613830156382793, -0.6878100919492954, -0.634402070229148, 0.04509922760657333, -0.2878972230018059, 0.07999255898088728, -0.16204517584146222, -0.09547783080819724, -0.051119598938047565, 0.01869279066443751, 0.033083010428349144], [0.10908908660273475, 0.10569420337658683, -2.162386709173314, 0.4844788616470862, 0.04604176842089926, 0.22238354732978083, -0.4466482007475324, -0.3054743319152448, -0.027226770282879197, -0.34553311894343214, -0.2747618648823655, 0.2534476440286746, 0.22677099147759422, 0.01968369988059711, 0.2294130482862552, -0.06468921090545328], [-0.2228337983169167, -0.2361538771504616, 0.04542248891120092, -0.9847838467186766, -0.2671072407742583, 0.3991741779948889, -0.0945803704423335, -0.5660701903443125, -0.07837030320299587, -0.0658101985119699, -0.05059831949688735, 0.17914488878111962, -0.1408561749317173, -0.15897892869982175, -0.2586370646971879, 0.323449701075736], [0.7410110175958419, -0.5999110620029806, -0.839741539508871, -0.8767301859612907, 0.3939171662212825, 0.15280908941383256, 0.04814879267485178, 0.020513736483957625, 0.11732624086555134, -0.1664079478595833, 0.2055688150787909, -0.18074741950515996, 0.3228641981469134, 0.08728092540951678, -0.2848278008797844, 0.03412048356734278], [0.17823477422168355, 0.6897145328338581, -0.5591241192023394, -1.5116108901971714, 0.1738108647722657, -0.04330249350162589, -0.8441221627536506, 0.1890052085253462, -0.13004997278173397, -0.08669535988155026, 0.18389279332480865, -0.308430052167674, 0.15141822216286338, 0.06227394311428708, 0.2601014130127211, -0.22027189893721227], [0.9211231606118646, -0.9301966269425727, 1.0684347795251403, -0.08518936535294207, 0.01957740322616404, 0.001241615557153519, -0.3962916991219577, 0.0696781621800904, -0.1150192195094568, 0.0907551263806875, 0.40595443555865346, -0.1776295403604711, 0.028891213105660455, 0.11990803404131262, 0.0854023262744426, -0.14633771223114328], [-0.5263184932456264, -0.5499729882641492, 0.4019431735684868, 0.8393771478669829, -0.27690209024850176, -0.18413591300903798, -0.6858427419583127, 0.05663030611611658, -0.29346745830819176, 0.15973454442348464, 0.26691952296064625, 0.3119051649134847, 0.3396537762536815, 0.4156034328392049, 0.24699715393601498, 0.08852521477525091], [-0.11516208937015913, 0.8696580558053415, 1.879673650734209, -0.23608440501754835, 0.10665881389298673, 0.6942856318272038, 0.010438095357129473, 0.10078533745740828, 0.10433849916481468, -0.11460326937834521, -0.0560838772053926, 0.21790234770531003, 0.17966325341561376, 0.06195100365056589, 0.2406324886828472, -0.059174653346753286], [-0.897127882000586, -0.9206399075299916, -1.2822820315771752, -0.6587102371788126, -0.6052355429396284, 0.11845922862055518, 0.10818731087526715, 0.22949658598106631, -0.0028281735181032944, 0.036745091747012765, -0.09054763631497754, -0.0488909366372522, -0.007235746454388048, -0.1838824055512683, -0.05553162624138642, 0.1597323247727884], [-0.5472218563455893, -1.162797796992377, 0.4640654816651963, -2.5904743499058958, -0.3817329773766248, -0.33444357489952775, 0.10337100197194145, -0.08591892356067649, 0.34934646097955885, 0.4016675913849238, -0.199308971837052, -0.3024403318331994, 0.4722251286707583, 0.2980851429315841, -0.2683064174436579, -0.18217095666198183], [-1.0379824842871983, 1.825323531707331, 0.9256477174938155, 0.4802171324154016, 0.014443634795178876, -0.0546552508239669, 0.010512057433673014, -0.00852923793220758, -0.22150904751358935, -0.00486969972488003, -0.07839556633795178, -0.23896001592685018, -0.07119283205268542, 0.07329637248552982, -0.20499593750396278, -0.024815123612693352], [0.4236122082008175, 1.6067713905759176, 0.4690170210916026, 0.04401430488335555, -0.04829249254710953, 0.6538984660997853, 0.4341761151596799, 0.15922237695108887, 0.11102518052071375, 0.34485902443546923, 0.11031736484439154, 0.46447585404483693, -0.011221063478852218, 0.034802016747764855, 0.1870838623818426, -0.08514918506021925], [-0.9634758018989756, -0.04332277693018098, -0.6853643075847107, -0.7238738089129838, 0.06253247556440067, -0.15373512589439314, 0.2798590133924562, 0.006885989315619033, 0.42977775495349096, 0.09236497356130796, 0.012514626563072201, -0.12986244321425736, 0.20607187099387853, -0.06955200989181254, -0.17496026075965032, -0.23380491322405775], [-0.5393795605021263, -0.017362920590853908, -0.3178456309987178, 0.821485497836046, 0.43771634807214777, -0.6053322271275068, -0.4661219081881318, -0.5766939613299178, -0.16706892199374232, -0.19135899010050675, 0.006056849188056206, 0.09528200352272881, 0.0721228902946581, -0.2294163504893079, 0.17093067422715133, 0.21865781289797023], [-1.042406968622584, -0.12902388049725258, 1.672823185703704, 0.006117487304855807, 0.9551919676218789, 0.05238523398809401, -0.19493450052328035, -0.07162008586674076, -0.006180166515590659, -0.1346447947752166, -0.11759733222847492, -0.06606238628034233, 0.06639561991635787, -0.18292285368631275, 0.09966068551811227, -0.1295106731786478], [1.0330198955012788, 1.0395595231665677, 1.1792045956506108, 0.691186087919919, 0.43638993561044587, -0.40246668433267463, -0.1977849121014057, -0.4960755035731355, 0.5871100769440227, 0.1665283164375946, 0.06956485888099241, -0.024870215247224683, 0.021827850551561667, -0.05770856247447373, 0.11908149005870042, -0.13841103209951697], [-1.0870134068849813, -0.21661618292912568, -0.3638792294315514, -1.5494968112786545, 0.4102942180733416, -0.12055195404982692, 0.09494434745780371, 0.38230588659084797, 0.023985465780631314, -0.011599114128353032, -0.25402862694197853, -0.004426986876196202, 0.12933764230075664, 0.0018560527143085535, 0.08419326411188184, -0.1176688467647406], [-0.3335814862156167, -1.0956853813946124, -1.5325387504999066, 0.17463490702701032, 0.13777736084993816, 0.19828832528485985, 0.41625731069242466, 0.041224903628896414, -0.22585918237230582, -0.1307923939637129, -0.2624553654533584, 0.23591068465185025, 0.11069578946483806, -0.1764960284542543, 0.002138919921293764, 0.3558108853379767], [0.011904506040164022, -0.592710174129431, -0.8824139149364639, -0.5623098207297952, 0.37671659148173875, -0.5334413954713573, -0.03366387343928227, -0.31333572504957236, 0.008137589500816722, -0.2536785837774169, -0.09381508851178999, -0.03162381949346284, -0.017184667783300814, -0.06581217193331373, 0.1173862239841699, 0.09018500534043415], [-0.27621186078351456, -0.3424998438392174, -0.06596399272996742, -0.4587172323119748, 0.028444207033045683, 0.15006033965783205, -0.2322359776053882, -0.4064980355672252, -0.14161465415496283, -0.28764201731340744, -0.18575990555353042, 0.08168766609561041, -0.14670862459835257, 0.23506750568559467, -0.06096573207749557, 0.1965497510838043], [0.3658350061550448, 0.49031121975051345, 0.3073781291218911, -0.6816738814461403, 0.5210490305587496, 0.2715493977094488, -0.1779517856846836, -0.0377349417065535, -0.08618151404214061, -0.1572684666638001, -0.32996807491442276, -0.2349931324129476, 0.4560125483047056, -0.01385517155818419, -0.1162530060251907, -0.1269345722638133], [-0.4590415064057849, 0.41158456952390626, -0.19720926635095892, -0.0742707705966114, -0.12753145457143034, -0.0987558064173345, 0.03902050943563266, -0.3967966600593631, 0.4732600462161754, 0.6214285111276039, -0.1868523760275899, 0.3139230504164142, 0.018347455394568342, 0.17803961523743383, -0.022877600824145704, -0.028690928391073983], [-2.0007262390934595, -2.3928073635665985, 0.2885358769371042, 0.2908954132219693, -0.09631697414041952, -0.14579117787718526, 0.24556643432367786, -0.9238016257582141, 0.21394222049774064, -0.23343941750615996, -0.30624418575049106, -0.11429753723175096, 0.1551976668990867, 0.12343612028662784, -0.29454129003687884, 0.14339244459784894], [1.1931625774232257, 0.6676939230997229, 0.18359297318797063, -0.01596125616496225, 0.3738621779853017, -0.02873529427563669, 0.04641914459462921, -0.33962988830734003, -0.09888631765844656, 0.11445450815117345, -0.13957466808226285, -0.2405986479752126, 0.4350012669898518, -0.05995898586664866, -0.002868054847085825, 0.1435508078678249], [-1.1250682080878907, 0.812622769336987, -0.566883060457564, 0.4603209504805119, -0.4109447548577017, 0.243872492296503, -0.6257241552291994, 0.19830967750104803, -0.11353005099316443, -0.2147518157401476, 0.11383218367415916, -0.20989619793678158, -0.0018657484381100718, 0.11795934128948038, 0.3938136465225589, 0.015820176611822907], [0.21217501102719985, 0.26598095200889194, 0.7936821045917842, -0.5119430471818477, -0.1505670954443703, 0.3366402716647365, 0.13344669913513107, 0.2979192635145991, 0.04129490509278645, -0.09598837675464367, -0.09168492434560273, -0.06542292750831759, -0.04896688088496177, 0.18383999582776483, 0.022186944701557236, -0.27480219301628317], [-0.2705767769645389, -0.7430365619293402, -0.3609843876685824, 1.6002272215621827, -0.10220882077140152, 0.15549654718486663, -0.07552802823368601, -0.16479761091528228, -0.3535188116077713, 0.027173898848481273, -0.07302543699295119, -0.3018449883846689, 0.02234104943630593, 0.25275314149071315, -0.10061482098543095, -0.19893462042015245], [-0.250916984773813, 1.0831714507648316, 0.7330640671693185, 0.682527590922626, -0.026999207668376674, -0.044165085482683705, -0.026459706002019908, -0.3256459665301602, -0.2059646296579099, 0.0248987172757484, 0.2602372145152311, 0.6561256301301486, -0.22009864794297523, -0.02243808295490883, 0.14878781176134462, 0.06372782849864397], [0.7078297308914067, -0.8847470881459332, 0.3215433600232643, 1.5242678930586344, -0.41437493440197704, -0.3049191173081102, 0.4709588910394766, 0.11746366327781198, -0.21442254174132314, -0.3032571422420316, -0.2468145606363532, -0.3213276790079297, -0.06083352746713974, -0.13380213774827393, -0.015532587304649244, -0.1776320610790406], [-0.5242190955067912, -0.019563716085048078, -0.6446955663059818, 0.2786022399202206, -0.4005076589932795, 0.434572775028378, -0.8083878817807192, 0.2331021045667184, 0.11120361514076596, -0.22636283694357326, 0.04548117607322776, -0.14551635308539526, 0.10979667968002137, 0.009417532953726738, 0.1549365499407501, -0.026328402445391152], [-0.8388332752382658, 1.4625182819217186, -0.3606959232011887, -1.543428448784976, -0.14602265610283552, -0.00714700367258095, 0.09957927862218138, -0.33659060398824026, -0.2472096179653861, -0.2195265113685988, -0.049454304129955204, 0.10374950209361644, -0.1160173899106461, -0.1401068221576831, -0.28626081463453246, 0.5537405848829245], [1.5197986336966736, 0.8907592065065026, 0.4534513132251163, 0.4898147105823271, 0.2129552198177323, -0.4311186138904355, 0.5850474720769023, 0.29331225349144685, 0.06383065288173054, 0.3749716886325666, -0.2776391589138687, 0.04902341935039553, -0.10842730167195135, -0.0010324446104963572, 0.18223062041156743, -0.07824456707571742], [-0.2463789070096597, -0.17717350181307107, 0.6403215454206439, 0.8670584268943754, -0.010707118469376121, -0.19367258318792474, -0.13300830691795656, 0.1728342233612832, -0.21380379019712936, -0.08733865191060053, -0.2888764595500193, -0.16062068395792864, -0.2027897977654411, -0.1777733697025587, -0.1755901040718362, -0.20940426491821412], [0.8143609424641932, 0.21271392785548016, -0.44212763012453743, -0.22019172507770915, -0.11640344555090869, 0.1642017222217101, 0.16529991545081812, 0.9735012486398196, 0.38591102528313054, 0.4140395315078077, 0.8233271356027138, 0.3493877129658034, 0.0629280523184421, -0.06329972763983728, 0.26399272851911604, 0.15520533855032187], [0.9598475948080473, 1.310657634125577, -0.32839505388277274, -0.49963521248195203, -0.008931961847006386, 0.23026307864053486, 0.05312048124508309, -0.23541302951714224, 0.2193061634120571, 0.20948791116340856, 0.06233173369360233, -0.251970859919019, 0.04372121763250078, 0.16285520509638454, -0.12941173816104837, -0.16749181010652373], [1.0732448650878823, 0.6699176936788412, 0.6159874667277402, -1.3177627000375478, -0.33232865738319917, 0.05555039744089565, -0.06360075704978582, 0.10343763182700852, -0.25341125561923183, -0.05774878622206656, 0.17308240846665587, 0.5949562157460317, -0.2388870905467121, -0.04603768168684057, 0.04286278445977517, -0.2921160928714917], [-0.25949783964357714, -0.43811425375401547, 0.1710134515697636, -1.6828289012768198, -0.6743002080816809, -0.11054301537158391, 0.2843085955308653, 0.49007806374733176, 0.04691910672738663, -0.24991188818563295, 0.03009907705777265, -0.1898879364507636, 0.09374602977950823, -0.1728943080313622, 0.06042481925428542, 0.31128786049270724], [1.0931402665341279, 0.29105951536932656, 0.3773653012428966, -1.1921642260847403, -0.22958664994364122, -0.02538611525850848, -0.15898191450699292, 0.4151277725963986, -0.1043424067892481, -0.22736031472876572, 0.28060729540018164, -0.21748629399483801, -0.02198312301502586, -0.1583811374782242, 0.23180666881806308, 0.015548242905114744], [0.026019286012191375, 1.216490090328229, -1.4453760820299741, 0.26758636937811814, -0.5589636358825758, 0.10250619713521042, -0.681677082277679, 0.18468816565693846, 0.08416185630481156, -0.16716150701493307, -0.06730130454273564, -0.12105613022373585, 0.006864388176224964, 0.15472060028548676, 0.24700316593370658, -0.07081452536337943], [0.6221671114153674, -0.5964066360527882, 0.7228159576457611, -0.355380483077997, 0.2260461513382307, -0.2693453717357461, 0.32619009265198023, 0.026048029032015606, -0.19283348173895698, -0.266281204796892, -0.15322482379636537, 0.20864898177696778, -0.1298082188626583, 0.20941575813261762, 0.2216508828216762, -0.11238280500606557], [1.0586268330256503, 0.49446272870750196, 0.18598180812211076, 1.9362601879167822, -0.47522604421601317, -0.288163383396822, 0.5390628906947996, -0.3930701414648667, -0.21920557758238995, 0.36443781011668513, 0.05421890546123861, 0.2892678051125008, -0.26785389401710946, -0.0021594952381914973, -0.2227435419094399, -0.11328789937055558], [0.7315706803988602, 1.1932186964968647, -1.0996783411734934, -0.665511345886152, -0.4574474228410819, -0.15869237073994402, 0.7472575281018494, 0.07024594347877133, 0.4618676276416802, 0.5354048161612948, -0.3678420711773088, 0.06580686740279837, -0.07160483979875358, -0.19589537171674876, 0.12832668002856032, 0.43687771128471464], [0.7354115934670449, 0.8326929142252438, -0.0687212768582034, 0.7319512611348431, 0.3403149718215134, 0.288420436660886, 0.6558345624401439, 0.3463802947724892, -0.1392652480552467, -0.22620576023353572, -0.09761281891406162, 0.2537620311237428, -0.038198629637737604, 0.12408165355640656, 0.07195023868713886, -0.007682812569109519], [-0.8222479345055334, 0.21386274739933456, -1.0612729030502415, 0.30168439478760056, 0.42306763289614696, -0.4234544920044591, 0.22288828874594618, -0.2800957578124974, -0.3160014522175938, -0.2904541181736962, 0.1849798764558783, -0.24229295135791887, -0.24212786313237844, -0.04245829099559084, -0.09242760910157888, -0.049455402781361804], [-0.3519044897951961, -0.550829582183126, 0.03315695085111627, 1.7486796068093307, -0.7072776922818501, 0.04740364799998543, -0.13626631149818677, -0.1973370914584338, -0.10031579598380903, -0.06528333714563996, 0.3271049568087492, 0.12055840611191003, 0.05007763728900009, -0.10463301411506043, -0.047142084166292904, -0.07113355108500169], [-0.7839484888033477, -0.5157211892932465, 0.952801272935293, -0.44698559900344004, 0.5013009961233366, -0.23660489648374414, 0.2506815586582149, -0.060155975765160484, -0.30408098980984366, -0.2203575070335797, -0.2175958298483527, -0.2549205332731509, -0.277820825091586, 0.030699441882560883, 0.2618899755539496, 0.018014509241377815], [1.5021033656675413, 0.22164041009658175, 0.06437618247853569, 0.31766778959832537, -0.05866247503611379, 0.6408005268149867, -0.35485675558861607, -0.025486368051333683, -0.11618432953918102, 0.11933735825621374, -0.18457047977605778, -0.21052213718964463, 0.15811137507710962, 0.09368719707111361, -0.06071223601471007, 0.08504238332829386], [1.4790172686249476, 0.6088309849185655, 0.4518151478010083, 0.21476729520514054, -0.190079575967047, -0.26704535491482945, -0.18433041860868069, -0.13416790605711443, 0.015105339283828295, -0.024548749194626292, -0.0034939463110786146, -0.042292871012994004, -0.26518687569658467, 0.12774564904788246, -0.05428190250680236, -0.12391074974900367], [-1.2365982219277765, -0.7693458322047464, 1.330783193818233, 0.7732498472571256, -0.5149396309637781, -0.2012535280541504, -0.11867888263900006, -0.32572684169954036, -0.003590570979840602, -0.32204651187885375, -0.14800794764356223, -0.19991647380462568, 0.041563194887878144, -0.11667805914829417, -0.18527237682449096, -0.04141270708271778], [0.4637314288503204, 0.5924617509571097, -0.5123308644412934, 0.2991308831672433, -0.168864603204389, -0.7336479191530472, 0.19699485366345607, 0.21408835211262905, -0.26129440657673897, 0.3961795969264631, 0.205373780746951, -0.3106331676557701, 0.05311114045279981, 0.04886929460787179, -0.1350588512657045, 0.010945052936314726], [-0.6927315950872662, 0.37266996383008144, -0.6674064483736358, -0.24148432874058007, -0.576143677226115, -0.4378399805411376, 0.11261320191496378, 0.032573002703495925, -0.3274842663274081, -0.2161006687867875, 0.18054130635892382, -0.0035417646204429516, 0.17008888791447038, -0.28815535214260635, -0.012966638632786803, 0.34678749982965557], [0.42045219718687904, -0.2697525688888335, 0.5708163447266608, 0.41481490799405096, -0.43545298053548237, -0.26869862351466356, -0.2846219372056364, -0.3532943062781703, 0.3514924685252977, -0.011092563767849324, -0.12511687613824088, -0.19712778396622332, -0.004047715295175129, -0.1883757755962094, 0.11489603007800095, -0.22186332210726453], [0.3432181457340799, 1.2073308572185437, -1.3582542575540957, -1.5959637972120415, -0.295478273552883, -0.3747190694371471, 0.14432125073183114, -0.06713859051841722, -0.3113715210509929, 0.3974787228036864, -0.09492280550853718, 0.05857217650424718, -0.34197608074532065, 0.05849632712697397, -0.1599783427255177, -0.06489399418847092], [0.5542987857362855, 0.8641652495393991, 1.8111682608356514, 0.7089565862973961, -0.24483112261455406, -0.8904282581773126, -0.4985120478873994, -0.09365462460342965, -0.1765570667924943, 0.45073459559332074, 0.12496883069932409, 0.1470887055413663, -0.05831017569035317, 0.0026678247613813595, 0.009504050825136919, 0.13510395290239216], [0.7301884909275538, -0.7673849951446188, 0.6663301254371379, 0.6282069786150984, 0.15081589967923084, -0.08488017610581577, -0.23112656510707288, -0.10353840798477579, -0.10188497012250942, -0.17560623668995395, 0.03770363961313753, -0.24425483364608191, 0.08887959483401695, 0.13230877390512422, 0.12478128203705265, -0.0651334709288617], [-0.8202022972897673, -0.7792265891112486, -0.11899808822273399, 0.2504265773410541, 0.452867523553968, 0.6644251656574366, -0.32335975293825603, -0.08444087408421153, 0.34906290969572845, 0.15953815744191088, -0.01908947246427729, -0.05355814351843086, 0.0965640452152667, -0.06276642546747874, -0.044452268064258144, -0.0782114993080059], [-2.3729277481748894, 0.08546795494905911, 0.19188196584014564, -0.20524945670584793, 0.2703846951368995, 0.5538394604999745, 0.23006533168702425, 0.31045496846292847, -0.1465212396329143, 0.4477722026626572, -0.09120579452305018, 0.018770338119464887, -0.08558419055486637, -0.2172156018270159, 0.011801623443519439, -0.058864302950117124], [0.2670720087102272, 0.43040784708835245, -0.937928807661347, 0.3757635843115774, 0.024114068380385757, 0.633969726832288, -0.0393277746780499, 0.20961732349423254, 0.30013572293541635, 0.011141201497245031, -0.08439603727966608, -0.24005882482425428, 0.2640143000583243, -0.10210451059446742, -0.04105209974236563, -0.10033365335555762], [-0.15884160664800195, -0.8235617215147617, 0.1721374811916587, 1.4255397182651934, -0.07586014224461703, 0.3354919200787706, -0.1091794739581033, -0.606646172661505, -0.24333393874762851, -0.22612042477175306, -0.25772325512955124, 0.40624731326486596, -0.16027050417383673, -0.22610692620607697, -0.13354414152004038, -0.06970164862219949], [-1.1525031673171886, -1.4562167414785876, -1.5212766780248064, 1.905295673261986, 0.0727443510436517, 0.36570096665982, 0.1666081296106506, 0.6355602182750719, 0.2802850026149019, 0.23527540056494978, 0.578559368066193, 0.13965967900107693, 0.23390852745791635, -0.20922703997324513, 0.13365025662255983, -0.18720298990981818], [-0.1590689347213307, -0.03063797280078879, -0.7332774113749884, -0.9534043133504309, -0.0829908923837121, -0.22448543734072288, 0.0036028783469366998, 0.5170558308235489, 0.0063651829238094695, -0.16303868807091265, -0.2052938638844104, -0.23688754816260166, -0.08869134695000269, 0.32744949939610296, -0.04551086336547505, -0.04457447483827798], [-1.6183770876649264, 0.1750133100826107, 0.21798400216098185, -1.9685187409543432, -0.06427275428247271, 0.29851872622013154, 0.3718077749500127, -0.4333744209599872, -0.3016956220739949, 0.0462884474884547, -0.13509941894921088, 0.31394043455697346, -0.13873613097800902, -0.12180377218943089, 0.14320337906450492, 0.37964661749710293], [-0.8097495132637011, -0.6430724192957225, -0.04168060471403082, 0.20719513668776277, 0.051629011860322475, 0.12006761162447079, -0.21800811350146804, 0.22659641438218694, -0.11342766699664278, 0.022058771062624948, -0.16197241108785126, -0.004264184902978577, -0.004236462980420259, 0.2826187134628162, -0.05381601314583092, -0.03690945055362949], [0.9731587341740221, 1.243152866255614, 0.953519960997154, 1.2823815971196046, -0.14064818421104794, -0.03963311181210646, 0.1281072292463728, -0.16048017362991465, -0.17813288969337385, -0.10964681028982572, -0.34511999215154426, -0.2169396013110023, -0.17688635442895503, -0.15949663525408495, -0.0636975945532813, -0.15294264518370942], [-0.9110775581173153, -0.47344569000820863, 1.021859409216466, 0.25082565999423123, 0.9111045600572371, 0.14307290808403936, -0.40454497500186526, -0.2691266388024483, 0.10712254228833992, -0.2447222085671276, 0.19758678821703365, -0.0287950084425447, 0.03060122158520557, 0.1629846449967368, 0.028930046600960446, 0.22307852192954647], [0.06312687084834381, -1.7477317797846392, -1.7086643337144816, 0.6841026811568458, -0.10542534881923755, 0.11334485248668227, 0.42544770888452804, -0.17388073157246012, -0.13450821773567026, 0.29350754444894467, -0.02345742276166609, 0.21833575456774137, -0.0655966049963391, -0.07139684008995649, 0.33446793176744, 0.07032819624294508], [0.32851904202211835, -0.24226291544524584, -0.39355560361876146, -1.7231563991326846, 0.054650000362250505, -0.5987013346376461, -0.4832648498116262, -0.12828738249730356, 0.23698361020504, -0.21628257133839562, 0.2898061081213281, 0.13776231809329917, -0.033047595553313214, 0.2146055825813859, -0.31504718946034527, 0.008713829669723009], [0.3528826062965922, 0.9479192037893666, 1.4752060298941403, 0.016150815860495292, 0.11309260251573673, -0.5498400188713953, -0.010320771014826717, -0.19693610768645609, -0.28893419999569886, -0.3483119184467231, 0.042747836214795616, -0.3012317676830725, -0.1351668144115369, -0.27789733281188655, 0.28123965040502497, -0.11904836237348064], [-0.12011594004127227, -0.957850315716792, 1.0942712717582967, 1.6403138634239218, -0.3997333820012205, 0.13408692139148876, 0.0308339196863943, -0.8804564616369543, 0.7175691320204166, 0.5323460029348417, -0.14376716978750403, 0.16112257953031256, -0.12865672144499588, 0.009144586626160479, -0.062113833918906576, 0.1361139898922081], [-0.456299140709033, 0.28267485657225033, 0.06441091037691125, -0.5942047657957977, -0.11503098314000396, 0.16275540049150575, 0.3020119219671588, 0.4954222560713316, -0.2975647639367882, 0.009919999272494026, -0.050709718428425074, -0.17731998543998886, -0.11872705833308787, 0.26678092029468436, 0.00033876252724790283, 0.061923548234030734], [-2.005209778221026, -0.3048292066184438, 0.5343186644544532, -1.446080082686859, -0.0218334966771933, -0.1757474526808695, 0.20340640803123142, -0.061727916697794254, 0.08865120420682729, 0.29369103286353987, -0.3260378807772294, -0.03688713434902167, -0.044159270241076874, 0.10822707675539711, -0.10736264580033962, 0.3174398749871802], [-0.6418377300504591, -2.914739543047614, 1.149997466925153, 0.45815756239341154, 0.1661912057362044, -0.2265551363115458, 0.18943279348725367, 0.1186036432003074, -0.08217663325930312, -0.111212431125874, -0.38054311320726547, -0.056073709013597484, 0.10422979811278145, 0.02946816299586204, 0.047170972625581106, -0.16893560388504814], [0.08512143526298298, -0.21937648615531957, -0.597524222840708, -0.10920361865628594, 0.23598040435679754, 0.19842659292333636, 0.1535735969426439, -0.2254981715672948, 0.37063962870239503, 0.02991199435727317, -0.4122262568171445, -0.23054266511277313, 0.24249142785023237, 0.16937669235693306, -0.23044420083578943, -0.16603013566907615], [-0.2073469911537505, -0.1995919771505433, -0.04878109536009159, 0.0911151003894245, -0.1486994264451419, -0.17811692753492478, -0.18173418162728897, 0.1410381423471819, 0.21250378920338273, 0.320454153808251, 0.278518578182236, 0.04335544883516959, 0.3226280447997303, -0.027158401369036297, 0.24460464181518607, 0.08062756761725019], [1.3210245499922548, -1.2740166196119358, 0.22017435147903777, -0.6439113426455302, 0.24042344074240488, -0.1079032221306533, -0.15847965839013492, -0.1683264827548959, -0.33761676102090754, 0.30991465565090315, -0.2114100994170293, -0.014546564064328384, -0.2117699314075351, -0.3122853331851173, -0.16485187525721304, -0.15914429234178318], [-0.888936104758071, -2.095875882009992, 0.5338167245033957, -1.002325085657448, 0.10402492830345372, -0.25438465241458835, -0.10547269309804579, 0.1077727547165572, -0.30655041041106096, 0.06970190751159973, 0.09904867231459254, 0.1202637799672575, -0.1808641390635882, -0.08288488604792761, -0.1769624256045702, 0.08755527937440327], [-0.5767378192448028, 0.4339614200414146, -1.0123421603847684, -0.016272158967073496, 0.7424685656352414, -0.09353311781206697, -0.11690068750118779, -0.24400905631917047, 0.13558643094959427, -0.268221936933595, -0.3743863426592923, -0.20103569590201864, 0.10134430059546325, -0.14490717931744787, -0.2659947582023628, 0.0513623400005625], [-0.022035879833663608, 0.7309211002063327, 0.8918564099260435, -0.8910956463654035, -0.5167679749410593, 0.2365883882881835, 0.07045349808629807, -0.8655262804503429, 0.16515198236453243, -0.25221820607822804, -0.1978392473109435, 0.02662431558416148, -0.3150025312515871, -0.1544699137016364, 0.044783110523021266, 0.15637238348288834], [0.7934532016435821, -0.07291352048142508, 0.08453162754155674, -0.2500021383272938, 0.14896939847600268, 0.3049869611009035, 0.5692726079752966, 0.8518672390934584, 0.03102188542798184, 0.34932502375770647, 0.5070057699151787, 0.028191658695983918, -0.07538551240545416, 0.1790412271983184, 0.33729238520400856, 0.193237249210341], [0.6770242145128543, -1.0707457845745942, 0.2093677870426307, 1.110190255444823, -0.4198823407620478, -0.36282374922830757, 0.05802446262788432, 0.010723336553585022, 0.07333095431150044, -0.10313500260627226, 0.21986294045402127, -0.21505372255285135, 0.08009909888508256, 0.2436524076566057, -0.19700729767874445, -0.021226682198198107], [-0.1936644968212531, 1.8275783983123992, -0.6962958942724393, 0.1675805215526043, 0.4224269146166815, 0.2371326233739459, -0.1534356589692719, 0.28574259541488634, 0.011683944019974744, -0.2414108235302911, -0.15989353279352808, -0.1415384092389889, 0.23832302291325774, -0.11436462306251718, 0.05934954189386416, 0.12026623280816306], [-0.357195505087868, -0.5398738196306724, -1.0417110359385817, -0.5709248645598096, -0.2321479055694429, 0.42306099791557195, -0.5678220713286283, 0.4925301389706037, 0.19304094105434424, -0.03221805582687468, 0.5620019606954116, -0.10029079971308012, 0.07065142600281088, 0.0430107246137221, 0.09857896956383998, -0.1810711710165465], [-0.0034226671076941864, -0.7047816748087472, 0.7752417760388015, 1.4477629827441125, 0.11063149926865049, 0.28167828955781504, -0.45556746032198303, -0.47099643557945803, 0.7234157290234562, 0.3231920593213606, -0.030836539175480026, -0.12529897672207713, -0.08013438567966642, -0.18623361894889792, -0.18127947527080984, -0.15396664500855073], [-1.217262167407435, 0.7604412896526876, 0.1438754817577881, 0.19660545504266613, 0.4140999398120498, 0.38093723815913105, -0.35341374404365683, 0.10157059646025397, 0.1898205082518352, 0.12982034890397548, -0.08680462489046034, -0.1772886717957979, -0.21492667984933736, -0.19964767146405513, 0.036860538307281907, -0.054691855823946096], [2.0620904508947495, 1.0909615079048052, 0.2768618420216088, 0.1376175657518265, -0.03274823141764907, 0.09249402682666427, -0.19705503134251762, -0.2784533723902613, -0.10006401396788193, -0.008811860126503465, -0.3521276525779458, -0.1927325273547041, 0.11267805661093422, -0.015098436660070505, -0.0591147828450159, 0.040823429970108745], [-1.7325199521366796, 0.7135198513052988, -0.6988247747192784, 0.14018303601251886, 0.1407136498734871, -0.3950913872215879, -0.1763457268487508, 0.04887116262209825, 0.16895174941503446, 0.16907903910580552, 0.2146870231071276, 0.179109157320097, 0.054804242076888984, 0.04321775150535775, 0.2282578172913025, 0.17912527689367932], [0.12799137113827586, 0.8816603771343107, 1.8283200769578523, 0.9317002633131262, 0.49667609500585375, 0.24776587174074483, 0.12360149672634613, 0.43274099062097465, -0.2044818308539648, 0.26193450689312664, -0.32553232871233345, -0.16854421650067325, -0.0526733383998817, 0.13248703813586976, 0.163899926842462, -0.038240136270334346], [1.0941232861615287, -0.18723506749345623, 0.39640305752803123, 0.7216857381108893, -0.31027388142378576, 0.07918125853319871, -0.17992462678426177, 0.028487625751063297, 0.24705687374255525, -0.17349286537595626, 0.5739698556379055, 0.22744501527369695, -0.07372865892055472, -0.053425586367589956, 0.19601780814310696, -0.1312240010140496], [-1.135662168988669, 1.8488422991077524, -0.6680730955703554, -1.2836765483258745, -0.09380277588511153, -0.14701549658135854, -0.4052791647220934, 0.4111716462725723, 0.5037451437381999, -0.018533121340351306, 0.14075694163148542, -0.1829387632833511, -0.2533076159839374, 0.11565596990271974, -0.10043436117911124, -0.1841065120544017], [1.3909501235599062, 1.9176294970473422, -0.6573773306083027, -0.6328882137204881, -0.18428237052808197, 0.4260152994476046, 0.6763782560216572, 0.10149856032995175, 0.01975850498336161, -0.25148851617371343, 0.15341586256193634, -0.10670752203412683, 0.03874242914170589, -0.07697357771171665, -0.13021596509385724, -0.012379380241412406], [2.6057839671907135, 0.1233178818110948, -1.8221600386008865, -0.6318680821026389, 0.24994873775768675, 0.13496063499104852, 0.5334755480980209, 0.1254687508342873, -0.15456579215709038, -0.20963800158260162, 0.38370077375874023, -0.0021835088179765374, -0.1236597912336724, -0.2760171501963016, -0.25835632518306717, -0.18527477351046515], [1.6935138293842855, 0.6121967633123605, 0.6658548320771032, 1.1677781527882505, -0.2685054916157851, -0.3890744557759558, 0.16722273627044723, 0.1142982743620253, 0.02911044477979992, 0.17059689853086304, 0.04154381788088003, 0.0005042668777488855, -0.17542153630646326, 0.21523205268095857, 0.2129606868641885, 0.08585283146932747], [0.6032391533585246, -0.2754927099771163, -1.4677597617207958, 0.40534315332727244, 0.04943193717230641, 0.2937580462718391, -0.17496979585772596, 0.01736398867688739, -0.08164424533344977, 0.023611424044994302, -0.3630243823430438, -0.22677404615787713, 0.016035964420919122, 0.23859657366067344, -0.18550803130157306, -0.06838620089198431], [-0.869662861453164, -0.02773225768112257, 1.581413516016797, 0.4977142534020994, 0.6696736057964113, 0.8478016514610524, 0.3776746496072511, 0.08681673551658668, -0.23005421980080495, 0.007195977531264077, -0.40658267032720746, 0.2571340934663404, 0.06690015152828706, 0.42403559826554377, 0.20342186453286434, -0.01685961492216318], [0.09664036636459282, 0.08133024555877832, 0.6464807736557985, 0.8705941882894083, -0.07021218849499172, 0.17724478157863838, 0.1094757584749565, -0.2233939296666691, -0.33397732566656513, -0.05902812017828739, -0.23277197779079387, 0.38101281394397346, -0.2971271436712899, -0.20507430167276236, -0.005050811666481589, 0.14973803447744166], [-1.0347065827331166, 0.1884969188799665, 1.5420185700246247, 0.7071066501080044, -0.11401753794730066, -0.14114287475604825, -0.40598390038683896, 0.1762400947949602, 0.36632022500813777, -0.07269043295023243, 0.22622023690060192, -0.06066659972398347, 0.07235867543884415, 0.06357801664210602, -0.04974174259195823, -0.1085541911940353], [-0.5812095340976267, -0.5853862800914227, -1.8929628707177018, -0.8093122524529495, 0.0631477541932176, 0.292918228860751, 0.5903065383356203, 0.05924486193546064, -0.17254309573547144, 0.0627165236564784, 0.10458595625293307, 0.6213152542468979, -0.18112031085791333, -0.2662650188904016, -0.22274657721203323, 0.21395647103841361], [1.3686907518796434, -0.0396167235874195, -0.7955062539598904, -0.5964515471071424, 0.45805644920371247, -0.06352729629966111, 0.3303951762924782, -0.09653620925980134, 0.33129534886533796, 0.05479023050130303, 0.31741205200514644, -0.039979789836738056, -0.19891256871469953, -0.0030186705582387506, -0.040735102486166255, -0.0025185037456459183], [-0.0432974510232431, -0.07273506896083719, -0.3399081204985975, -0.7855194022523365, -0.15223927299112247, 0.37336952465612855, 0.45984465588416684, 0.37911836841957613, -0.01691631155911386, 0.036564347232696706, 0.1288922436852848, -0.09322922604359121, 0.06852743243946895, 0.04188034046243975, -0.1478537752944517, -0.26016573916279706], [0.571008998144309, 1.3988751770878802, -0.5344852471911754, -0.5623082781652748, 0.09173916249783215, -0.0965409678317637, 0.16102368555777924, 0.47080253932165483, 0.1883652337010364, 0.018034207388859275, 0.012063202588289728, -0.01988904688856317, -0.11155168049024547, 0.16320347468400734, 0.009045170582140025, 0.1668610393975089], [1.0254062405724655, -1.2868187701304583, -0.555797374663985, -0.40243639446064816, -0.12365746557792834, -0.03152992332842581, 0.3471188684776398, -0.01297263164257012, -0.1796023838849894, -0.20413975109875465, 0.4669355085956044, -0.3215627541315921, -0.27857903711918813, -0.31824472236959406, -0.2430024869205161, 0.16290558524441046], [0.18565668467252297, -0.22337103782737666, -0.824233517883062, 0.2722287491794636, -0.382531619789114, 0.24275624586520986, 0.5005331669871834, -0.4891672393689514, -0.19084156314080097, 0.08113470712666633, 0.32185012774288674, 0.6568571318213033, -0.1699394989181168, -0.03915133356051838, -0.27586110425377314, 0.42006201559148926], [-0.9285813605303546, -1.5361930200736078, -1.8623510082224404, 0.7015513149757375, -0.3559285140295952, -0.20983841266324912, -0.35803082613037907, 0.12499839832249357, -0.14190334364103688, -0.30473317920774856, -0.012555808971958437, 0.5412887139609209, 0.19576483663960761, 0.22199388050111216, 0.006042099762028221, 0.21714079629354416], [-1.379988240186553, 0.4224920054639304, 0.5918461371390115, 0.7585740263178707, -0.42726182727751416, -0.3818157961423629, 0.26591748241709806, -0.2433652255959496, -0.16035435384390417, -0.2079020204539674, -0.17712528199261873, -0.2949104440049642, -0.13909822990794632, -0.18458590058776964, 0.017987253224233755, -0.12303868986848544], [-0.0958549508551286, -0.4678174881251779, 0.05986547980884253, -0.6137093945914555, -0.8532093379115882, -0.27189920673945284, 0.30400333268210405, 0.11529623574967493, 0.05346469777664722, -0.24400005628857094, 0.06858984441492467, -0.21846933016985362, 0.09222956051940025, -0.11606848958665317, -0.16674785149169594, -0.00843530810786847], [-1.0095433861512055, 1.1456323116085954, -0.8313571601205247, 1.7275451717696255, -0.0045594452905018965, -0.5292883012356772, -0.47720133143278454, 0.5787330247551149, -0.16205282782451064, 0.14016692653480614, 0.02203777843096014, 0.009538679724084754, 0.24707406939289203, -0.28422471284087725, 0.21507843029742263, -0.1509422534381664], [0.47088272547068166, -0.3840486279929984, 0.37992102708305703, 1.1732570087637921, 0.2556283578952396, 0.8517729382081464, -0.4015210515884609, -0.18394458312334996, 0.024538785077462294, -0.2562259919590489, 0.06077554039718961, 0.16316060381132066, 0.047457315174830664, 0.20555076829755103, -0.018248831231092735, -0.010671394291423253], [-1.0853884584672342, -0.8064705620902711, -0.9721456976162616, 0.1296984185644301, -0.017235122934136135, -0.3069281119630403, 0.23480241918205327, 0.2688195935194948, 0.051729966017806356, 0.41124657180923185, 0.08344738163907274, -0.17563669830515624, 0.08333766318900274, 0.25200395413804044, -0.25511220072833785, -0.1839501163177413], [0.3800385540342932, 0.04848970983029934, -0.680204739567154, -0.5497472328482813, -0.38661137798185125, -0.17533167331888405, -0.3540589055640037, 0.17939703218721384, 0.046689748448625244, 0.34378407422686375, -0.028757803411774887, 0.2623285513440685, 0.29272656548134174, -0.010603426846001707, 0.2503977576744582, 0.23189822721434128], [1.0235075475413455, 1.021739311551396, 0.10140635156085458, -1.3160728901628755, -0.02800275696866572, 0.1922207662004488, -0.38085200108187756, 0.39213593287320525, 0.31826315746732414, 0.322111386244473, 0.0023518665884658314, -0.25253489371518556, 0.21612259904726472, 0.2870148326653547, -0.011203312519068287, -0.2370199648393993]]}}, {"name": "decay_uniform", "n_cells": 80, "n_genes": 3, "k": 7, "max_m": 1, "decay": "uniform", "k_per_harmonic": [7, 14], "locations": [[6.4285101384599805, 24.963893122005747], [30.074917881167874, 1.4344504185972273], [7.396304228872797, 46.41055114801848], [3.5210288077098415, 6.488697469964899], [47.41642266458875, 31.094179639819142], [18.44965618648955, 25.569501090163133], [33.14214762583996, 13.765440788056466], [6.898403643347767, 39.401979725199595], [33.518029205124186, 25.61911567415802], [40.8368217984829, 27.453763443501316], [49.045681964865274, 10.225473066502245], [27.68651814326139, 24.181234846169385], [17.663742753022404, 29.579765197452172], [11.765061583379028, 40.11013418892417], [43.36667759212073, 6.437983561392552], [23.353660336913556, 13.857244626685217], [4.15584988676212, 44.797215412518376], [21.497434602391767, 7.384564998104704], [33.66811786379554, 10.110801389401908], [45.07155393440885, 10.857412870926408], [1.6537343688714345, 10.038447708060966], [17.287393687781975, 23.44540817112423], [45.30671694477803, 34.86805443681489], [16.966033037122262, 0.8438607548748922], [7.991184705249049, 49.821793776983526], [22.98579899465923, 34.551995815937964], [2.7334030700919, 1.7025139473518802], [42.294505322252874, 29.394097033343026], [15.435487160228101, 15.868831914066872], [4.461862720887439, 8.633480055428771], [1.229305373259315, 41.956242418639086], [23.315159860158257, 6.36014580292652], [36.9623437016846, 9.782641497266049], [3.0960117574226285, 29.919605366201907], [44.78788758706408, 1.34717056923514], [40.25679949458346, 9.508500836417038], [4.645071081827357, 0.8981017826278082], [14.648753350604299, 36.35558719909591], [24.658947550405845, 42.64599972272639], [10.860565176074516, 15.759137357171582], [12.907042592729418, 48.91505686571085], [47.050299732571744, 17.034308792825453], [21.800075179616552, 15.715981435192644], [37.32544586527053, 2.000655127659512], [3.371946654601304, 20.20187937342031], [12.2547025557032, 42.261249085061344], [37.09035482376451, 27.289699126147838], [33.07377571567503, 34.61395533424619], [39.052741169917105, 46.37512985578414], [7.4867586893866465, 31.306507887269074], [7.181072155667756, 22.156547064234843], [39.3142394311866, 44.73488968430727], [37.96140770622649, 1.7704102040796865], [17.970603821688837, 8.152841621076446], [49.94012438162009, 7.200767881501868], [12.215722142324148, 17.860985638976352], [3.044335145459398, 43.51924585216669], [31.818071093156213, 7.987411997920995], [24.91342788562751, 3.933487931747881], [30.548989367994782, 11.583161404872882], [1.931946643237925, 5.761875184695126], [27.763131131011054, 31.84903054790911], [16.240032356709854, 32.17262147805434], [17.603304995430634, 6.53295033951164], [15.76051409616836, 19.763411312690977], [45.63194173515474, 5.783018685987818], [4.308194528362675, 28.07510135358564], [48.1696394234913, 45.36275631283964], [35.012202889228746, 3.337537332282764], [40.32007121404446, 34.16873686910788], [7.1965119625464204, 23.247186301368565], [2.466132768976703, 40.093798264232476], [35.931710859414146, 40.23140499590264], [38.02078203100886, 13.362878848134867], [39.487025724675554, 12.45853229602032], [6.89477389681965, 19.51950168045739], [24.892017644551405, 14.291107381848533], [30.28914522769588, 30.12518646046972], [11.990882910715822, 31.12837439163244], [17.86264587770882, 36.73447993268751]], "features": [[-0.818083666605393, 0.38526930227745887, 0.4581670048370468], [0.5596122240618859, 0.5419022252820672, 0.20205463691158088], [0.17412924424976314, -1.5024999410944402, -0.1654011831842485], [-0.7476197010175331, 0.12608730560642875, -0.46754626006357575], [0.6185207511629426, 0.8190757096799433, 0.30869236500853114], [0.31616814431588613, 0.09294668494996648, -0.4477978929622047], [-0.16450126423277087, -0.49564606330714495, 0.3879871341457924], [0.014113411841972533, 0.5812911986088503, -1.3286483115981003], [0.8877789284048715, -0.7626962368507467, -0.7342821862702664], [-0.19744298486173803, -0.5633845877352657, 0.2911251954982905], [-0.5741647764650408, -1.0694775505189256, -0.8458028083790133], [1.3119833252675124, 0.044258328637274344, -1.1675302849446099], [0.008377403177420764, -1.555946414705409, 1.7895665579723081], [-1.5244781602909778, 0.4787527046455685, 0.5436256643142272], [-1.4500077538405294, 0.30027651841828845, 0.9971720401657596], [0.46757528576185525, 0.261016274083352, 0.9490966814610048], [0.16090454888866232, 0.3364252880770561, -0.12671154648393168], [0.6318057260154758, -0.9413841472373661, 0.7917632588742233], [-0.5053015337885142, -1.090653373060846, 0.3652489557719693], [1.6929555515236436, 0.9616782115907366, -0.5156498276026669], [0.698059671998619, -0.454209119721369, -0.12401945613631439], [0.08952849321707658, -2.317218216900625, 0.19161476616248335], [-1.029609188818006, -0.6973986134552436, -1.4743904107207184], [-1.5165582181462036, -0.9432644007214415, 0.8255972952985817], [1.6660413474635754, -0.025205103519519486, 1.091790933563312], [-0.26398064687868195, -1.9119728247927603, 0.14991661602143025], [0.4456482631425715, -0.42861655475758254, 0.30222423421292294], [0.5725562476093207, -0.8634075676336961, -1.4768340975643026], [-0.22125416534201214, -0.21106054027038276, -0.35266321385541605], [0.9872467528013661, 1.7255887894094382, -0.4166470179838092], [0.6988867031627518, 0.9409311129269357, 0.7131564204233815], [1.0474862871297028, -0.38924397003268574, 0.7398063595133139], [2.024481935859489, 0.8036655593800595, -0.6198936689169603], [0.6077124939345443, 1.2623802917054945, 0.3689862863896283], [-0.5634006961428569, 1.5430805830215768, -1.2497670465629258], [0.5034250466559266, -0.016175574467128036, -1.1936657251775022], [1.2194496835829487, 0.3478875937013457, -1.166798177099069], [0.6017283565618432, -0.43160042891134, -1.9027885021671262], [-0.6889051253999523, 0.2635514475016157, 0.6357028862761235], [0.16556490512827252, 0.04516501126799043, 0.46999000714326233], [-0.210976101965214, 1.176954603942294, 0.14864164821343293], [0.29392155247372515, 0.540798991545746, -1.0571688403044779], [-0.7092268763497593, 1.5285791140398155, 0.33530869036097966], [-0.2826160786151785, 0.3414835288114959, -0.48162223506155016], [0.27856628863229466, -0.6658710549900579, 0.27601881733916134], [-1.5777025523190094, 1.330919793665682, -0.5129578726969883], [-1.5812411969951867, -0.2238416945870532, -0.3709961947182103], [0.15239841860045156, -1.145250608848122, 0.3974655997902583], [3.623567688368005, -1.2786677207432902, 0.3377155756992855], [-0.31071885365042484, 0.19260829481441374, -1.811809037837263], [-1.1510093879783454, 0.4596595352026752, -0.038418019395222595], [1.6352381805909817, -0.7047973922713666, 0.17449952715639466], [2.913121452537828, -0.765561436417932, -0.9038334934759573], [-0.035130084895088134, -0.04456267883565894, 0.8441672801225347], [0.12957587279758478, -0.7567393122486353, 0.21142155200757654], [2.6385967525787044, 1.2717736740410226, -2.7821691176232233], [-0.14201691359430452, -0.8750905219509657, 0.6222625144051509], [-0.17326348062410027, 1.932695747995194, 0.9312355636189067], [0.8904028924592736, 0.18657106002655185, -0.04029765330752769], [0.34017992887452764, 1.295279791418775, 0.534389769872797], [-0.3511325658376627, 1.2750846584688966, 0.19211036905670717], [-0.0776150634716236, -0.7913768386620321, -0.5659922764661505], [-0.636046779726964, -2.79235715975389, 1.0168462003981633], [0.5664775694278109, -0.21427059157909795, 1.045983738409203], [0.43798777953339196, 0.37156747896960074, -2.4747635495786637], [-0.23301591961061885, 0.5321891257672531, 1.6096868317882371], [1.8402948816174964, 1.4258382457202734, -1.1616095185495017], [-2.197671367087202, 0.5704695747069322, 0.027615835350643075], [0.9625532543524465, -0.12588436360404337, 0.2197549635234998], [-1.499989013056637, 0.44800965515897445, -0.44489845287418683], [0.349985357704251, 0.4594059935421338, -0.1172221448808959], [0.31680112211393313, -0.013607030533302129, 0.759199501128509], [0.5017429484459656, -0.5472163690372069, -0.5879018811026014], [1.7437387779906113, -0.10159549531612938, 0.9918077625655023], [0.39338573028374196, -0.5641124904961297, -0.7489737969543596], [0.12012568949433819, 0.2566544207133919, 0.6143637194600546], [-1.2669334275073838, -0.5946832824261059, -0.0948662034142554], [1.6007494601475956, -2.360178570626117, 0.43911164810792375], [-0.540045858613423, 0.43137734284316537, -0.49197890628019864], [0.36455106356938455, 1.5646380406865834, 0.3541965034570923]], "harmonics": [[[0.2478509242505935, 0.4843822466726178, -0.26709855678200556], [0.6931975419216367, 0.012772456245390652, 0.11861320865466492], [0.0870357776397763, 0.49517519596433324, 0.08679054083232246], [0.4692803429014933, 0.39536497129744447, -0.018396617335177917], [-0.8056394215336748, -0.1126791774285151, -0.6436495664761376], [0.4729115879191027, -0.6495064238384085, -0.5597734762705343], [0.36518399015548164, 0.24008520821354534, 0.19413548322051427], [-0.2704965725413116, 0.0994044865337906, 0.26188192827229995], [0.25448402947090454, -0.843311648493573, -0.3505214871852572], [-0.268512150441749, -0.34650133664799193, -0.5421776253355565], [0.19003429718335338, 0.14255935287287588, -0.09959682372534763], [-0.11861714735080006, -0.44446440345175325, -0.205644916480312], [-0.009728175364982638, -0.7663123659826999, -0.16142731648148004], [-0.06760743273894251, 0.4365897935678122, -0.5048098949228386], [0.5526423616137809, 0.061284863818135075, -0.41251578820032175], [-0.030438944582076726, 0.09184632666519872, 0.3997008487820253], [0.16432176613124028, 0.062391358300462926, 0.16848600029157373], [0.021902900604281038, -0.24834822706929802, 0.6099267854404078], [0.6667780964010607, 0.40773021074392807, 0.04041243416488233], [-0.13384003538645864, -0.147605755999933, -0.1467615352648257], [0.278897772971189, 0.3766878797359801, -0.09518204501108685], [0.2620860368838097, -0.18492816610418236, -0.41652461789829376], [-0.5405035163975049, -0.05147075420676744, -0.32188531862883374], [0.6971577568260013, -0.07330007266783488, 0.34523992048917984], [-0.34589331883833263, 0.2694847200303043, 0.17465937785586055], [0.16754847355110059, -0.8718957034957983, 0.252377573939762], [0.12227474182990644, 0.26612917645202866, -0.01590278693118232], [-0.3785120407947573, -0.3036409109482162, -0.2896120120409003], [0.4364137507106362, 0.15947437952364238, -0.3523936059930889], [0.221442278070222, 0.16686475932558598, -0.02566793763228742], [0.09507065723894631, -0.14570477225239323, 0.19944536744927407], [0.2591157407605471, -0.1150587343837511, 0.5282716770081091], [0.3053804578799174, 0.13711322039522728, 0.1811470948347294], [-0.05014446269907775, 0.38404109420143745, -0.4124074006809819], [0.46763402449266517, 0.08530729449343982, -0.03949869390801479], [0.5237481126311175, 0.12020686518331895, 0.29705689954535447], [0.011731681766995426, 0.15520001238646747, 0.19395755754195934], [-0.5558902103373708, 0.005525072284364349, 0.19580711936664338], [-0.04269678221309572, -0.27597989084274227, -0.38115168759486934], [0.35042833066037465, 0.2774470724583405, -0.6964076440763152], [-0.17557272482290262, 0.04637048834746165, 0.017708599759917332], [0.3484154927065625, -0.17802081329113184, -0.15767011476781484], [0.014797086683330792, -0.4966178732310265, -0.02080728288972699], [0.7071122090691698, 0.32590050165898404, -0.3640254705046436], [0.4493535045627606, 0.6148237403949923, -0.3652711527154971], [-0.06000394816350944, 0.3148516379935103, -0.353869389635522], [0.40400491173019665, -0.7432356554139569, -0.3851203683224133], [-0.061793511914813776, -0.8784675541995631, -0.30214896104315164], [-0.4466850209606283, -0.258947472320631, -0.18170098516058392], [0.293672139491613, 0.5877088493980053, -0.5964420131784497], [0.6535786012214234, 0.4540336560817447, -0.32035160461058504], [-0.1626379484210535, -0.34092894781662003, -0.15838440679731378], [0.25057827604731187, 0.4840497824060452, -0.30370957644544255], [0.26656219675798604, -0.32166233081872425, 0.5656123523419119], [-0.047183856486535815, 0.3989100436225067, -0.3221707680103699], [-0.029867332606146758, -0.1336894739250308, -0.24387120499205678], [0.2075962607716641, 0.23546504544732316, 0.06148970587884768], [0.5867753482266197, 0.15931926230505986, 0.14989201971445018], [0.15434714613849768, -0.008303973589855566, 0.7686583046783347], [0.3036851847798838, 0.10211419533548274, 0.41580231789027994], [0.4352736948955056, 0.09943313864517048, -0.16096826465534592], [0.3022950988177118, -1.1308040031104192, 0.07189310799411913], [0.08233242219278661, -0.5896822595472027, -0.05103869397088792], [0.18061824614042907, -0.2974183432839473, 0.5367814297295307], [0.342786134720358, 0.09526287826302553, -0.2816218630448663], [0.37878638529522224, 0.02815449133971159, -0.5000179012892471], [-0.22622766093949945, 0.3606899579136119, -0.19375085711824913], [0.6317182306146534, -0.40348604261455506, -0.45187391062822824], [0.7199227951553336, 0.2496223825032729, -0.2429251380470733], [-0.1375821435508929, -0.46020339023094914, -0.4161199176869647], [0.5023147216676628, 0.6279577735243226, -0.3235229753631509], [-0.31373767400873454, 0.18438994783981238, -0.03638204497435847], [0.5419214886332056, -0.7821045433262213, 0.009315196205011504], [0.6120893421680063, 0.12771943729404606, -0.25579387983727575], [0.5492558228811222, 0.05164996903397658, 0.05900095299312772], [0.271658289856168, 0.3324242771872605, -0.6011995717369335], [0.22545557175770617, 0.1734340457327267, 0.6546455963358064], [-0.1529521783041848, -0.620410031420638, -0.3909024542088193], [0.15001462927762327, -0.1730785885531299, -0.17963297026989725], [-0.561735462584256, -0.635832426715569, 0.0846042510802594]], [[0.08658065632167639, 0.26525884109219977, 0.0786800018401808], [0.24112680203408712, 0.1927424593767426, 0.37287107137503533], [0.29020278610063394, 0.11813264767866058, 0.25585821675553905], [0.059790435143883026, 0.12626396608932833, 0.08977651522104861], [0.06402951721446559, 0.14244718921873392, 0.09550201162082048], [0.18014796193742655, 0.37420055201986374, 0.4154616848631835], [0.44396530853503813, 0.2008972108870991, 0.26991591013231037], [0.25188709492382166, 0.23301419675097249, 0.38604128581286723], [0.2279506162951414, 0.36860996584004124, 0.10542058539809829], [0.29764650441167434, 0.26444598654520546, 0.13185593847885696], [0.1900048205164199, 0.004042713068791915, 0.1158034990470251], [0.17289515742766576, 0.47076222453158023, 0.021162191738858572], [0.2772333221659371, 0.20636168575863498, 0.21097522209657132], [0.11823470421715643, 0.180760260897124, 0.2703916326039952], [0.3234443408132886, 0.10925940382315975, 0.08721155901829938], [0.1634377900059928, 0.12187763474071002, 0.4359684520478932], [0.18062003385169492, 0.11194153698950737, 0.24025956325450004], [0.18072917219621643, 0.1880837935476067, 0.08211853265875049], [0.2784353490952318, 0.205961670435527, 0.18813224936037368], [0.29581707272791824, 0.10313138063387138, 0.09844898618221473], [0.12192933562123952, 0.08519325059761475, 0.0709240954292249], [0.19152458608002157, 0.46639907823177895, 0.40108115969265984], [0.18890996931662307, 0.27036311998969714, 0.1566515079658615], [0.11184399925926901, 0.10903360266906376, 0.27193418789025214], [0.15607184043930042, 0.19204747058894805, 0.10165365081017147], [0.4259054224753164, 0.5072224489172602, 0.025350884390165206], [0.02549513802994757, 0.17389595448599424, 0.0854742743056811], [0.16003476149892468, 0.27946651894608626, 0.07635435919948615], [0.20373352933884484, 0.14669580787535136, 0.5293062476664893], [0.10317008769518039, 0.05420241883319333, 0.08836740828320758], [0.15423081123827362, 0.2362772703010716, 0.26782407524965807], [0.14670197796684356, 0.23753758788662918, 0.15117054765066362], [0.10264971682132558, 0.09109141033400245, 0.15520227688877605], [0.11173684066702753, 0.11281147568245758, 0.1691167747895364], [0.20604589889187538, 0.09485996453572951, 0.06987105977442068], [0.25468133137975046, 0.1597472460940368, 0.07719672399198284], [0.10741579108464365, 0.1958644759548444, 0.18465414245709078], [0.14142430983711698, 0.47077968038825646, 0.30157618920254803], [0.7049455528691909, 0.5511020763999054, 0.06434604954620822], [0.06871234753466045, 0.07443833615825847, 0.29867859488521137], [0.2870170602882419, 0.06425388633156436, 0.12469215686270498], [0.1315428690357096, 0.07140811149395478, 0.1175558528837257], [0.14969376874309037, 0.04895923961522065, 0.6139642478020251], [0.046773862482154406, 0.04335255131440888, 0.1728358652920641], [0.06010130239773551, 0.1294936002594749, 0.07911385124023962], [0.262498336605392, 0.05069283323040936, 0.26016765284176036], [0.3702786586061563, 0.30018662611419134, 0.13128846390114537], [0.2510643520106873, 0.16934696839566554, 0.23023256031312622], [0.21677771226228576, 0.2417385615678781, 0.12308541792858688], [0.20588700342075053, 0.4001317360281009, 0.13185680984981157], [0.12885915638290282, 0.22976085841748456, 0.24636242402947037], [0.3979141339855861, 0.2530332777727196, 0.18100001443225086], [0.16515734349269648, 0.11003304196244289, 0.056784603910249865], [0.11296862827417256, 0.2981457798021039, 0.5297222737475007], [0.06849557521644786, 0.11261728265662845, 0.1213703825159437], [0.09238564962416743, 0.19917252827041754, 0.19814904686911303], [0.22237763314760794, 0.19646009545598112, 0.2498454432118149], [0.3256082994205919, 0.06872016517063945, 0.2315315246837788], [0.05961688739904972, 0.2722502062449065, 0.20105029697945617], [0.2718535484146174, 0.08086500922449957, 0.22939216101968063], [0.0656574989159434, 0.1243979560370947, 0.0658494577167758], [0.20461784966404215, 0.20973921043357135, 0.3227826387006153], [0.21733087401522513, 0.5313309947929228, 0.25467690763508877], [0.09975562100844897, 0.26576895918560944, 0.4024974347937838], [0.16228855446519722, 0.35898613494242443, 0.23177858271827848], [0.15601013106099376, 0.10739248566073299, 0.10306013266106971], [0.08076784027557776, 0.22292608524127216, 0.12314539807946588], [0.3053756401871236, 0.09876648354907261, 0.13935635977912417], [0.04899332735572827, 0.10173778261393719, 0.2964578095457911], [0.3433410010433824, 0.25802438590683147, 0.15600944394091817], [0.04010749038766573, 0.23734582865310902, 0.24485790324109433], [0.21913079570782074, 0.25518730798350914, 0.4381832902368555], [0.36175167199646574, 0.2811180024664861, 0.20977384136695668], [0.02865094791989051, 0.1047272871082722, 0.25501738849193023], [0.1621102200286073, 0.059400239826436926, 0.22929960157936208], [0.22795465519095062, 0.12825280429012154, 0.2695870066688516], [0.04438020960981279, 0.09542516422901814, 0.4042130263362433], [0.21376518473987494, 0.017706978331837504, 0.3051124015404849], [0.07577606972268436, 0.6042465859542587, 0.3735804037528843], [0.2063637048007875, 0.705461221863651, 0.30414471102752905]]], "banksy": {"0.2": [[-0.8842804481270848, 0.3786712370678177, 0.5440291961160418, 0.09305201207156213, 0.47562183865889496, -0.19361839977245673, -0.23273208276834803, 0.10509586895702697, -0.2711534085803706], [0.297491006008758, 0.5242030916226729, 0.2815126154320329, 0.5755413390256117, 0.04214338156014274, 0.23648136567765296, 0.1192084726273007, -0.027017790282427477, 0.3329672162123119], [-0.03317179460143021, -1.3753058559309848, -0.09513161391681413, -0.0811754071418993, 0.4855421395124453, 0.20099652131235063, 0.23096686692015486, -0.16294535596375834, 0.09268161218880028], [-0.823837280922303, 0.1378582845976939, -0.4048319735493924, 0.3329490426842766, 0.3938019274356585, 0.08370434588444409, -0.29374017376293127, -0.14813134836627947, -0.24836674613249504], [0.34802205295809463, 0.7817324184339162, 0.390816871133067, -1.0483013242313004, -0.073165040167531, -0.6135031828204845, -0.28408671465263546, -0.11864801266561503, -0.2366094536091452], [0.0886675159547601, 0.10706644407836709, -0.38458978904445185, 0.33688314007051917, -0.5665878893656544, -0.5199745690809968, -0.0196557271369369, 0.3035708581109974, 0.4204269343861002], [-0.32364509218115756, -0.4398108827839823, 0.47209444405410467, 0.2201708668053399, 0.25107708692865277, 0.32069480039167336, 0.5811229144562818, -0.012161091192709583, 0.12154905034505228], [-0.17043150788817124, 0.560800444384134, -1.2874662954288223, -0.46852659868186614, 0.12177090326771572, 0.3962375572838943, 0.14371237363613001, 0.0463511018572328, 0.36001221858922455], [0.5789885745342327, -0.687934369656872, -0.678237759691437, 0.1002383302030434, -0.7447232704931188, -0.2866417037387716, 0.08920297423337736, 0.2933856726392789, -0.21624168718831074], [-0.3519021156310685, -0.502748564694852, 0.37281042611254833, -0.46637667220837503, -0.2880818439983831, -0.5003537743887186, 0.24791809106437462, 0.10361497338429657, -0.16195675581696256], [-0.6750496712589404, -0.9729731256506629, -0.792547008514054, 0.030413374270047797, 0.1614365447719418, -0.0068404413179225685, 0.0027908260705605675, -0.37079961436902825, -0.19492040000350383], [0.9428661547223929, 0.061828784884551215, -1.1223194351415502, -0.3039801561343525, -0.37812424751228785, -0.12509262833302284, -0.03617219240091855, 0.47949132733492544, -0.38926608762959264], [-0.1753517891682148, -1.4249644096680718, 1.9087210344852157, -0.18600964794703626, -0.6739496545546376, -0.07578643367563707, 0.20143212621652765, -0.002205661067508393, 0.0005144950196308434], [-1.490217399562744, 0.46552917635513125, 0.6316247904151713, -0.24871613953554952, 0.43169357581670875, -0.45868573746037217, -0.16064783152091563, -0.04884750722952129, 0.12252594524970233], [-1.4263375541504097, 0.29970215942096107, 1.0965123112115844, 0.4232636037611323, 0.08673338798415912, -0.3557703555330365, 0.30666627161159804, -0.17911103725318128, -0.2536338772735617], [0.21854279461766674, 0.26322441222236, 1.047234805074113, -0.20844773258437718, 0.11482384757708865, 0.5499167828027556, -0.05770900347842064, -0.15612256733493318, 0.46253752946192095], [-0.04451578391958231, 0.3332889519509195, -0.055474524270016895, 0.0025563718603362233, 0.08775041844180347, 0.2920935556794085, -0.018580700316122717, -0.1742246044390885, 0.06064981627510483], [0.35941774932039716, -0.8539581051925448, 0.885967184695803, -0.15174048332408743, -0.1978647633455963, 0.7843356783371869, -0.01833216477737602, -0.03550516065724799, -0.26409239415268043], [-0.6159795854833837, -0.9926481509718692, 0.44878768660998053, 0.5469184642087256, 0.4051673931781375, 0.14928118725427852, 0.20416944472516088, -0.002934427269537256, -0.046393492307560874], [1.2696596835831162, 0.9142282320160291, -0.4541383938966498, -0.3204726604246783, -0.10526768031238776, -0.059432903328216755, 0.24375201367776908, -0.1902753500372615, -0.23055784872497073], [0.4162496108488612, -0.4013107058643097, -0.05271511691037472, 0.12668822384202894, 0.37663494532991915, -0.0019176065494056085, -0.15223422390656033, -0.22295585536503743, -0.28708014297862583], [-0.10574133135199588, -2.1322824821944146, 0.2708116907010817, 0.10847435871345103, -0.13957244046705072, -0.36024052436720516, 0.006251715593619059, 0.47154234794809313, 0.3908965619495759], [-1.0657245720918946, -0.6272645944366747, -1.4368527457329872, -0.761052607513762, -0.01690553623404602, -0.2547100633710895, 0.00029757373122937596, 0.1143950775906448, -0.11103911595024717], [-1.4834237656348903, -0.8557050991917735, 0.9206472574498281, 0.5798318429791226, -0.03696987645363475, 0.4891884499285176, -0.1752010786554898, -0.1795224121180383, 0.12569357866829733], [1.2465729934910303, -0.0027115551129737224, 1.1934971954794886, -0.5502115692910866, 0.2780995433756246, 0.29897737017604115, -0.07448312857593105, -0.028283952626905796, -0.22397707793422833], [-0.4089773454617084, -1.7557581070377826, 0.22807085829011692, 0.006052192485241052, -0.7709962027169517, 0.38563943470769696, 0.5399959986025001, 0.5459162308716807, -0.38066461775638133], [0.19973405055361224, -0.3775319665638507, 0.38418700162057956, -0.042997449928328095, 0.2750153074616057, 0.08648516816663854, -0.3718392156904968, -0.06135321444576945, -0.25720138708169127], [0.3085942383212327, -0.7815079713133952, -1.4393575381396815, -0.5855507513537237, -0.24868683655779564, -0.2187227203921813, -0.06545855774445498, 0.13098006596422826, -0.27592910992087144], [-0.3723270683158264, -0.17539483185077637, -0.2870762215979447, 0.2973413175636308, 0.17698393119858122, -0.2887292673868018, 0.0340545588900156, -0.11090768497467758, 0.6542064590967731], [0.6643109132833454, 1.6239980618286014, -0.3526599714769406, 0.06444083727928626, 0.18377677243925652, 0.07559623657966608, -0.19495376313200047, -0.27941636939533565, -0.25126034370170125], [0.4169590285280992, 0.89495154556176, 0.805394744498379, -0.07247040412596997, -0.10352039787979267, 0.32661575009039806, -0.07867561643463634, 0.05229591841968382, 0.11725347265036186], [0.7159836826963285, -0.3409498408924565, 0.8327110781139511, 0.10525633454867384, -0.07535220145737594, 0.6932836386236064, -0.09582066881244888, 0.05459202261149508, -0.12229425423611191], [1.5540391463912764, 0.7674144340083483, -0.560988902526357, 0.15537961232583405, 0.15643075152615715, 0.30621169850346247, -0.1961387788663752, -0.2122103183274814, -0.11401510833894238], [0.33875085606478605, 1.1936186088802583, 0.45261847097459595, -0.22979672637100013, 0.3833936261840956, -0.3556494946964659, -0.1754451057989364, -0.17263971035969813, -0.08544172173419401], [-0.6658163688001365, 1.4544247866984155, -1.20661256647853, 0.3311654183577205, 0.1088135194747705, 0.06017382647129548, 0.03932040761773451, -0.20534459400623806, -0.289242549059528], [0.24929430106346814, 0.0056780227838315964, -1.1491084046090725, 0.3919595224201898, 0.14089133542162163, 0.43546049070187703, 0.15007555484439083, -0.08712997819148513, -0.2741993159283104], [0.8634918769657195, 0.3439388878837906, -1.121569020587735, -0.16276000011478017, 0.17305516188694817, 0.32049639889223397, -0.18528522560849953, -0.02132995775987135, -0.053535776126132285], [0.33361773287512453, -0.38030436416088614, -1.875963137195203, -0.777722579415463, 0.035481974436719806, 0.3225588096825336, -0.10783925034489487, 0.47952312921259915, 0.1865633541553745], [-0.7734726032916323, 0.2655799099178683, 0.726004447532527, -0.2217278959309213, -0.22326230856774612, -0.32079685064477664, 1.175440758585331, 0.6258581421427544, -0.3005881437314908], [-0.04051818473431678, 0.0626712080623202, 0.556147838272949, 0.2041845587565919, 0.285418111215904, -0.672332699663835, -0.273422728850105, -0.2425496501432418, 0.18061315147875057], [-0.3635106655198392, 1.1142473085921523, 0.22676400929977436, -0.3656859312550979, 0.07302489295532956, 0.12396457851319292, 0.22371216570076713, -0.2611041464117504, -0.17666756343145182], [0.06958464914142908, 0.5231780475350413, -1.0091983495768484, 0.20200384649547456, -0.13322357176073008, -0.07159685036342806, -0.1303417834732721, -0.24807025196104426, -0.1913219457867962], [-0.7909043640548207, 1.4409510824847531, 0.4180987504835063, -0.15943893491244654, -0.4260609232793154, 0.08101625912510863, -0.08900760658714277, -0.288968632982516, 0.8280514504367281], [-0.42496260128694147, 0.33798869923742253, -0.41925992506221127, 0.5906165144516928, 0.32995390787952217, -0.30169973561325925, -0.3233821929203764, -0.2991831540343488, -0.07780457869786749], [0.056413083049482816, -0.5979714933120146, 0.35732630571267654, 0.3113602701711797, 0.5955166724561518, -0.3030887718696641, -0.2930322506149884, -0.14224745319488133, -0.2702624999234768], [-1.5358726617933645, 1.2573005005234268, -0.4513791253657371, -0.24047851066460116, 0.3197983842419291, -0.2903748853205638, 0.1678768474483645, -0.28581029288447557, 0.10153102840333193], [-1.5389080698924702, -0.18727014551648707, -0.30586762745167023, 0.2622295230948453, -0.6527387783275107, -0.3252222501348093, 0.41331982637750325, 0.16872890440673594, -0.1631220634416404], [-0.051812243194712324, -1.0433759087463774, 0.48180992328406597, -0.24241732725295567, -0.7770366958559314, -0.23270243091312887, 0.14183878050016677, -0.06964076525850672, 0.04005939083724786], [2.9257162398858396, -1.1673373298256813, 0.42056582114560875, -0.6594094807378079, -0.2076070218211825, -0.0983932113916969, 0.06375945357759354, 0.06224554850825302, -0.17996699781024814], [-0.449068833688179, 0.19966472184318113, -1.7827086876666698, 0.14269479911566738, 0.5705941170886578, -0.5608629487902296, 0.03895856255133216, 0.35081347456120016, -0.1619549664588887], [-1.1698602459121947, 0.44778919995009026, 0.0350268248667193, 0.5326181073795633, 0.4477270398411351, -0.2529998483903006, -0.13645327410409477, 0.04042402135744191, 0.07318202559820607], [1.2201503964914975, -0.6341389985012651, 0.253268476924012, -0.3516723712261338, -0.282960002675307, -0.07239334365681405, 0.4762527743900545, 0.08282277881943814, -0.06103951887715825], [2.316303751331696, -0.6905965035089612, -0.85202877876122, 0.09600682991580042, 0.4753162553138508, -0.23444264310946475, -0.05379314646138975, -0.17770158792476684, -0.31611555341511427], [-0.21267200460439764, -0.02069719811447844, 0.939681593662583, 0.11332383837566173, -0.2652511603669343, 0.7349215069542113, -0.17264001472021864, 0.16501079729966622, 0.6550607676126232], [-0.07138915659282986, -0.6823996310581216, 0.2911137547384869, -0.22658920027293405, 0.3970603680214219, -0.25502836248210464, -0.2739163740957658, -0.17299350009153744, -0.1834888187365792], [2.080819668041177, 1.202346252632345, -2.7773330872653874, -0.20782844714107998, -0.09247657926905503, -0.1677180268720495, -0.21951264880880766, -0.015303196826310324, -0.025824023700069844], [-0.3043582786475476, -0.7923629178716094, 0.7122279927081506, 0.04944003722311531, 0.24683048079769687, 0.17278404724674393, 0.07651188591724856, -0.020244830924416243, 0.08033439676953281], [-0.3311612191264292, 1.8164266981333321, 1.0289270614025294, 0.46024334287733887, 0.17684135576027302, 0.27135976583519433, 0.31159415118178624, -0.25296727545024483, 0.04272681092047067], [0.5812393802724055, 0.19405536489442024, 0.03310018980573841, -0.008250149388413132, 0.022771056236157716, 0.9613341401717175, -0.2941353857523519, 0.117833057597072, -0.019866313861659244], [0.10926454447643073, 1.224186417456874, 0.622157947997673, 0.15354295039873553, 0.124261522449901, 0.5678712210839479, 0.18918102442932636, -0.2308412433607813, 0.03833363299206782], [-0.48373524428145404, 1.2054225771683849, 0.27131968638369003, 0.29610617904206976, 0.12179723875371642, -0.0752745538201543, -0.2803793896879726, -0.15153093078264318, -0.29750089881696046], [-0.2491151233299712, -0.7145822869100213, -0.5057396798710443, 0.15203692876595856, -1.0089708430341897, 0.18438468070057643, 0.03606837932508976, 0.003947667786215711, 0.23011074511004467], [-0.7281313313517651, -2.5737468320784718, 1.116678433269161, -0.08627103089651814, -0.5116007220918746, 0.04730579452335401, 0.0650191424145794, 0.5898382818514684, 0.09025579686732205], [0.3033800191292837, -0.17837737671562456, 1.146544569411538, 0.020212007626636268, -0.24296738567901643, 0.7027727000873609, -0.20272936501821234, 0.10602522541925431, 0.3938048793241384], [0.1931629771291142, 0.3659405051212724, -2.462240695359627, 0.1959049899235954, 0.1179641587947218, -0.20981305904126274, -0.06032610267972108, 0.27585253756402356, 0.04323414397581453], [-0.3824161638407231, 0.5151783900545026, 1.7243433293602506, 0.23490772617626762, 0.05628172426436187, -0.45334227759595036, -0.07462365639546516, -0.18251227410620843, -0.22108887097448734], [1.3960456411488884, 1.3454917830073423, -1.1162506171392703, -0.4205655801937371, 0.36193051253588304, -0.11182979167549587, -0.24596933108823546, 0.027972119138655164, -0.1798438287205763], [-2.067674674640062, 0.5507457830426296, 0.10271188786341931, 0.5089345425280223, -0.3404591332786477, -0.3996578402864116, 0.2655192827667022, -0.19822751908423802, -0.14655465945390853], [0.6431291185437626, -0.09625535902245118, 0.2996555472115063, 0.604495526469172, 0.2598431466672513, -0.16666308583161527, -0.3183279115813886, -0.19281427061723191, 0.17605277434391015], [-1.4692108949097782, 0.4369649835875348, -0.38161784706457014, -0.3245268671436811, -0.39259068108476103, -0.3597892509512305, 0.3519759855460259, 0.09191580778280643, -0.11235759281808327], [0.117675526874669, 0.4475536275853683, -0.04574783562258978, 0.36873854808253576, 0.6075887721706816, -0.2565361828738746, -0.33856320365728787, 0.05424266687374319, 0.07009249592579149], [0.08921047692161863, 0.008064525921389143, 0.852589154548836, -0.5153740858209275, 0.19988498696684248, 0.06364914170789022, 0.0691180181079245, 0.08674708952727754, 0.46708569413818435], [0.24785141685291706, -0.4877262385654485, -0.5281971446935688, 0.41164859068253634, -0.6884649780446317, 0.11460525576552881, 0.39390172708145105, 0.13398881413798294, -0.001952537301017839], [1.3132209424894707, -0.07368791930944311, 1.0910138972737256, 0.4876685694641504, 0.14779648928717443, -0.18101277210405242, -0.3646526405723028, -0.18736785466656947, 0.09095497345446397], [0.15490385989122515, -0.5034248786950767, -0.6932967411563664, 0.4195946216043367, 0.07787750880157819, 0.17000888680744647, -0.060732215173632226, -0.2699467414954829, 0.03814356241309303], [-0.07949541352498843, 0.259171697135073, 0.7041316846020373, 0.11884495480828547, 0.335950212892389, -0.5661680107652058, 0.08921217181787698, -0.14450799201387618, 0.12087364790623813], [-1.269298533920138, -0.5318290223414871, -0.022832873103082497, 0.06878884688194026, 0.18981490861413852, 0.834200763618016, -0.32883314426848653, -0.20431488736733852, 0.39732784226165496], [1.1905663746578226, -2.1721981003803785, 0.5244973510405272, -0.34117879045267085, -0.5398440440333314, -0.33166974281302763, 0.056899168550784224, -0.3459054312615067, 0.19382495733854294], [-0.6457828617720379, 0.42151145561638126, -0.4298755698184977, -0.012944005951537274, -0.1286809435168939, -0.09608720779228709, -0.2573368517254834, 0.7226792391089754, 0.3344238284744357], [0.13016981935050465, 1.4744543994598645, 0.4374588624170039, -0.7840553362178497, -0.5540194836720159, 0.19855863169157711, 0.04004413183340459, 0.9070766897574077, 0.1918378072927677]]}}, {"name": "decay_reciprocal", "n_cells": 80, "n_genes": 3, "k": 7, "max_m": 1, "decay": "reciprocal", "k_per_harmonic": [7, 14], "locations": [[6.4285101384599805, 24.963893122005747], [30.074917881167874, 1.4344504185972273], [7.396304228872797, 46.41055114801848], [3.5210288077098415, 6.488697469964899], [47.41642266458875, 31.094179639819142], [18.44965618648955, 25.569501090163133], [33.14214762583996, 13.765440788056466], [6.898403643347767, 39.401979725199595], [33.518029205124186, 25.61911567415802], [40.8368217984829, 27.453763443501316], [49.045681964865274, 10.225473066502245], [27.68651814326139, 24.181234846169385], [17.663742753022404, 29.579765197452172], [11.765061583379028, 40.11013418892417], [43.36667759212073, 6.437983561392552], [23.353660336913556, 13.857244626685217], [4.15584988676212, 44.797215412518376], [21.497434602391767, 7.384564998104704], [33.66811786379554, 10.110801389401908], [45.07155393440885, 10.857412870926408], [1.6537343688714345, 10.038447708060966], [17.287393687781975, 23.44540817112423], [45.30671694477803, 34.86805443681489], [16.966033037122262, 0.8438607548748922], [7.991184705249049, 49.821793776983526], [22.98579899465923, 34.551995815937964], [2.7334030700919, 1.7025139473518802], [42.294505322252874, 29.394097033343026], [15.435487160228101, 15.868831914066872], [4.461862720887439, 8.633480055428771], [1.229305373259315, 41.956242418639086], [23.315159860158257, 6.36014580292652], [36.9623437016846, 9.782641497266049], [3.0960117574226285, 29.919605366201907], [44.78788758706408, 1.34717056923514], [40.25679949458346, 9.508500836417038], [4.645071081827357, 0.8981017826278082], [14.648753350604299, 36.35558719909591], [24.658947550405845, 42.64599972272639], [10.860565176074516, 15.759137357171582], [12.907042592729418, 48.91505686571085], [47.050299732571744, 17.034308792825453], [21.800075179616552, 15.715981435192644], [37.32544586527053, 2.000655127659512], [3.371946654601304, 20.20187937342031], [12.2547025557032, 42.261249085061344], [37.09035482376451, 27.289699126147838], [33.07377571567503, 34.61395533424619], [39.052741169917105, 46.37512985578414], [7.4867586893866465, 31.306507887269074], [7.181072155667756, 22.156547064234843], [39.3142394311866, 44.73488968430727], [37.96140770622649, 1.7704102040796865], [17.970603821688837, 8.152841621076446], [49.94012438162009, 7.200767881501868], [12.215722142324148, 17.860985638976352], [3.044335145459398, 43.51924585216669], [31.818071093156213, 7.987411997920995], [24.91342788562751, 3.933487931747881], [30.548989367994782, 11.583161404872882], [1.931946643237925, 5.761875184695126], [27.763131131011054, 31.84903054790911], [16.240032356709854, 32.17262147805434], [17.603304995430634, 6.53295033951164], [15.76051409616836, 19.763411312690977], [45.63194173515474, 5.783018685987818], [4.308194528362675, 28.07510135358564], [48.1696394234913, 45.36275631283964], [35.012202889228746, 3.337537332282764], [40.32007121404446, 34.16873686910788], [7.1965119625464204, 23.247186301368565], [2.466132768976703, 40.093798264232476], [35.931710859414146, 40.23140499590264], [38.02078203100886, 13.362878848134867], [39.487025724675554, 12.45853229602032], [6.89477389681965, 19.51950168045739], [24.892017644551405, 14.291107381848533], [30.28914522769588, 30.12518646046972], [11.990882910715822, 31.12837439163244], [17.86264587770882, 36.73447993268751]], "features": [[-0.818083666605393, 0.38526930227745887, 0.4581670048370468], [0.5596122240618859, 0.5419022252820672, 0.20205463691158088], [0.17412924424976314, -1.5024999410944402, -0.1654011831842485], [-0.7476197010175331, 0.12608730560642875, -0.46754626006357575], [0.6185207511629426, 0.8190757096799433, 0.30869236500853114], [0.31616814431588613, 0.09294668494996648, -0.4477978929622047], [-0.16450126423277087, -0.49564606330714495, 0.3879871341457924], [0.014113411841972533, 0.5812911986088503, -1.3286483115981003], [0.8877789284048715, -0.7626962368507467, -0.7342821862702664], [-0.19744298486173803, -0.5633845877352657, 0.2911251954982905], [-0.5741647764650408, -1.0694775505189256, -0.8458028083790133], [1.3119833252675124, 0.044258328637274344, -1.1675302849446099], [0.008377403177420764, -1.555946414705409, 1.7895665579723081], [-1.5244781602909778, 0.4787527046455685, 0.5436256643142272], [-1.4500077538405294, 0.30027651841828845, 0.9971720401657596], [0.46757528576185525, 0.261016274083352, 0.9490966814610048], [0.16090454888866232, 0.3364252880770561, -0.12671154648393168], [0.6318057260154758, -0.9413841472373661, 0.7917632588742233], [-0.5053015337885142, -1.090653373060846, 0.3652489557719693], [1.6929555515236436, 0.9616782115907366, -0.5156498276026669], [0.698059671998619, -0.454209119721369, -0.12401945613631439], [0.08952849321707658, -2.317218216900625, 0.19161476616248335], [-1.029609188818006, -0.6973986134552436, -1.4743904107207184], [-1.5165582181462036, -0.9432644007214415, 0.8255972952985817], [1.6660413474635754, -0.025205103519519486, 1.091790933563312], [-0.26398064687868195, -1.9119728247927603, 0.14991661602143025], [0.4456482631425715, -0.42861655475758254, 0.30222423421292294], [0.5725562476093207, -0.8634075676336961, -1.4768340975643026], [-0.22125416534201214, -0.21106054027038276, -0.35266321385541605], [0.9872467528013661, 1.7255887894094382, -0.4166470179838092], [0.6988867031627518, 0.9409311129269357, 0.7131564204233815], [1.0474862871297028, -0.38924397003268574, 0.7398063595133139], [2.024481935859489, 0.8036655593800595, -0.6198936689169603], [0.6077124939345443, 1.2623802917054945, 0.3689862863896283], [-0.5634006961428569, 1.5430805830215768, -1.2497670465629258], [0.5034250466559266, -0.016175574467128036, -1.1936657251775022], [1.2194496835829487, 0.3478875937013457, -1.166798177099069], [0.6017283565618432, -0.43160042891134, -1.9027885021671262], [-0.6889051253999523, 0.2635514475016157, 0.6357028862761235], [0.16556490512827252, 0.04516501126799043, 0.46999000714326233], [-0.210976101965214, 1.176954603942294, 0.14864164821343293], [0.29392155247372515, 0.540798991545746, -1.0571688403044779], [-0.7092268763497593, 1.5285791140398155, 0.33530869036097966], [-0.2826160786151785, 0.3414835288114959, -0.48162223506155016], [0.27856628863229466, -0.6658710549900579, 0.27601881733916134], [-1.5777025523190094, 1.330919793665682, -0.5129578726969883], [-1.5812411969951867, -0.2238416945870532, -0.3709961947182103], [0.15239841860045156, -1.145250608848122, 0.3974655997902583], [3.623567688368005, -1.2786677207432902, 0.3377155756992855], [-0.31071885365042484, 0.19260829481441374, -1.811809037837263], [-1.1510093879783454, 0.4596595352026752, -0.038418019395222595], [1.6352381805909817, -0.7047973922713666, 0.17449952715639466], [2.913121452537828, -0.765561436417932, -0.9038334934759573], [-0.035130084895088134, -0.04456267883565894, 0.8441672801225347], [0.12957587279758478, -0.7567393122486353, 0.21142155200757654], [2.6385967525787044, 1.2717736740410226, -2.7821691176232233], [-0.14201691359430452, -0.8750905219509657, 0.6222625144051509], [-0.17326348062410027, 1.932695747995194, 0.9312355636189067], [0.8904028924592736, 0.18657106002655185, -0.04029765330752769], [0.34017992887452764, 1.295279791418775, 0.534389769872797], [-0.3511325658376627, 1.2750846584688966, 0.19211036905670717], [-0.0776150634716236, -0.7913768386620321, -0.5659922764661505], [-0.636046779726964, -2.79235715975389, 1.0168462003981633], [0.5664775694278109, -0.21427059157909795, 1.045983738409203], [0.43798777953339196, 0.37156747896960074, -2.4747635495786637], [-0.23301591961061885, 0.5321891257672531, 1.6096868317882371], [1.8402948816174964, 1.4258382457202734, -1.1616095185495017], [-2.197671367087202, 0.5704695747069322, 0.027615835350643075], [0.9625532543524465, -0.12588436360404337, 0.2197549635234998], [-1.499989013056637, 0.44800965515897445, -0.44489845287418683], [0.349985357704251, 0.4594059935421338, -0.1172221448808959], [0.31680112211393313, -0.013607030533302129, 0.759199501128509], [0.5017429484459656, -0.5472163690372069, -0.5879018811026014], [1.7437387779906113, -0.10159549531612938, 0.9918077625655023], [0.39338573028374196, -0.5641124904961297, -0.7489737969543596], [0.12012568949433819, 0.2566544207133919, 0.6143637194600546], [-1.2669334275073838, -0.5946832824261059, -0.0948662034142554], [1.6007494601475956, -2.360178570626117, 0.43911164810792375], [-0.540045858613423, 0.43137734284316537, -0.49197890628019864], [0.36455106356938455, 1.5646380406865834, 0.3541965034570923]], "harmonics": [[[0.22121805291042707, 0.5217789792823205, -0.24277422630123646], [0.7124781517764961, 0.08097313267181527, 0.11832931439859173], [0.22966683207083702, 0.3900637524087349, 0.18366820443895585], [0.4042982817302816, 0.753940087081025, -0.08708591500194905], [-0.6904142124321934, -0.3076824603235525, -0.8129063759776772], [0.2801259423220084, -1.1669621621481872, -0.14579752423274311], [0.40476667006568123, 0.27138062723683865, 0.2700894201911031], [-0.2916151910040377, 0.12244337491490437, 0.30392635326814244], [0.13854552605266837, -0.8069162076437195, -0.3261236824354636], [-0.24025961679869043, -0.4068511942076899, -0.7386951514329845], [0.2778188795397623, 0.1242936084132593, 0.009316318998004022], [0.07795481803485733, -0.6049029457333744, -0.2232453773502274], [-0.08972758276164351, -0.9997361414971467, -0.0036181564430557544], [-0.37759996605443824, 0.6067824673720863, -0.6388099679969644], [0.4095380051528466, 0.2272095210383527, -0.10351584579266057], [-0.4923478613265004, 0.12177013095227315, 0.25288696294081453], [0.15913172451847285, -0.2594604643584583, 0.308698941729239], [0.32894805357408574, -0.22957899782146662, 0.6646615688752799], [0.6212061787271435, 0.61856207268378, 0.1671174548900023], [-0.1927475865554814, -0.17783957959181215, -0.13394099251071268], [0.21757911796050575, 0.6780838089827734, -0.1700257282033535], [0.313535337482823, -0.09668416677860395, -0.590691620067323], [-0.3910791053864658, 0.05809950371508189, -0.31118498134514333], [0.6560772972796685, -0.14063065167506208, 0.4829435618126801], [-0.2268683934422736, 0.03292457420109836, 0.09395673518752433], [0.13899418591875048, -0.7667406522247393, 0.2550955953956375], [0.37798789643437497, 0.4607266419958698, -0.42388265575995776], [-0.448921399537155, -0.2507822502798259, -0.18850552915895746], [0.6287800935828344, 0.32324866390019585, -0.7626080166881604], [0.04040395645062613, 0.17349129957538362, -0.1314689857469078], [0.10370701188078274, -0.22023035217358325, 0.3071111466136966], [0.4346324855065973, -0.26172468426297074, 0.539422398581108], [0.3394040721537246, -0.03347353659645463, 0.08002276347807397], [0.3952308141227453, 0.6516250760115659, -0.6870635110271679], [0.301439173194889, 0.10731894773246939, 0.18795568818614306], [0.6471576798026988, 0.13405226433423864, 0.13590216334200536], [0.11282521171174409, 0.10510785995528867, 0.14114563346478384], [-0.5190854694310226, 0.07775125774705469, 0.27815385313640206], [-0.02729759332774648, -0.308471349194334, -0.3217944614813507], [0.7640431650141168, 0.4580131865564485, -1.0948325954583542], [-0.04442492393223717, 0.009177010935416263, 0.10978181159890629], [0.4226821222453165, -0.1574594439680099, -0.23852318933519923], [-0.05329721347332538, -0.3154078079362604, 0.13628437604086277], [1.9118197123805403, -0.3017525652983645, -0.592822992771767], [0.1858762205985011, 0.5346351946227776, -0.14264101030087403], [-0.4022439709934482, 0.3199902704055543, -0.18449390603823176], [0.3751244386980822, -0.7513966905933068, -0.3716402382621143], [0.04700409255359604, -0.9211215716143486, -0.2819524907957271], [0.5030930127492095, -0.4557776352498309, -0.0459730345503347], [0.3440455279498657, 0.700116140464722, -0.5179892399755012], [0.36822029994718064, 0.39392702395843654, -0.08095849955711615], [1.436144637965856, -0.7343991205620878, 0.007178681779420128], [-0.012731286418050165, 0.36948709087739645, -0.3643266815177052], [0.4076731908303223, -0.35539347786184716, 0.7439626175565585], [-0.1420378423462995, 0.19557459351493786, -0.19553878663877533], [0.015665729405419795, -0.04935116133745526, -0.26891603997121744], [0.2910193155656804, 0.28630228800796903, 0.13459403641937998], [0.4354351739974817, 0.06849888955179231, 0.20098389346127188], [0.37533019461847544, -0.11133333301099385, 0.7424370550723004], [0.10596735438670607, 0.06452413194463737, 0.4306453031748323], [0.21524977219210753, 0.20434547257589936, -0.29892941594550915], [0.559374117061758, -1.402671770677016, 0.1213482987089745], [0.07737390324368698, -0.5153529203271927, 0.08537128176880691], [0.12806426792387957, -0.30185432711559235, 0.6742236133111169], [0.4646375536428068, -0.04421969747623426, -0.4652138336151598], [-0.04539851297619106, 0.13838524680145456, -0.22943742975289058], [-0.10120148297661888, 0.5517302468110118, -0.10700073872920829], [0.828665765407931, -0.4819938457912094, -0.37420768502228763], [0.7764951360572035, 0.20799795489423786, -0.2980516988128548], [-0.15196484278026642, -0.5067443983676908, -0.5295320515022621], [-0.27016106937017864, 0.48526848618329826, -0.04578140092544886], [0.005022361773024239, 0.243306048842298, 0.10953189905580467], [0.7075834772124037, -0.770050033292971, 0.045623889358605486], [0.5956964502340918, -0.06994499923115441, -0.41830457883413946], [0.9473218938401604, 0.06163607322215921, 0.10204800731023546], [0.0889659141412896, 0.29054266551087465, -0.36508223094177705], [0.20902727670970636, 0.3737375319724146, 0.7108901112099223], [-0.01536886723713718, -0.6848895114477137, -0.4148166705889578], [0.05081733242908152, -0.4517638813395634, -0.20025367133805977], [-0.3885163484456373, -0.797683376817125, -0.12109815600666946]], [[0.2383094077295999, 0.22948555699043408, 0.20443920105234778], [0.19895112257543998, 0.1627497489970995, 0.3141905053314969], [0.43223552693156214, 0.16376121813050495, 0.32044765564542926], [0.2231093280809695, 0.14062244773587804, 0.09168692214503223], [0.120694663305685, 0.0912551031434244, 0.02616310739223424], [0.15931365014663665, 0.15974321124170993, 0.4707132533810129], [0.4212991564611272, 0.2433502372746421, 0.2260518697680642], [0.3331390502379577, 0.23167702210380262, 0.37123058263126196], [0.43779279313467556, 0.35265457107431064, 0.03420252285017776], [0.1875905078990965, 0.1514827308888744, 0.2467539052815447], [0.2730696499595177, 0.1629329065768424, 0.22334406839013413], [0.22512867947819126, 0.4705374291881965, 0.055697027209889886], [0.2622454493424192, 0.21878933143375287, 0.2649375980820329], [0.2598716730791843, 0.3106419534775476, 0.23188270775646302], [0.40352277698581446, 0.1602997686176387, 0.3652112768148857], [0.35267604179159184, 0.31200722423695326, 0.2643030833376535], [0.1529049640496627, 0.14872890950337092, 0.27581316495124525], [0.2786374632038034, 0.16283019218896957, 0.1077091115727906], [0.3669490165947208, 0.3490229595817189, 0.2825058170729327], [0.3624610424564053, 0.1450808903945886, 0.20998567410907215], [0.12254218512376604, 0.16921505701931147, 0.08386434486720411], [0.15408132249830636, 0.4322015367100582, 0.5186575906540091], [0.10042676820381824, 0.2860062505634887, 0.135103642587928], [0.0933539961747884, 0.11618926574938251, 0.25249097681624477], [0.16286227693549724, 0.3004190570086748, 0.08317083854376825], [0.3242209449484111, 0.5117932159364764, 0.06944227871608141], [0.28195665557337934, 0.16026444298675882, 0.2186212771158699], [0.13550384076204608, 0.25676057538469776, 0.16405864612799476], [0.3507048020219198, 0.14603019410588367, 0.6651396434637489], [0.22083232342856976, 0.10590853203662942, 0.06171231174467403], [0.10518420814119128, 0.24261281088124417, 0.13054231796351728], [0.130585573023879, 0.3386203360042133, 0.2113128102892309], [0.1862515775264361, 0.1230003293586701, 0.2663569933224237], [0.2416299562075719, 0.18023248853625584, 0.15419520859464614], [0.2993076166890701, 0.0661712802676791, 0.19180583249513397], [0.3624293751745749, 0.17474210868804466, 0.061369005332090165], [0.07764191547609814, 0.15703665980255857, 0.12218383888023866], [0.23255985525998718, 0.5674912799682279, 0.31635574334997385], [0.6080061859609409, 0.5496966056283906, 0.05509337923422819], [0.1980923800466306, 0.03905595524250987, 0.5006312697887672], [0.41983271388012944, 0.08974725173889199, 0.19037383203985098], [0.15016504113032633, 0.08170139650888253, 0.061374600298517976], [0.2249947704195635, 0.051498039999386166, 0.610291080656805], [0.7335326574338266, 0.3288580435405986, 0.4032199794930204], [0.11767912590501652, 0.11725591835070416, 0.0037837022683575123], [0.3577321534939899, 0.06797024630769652, 0.15547260506713448], [0.40459212064211947, 0.2580826282133635, 0.04841474708522009], [0.21589729918065326, 0.2728675318707977, 0.17905394845609365], [0.22808129863780854, 0.15928609362701873, 0.04266735233644017], [0.32939450035453965, 0.46618685580410524, 0.09910655494740149], [0.12548853215703368, 0.1600337400841048, 0.2191828115007434], [1.4877971672447152, 0.3192171498406235, 0.297244369261632], [0.09962543701430807, 0.09155983701448711, 0.08508905150938481], [0.04024720146346252, 0.29425145879183096, 0.4833384677658712], [0.08500248047846791, 0.2546029024436308, 0.24506512632936658], [0.06506116266521907, 0.12401025596409597, 0.3806660289069389], [0.20567871263003984, 0.21744764879300352, 0.24003906501345582], [0.3086475336186259, 0.12924804566801865, 0.20913346169523786], [0.06242933895762868, 0.3275739295986873, 0.18565676823946647], [0.18652630461063016, 0.19344340938037374, 0.14771274365353365], [0.14859792472844452, 0.1509233703949266, 0.033806565484103185], [0.3397860010648874, 0.13699299820419653, 0.21844844180808123], [0.14849406785746502, 0.5859469415284501, 0.4936375489638218], [0.09621356143447768, 0.2232778664370478, 0.21651027690810537], [0.26399741086981127, 0.49688464451985853, 0.33968463326032294], [0.10717444187832545, 0.20369077853527587, 0.16120158815638533], [0.207173713754368, 0.28252970404159766, 0.20754914171855224], [0.49527002248712776, 0.1394579913959643, 0.17346869045279803], [0.1597247684673633, 0.17702651530399852, 0.3566214499843411], [0.3216857186795147, 0.22966968189817213, 0.20597895381060513], [0.15774993781444477, 0.12022143633626883, 0.21058790125814697], [0.23568727465018527, 0.2260203428522233, 0.509202508040047], [0.6260620577413252, 0.2228225093763342, 0.2095531535952767], [0.08299096122180881, 0.13269419420270098, 0.2986041042578599], [0.3169933223687091, 0.09085178700406012, 0.36680954259054904], [0.33610732144325983, 0.06957408563285787, 0.32069693038484975], [0.09025031265320493, 0.14156684004938833, 0.2470660745069554], [0.21357130705583285, 0.08880036424207552, 0.21298243452389093], [0.07603881989828729, 0.7078170366574488, 0.5060521058944263], [0.16425943754382066, 0.6805544716134152, 0.4057593158359704]]], "banksy": {"0.2": [[-0.8842804481270848, 0.3786712370678177, 0.5440291961160418, 0.007607673607808399, 0.45507632987082774, -0.1620277748910916, -0.024204650524654647, -0.0009922784310943443, -0.0556199691512644], [0.297491006008758, 0.5242030916226729, 0.2815126154320329, 0.4372718654956328, 0.10893565934296447, 0.19082840174823143, -0.0767809072022551, -0.12024731660569186, 0.14166502614992058], [-0.03317179460143021, -1.3753058559309848, -0.09513161391681413, 0.014997115328752865, 0.3516475815923651, 0.25467499511261205, 0.23484905010578716, -0.11843984931423808, 0.15291265439808416], [-0.823837280922303, 0.1378582845976939, -0.4048319735493924, 0.16773266390946626, 0.6373797229447887, -0.009895280798032717, -0.04450948052413689, -0.15978819032780736, -0.258299408457515], [0.34802205295809463, 0.7817324184339162, 0.390816871133067, -0.7897209543255804, -0.19625427540554347, -0.7191384864728871, -0.18131878717165087, -0.24800626606519235, -0.37608266006008717], [0.0886675159547601, 0.10706644407836709, -0.38458978904445185, 0.05912948610238427, -0.8709995276466536, -0.0672659560269999, -0.12973011259332917, -0.12561991619762555, 0.4230246857575734], [-0.32364509218115756, -0.4398108827839823, 0.47209444405410467, 0.16814232407947333, 0.258452228483445, 0.3391224079286871, 0.22023984092091634, 0.0237835207431205, -0.016769813574240938], [-0.17043150788817124, 0.560800444384134, -1.2874662954288223, -0.4409247470555528, 0.14149996756925576, 0.3721865280190787, 0.10247230213311487, 0.0029238089530453128, 0.24419821658418941], [0.5789885745342327, -0.687934369656872, -0.678237759691437, -0.06469908308921263, -0.5882751738947383, -0.2434735850304557, 0.24227265235817758, 0.21910733402834123, -0.36163129612175454], [-0.3519021156310685, -0.502748564694852, 0.37281042611254833, -0.3960083141093235, -0.2741260466309038, -0.6466221968075639, -0.09195683752795981, -0.14038116550948382, 0.02044342052650306], [-0.6750496712589404, -0.9729731256506629, -0.792547008514054, 0.05711169090945842, 0.14295285452317946, 0.08430519046510872, 0.022229369923580326, -0.11992001908999556, -0.02163725989417474], [0.9428661547223929, 0.061828784884551215, -1.1223194351415502, -0.11769271651573154, -0.42964523177658565, -0.14294495182692224, -0.041811956052053005, 0.4297607323644522, -0.32299354853907963], [-0.1753517891682148, -1.4249644096680718, 1.9087210344852157, -0.26435051225028977, -0.7396860993812536, 0.07166612981751053, 0.00777000138795038, -0.02010613687442847, 0.053129772385959194], [-1.490217399562744, 0.46552917635513125, 0.6316247904151713, -0.5161284506984143, 0.5218249099789246, -0.5490183243508011, 0.004599023038101116, 0.1440319514718409, -0.006288509022111118], [-1.4263375541504097, 0.29970215942096107, 1.0965123112115844, 0.17231541250897314, 0.2237670798288468, -0.025949962926110546, 0.19649349408614608, -0.12462536360122381, 0.23337812904627941], [0.21854279461766674, 0.26322441222236, 1.047234805074113, -0.6164888540910388, 0.14097130598628016, 0.3223128433301943, 0.1285705398639682, 0.14647165245737248, 0.05198919151372624], [-0.04451578391958231, 0.3332889519509195, -0.055474524270016895, -0.04669405408671739, -0.15838818504876503, 0.37685011374241933, -0.13829107310979769, -0.14530216795673132, 0.07267930004563103], [0.35941774932039716, -0.8539581051925448, 0.885967184695803, 0.10183011052883545, -0.13492390719718422, 0.7246827918652031, 0.029667061304643128, -0.1201035668526611, -0.22949849728173297], [-0.6159795854833837, -0.9926481509718692, 0.44878768660998053, 0.3574438912050751, 0.5310747883834323, 0.2385022536461601, 0.14763690883464264, 0.2126177450024979, 0.08470977067239717], [1.2696596835831162, 0.9142282320160291, -0.4541383938966498, -0.35445350815924015, -0.09429577792793112, -0.05568021958273662, 0.14164170657076636, -0.1518210769376932, -0.04564982876777647], [0.4162496108488612, -0.4013107058643097, -0.05271511691037472, 0.004425001031307203, 0.5778139454793245, -0.09094080397598128, -0.1788507990226645, -0.10869399046515235, -0.2723609918859379], [-0.10574133135199588, -2.1322824821944146, 0.2708116907010817, 0.08834989461177944, -0.030568880419353565, -0.5019989673991954, -0.1367196498758203, 0.3612555556324305, 0.5092077012191807], [-1.0657245720918946, -0.6272645944366747, -1.4368527457329872, -0.5279175284635473, 0.09097425223965734, -0.22887607391086842, -0.20839339296345835, 0.10000863355880134, -0.1802550740887539], [-1.4834237656348903, -0.8557050991917735, 0.9206472574498281, 0.3879427471220909, -0.0650776462770887, 0.5471151029016456, -0.21784146409165694, -0.2034496089595775, 0.03075617387553908], [1.2465729934910303, -0.0027115551129737224, 1.1934971954794886, -0.38429612910772254, 0.07120575994431427, 0.16701247599300553, -0.12498972534898237, 0.1257639189821144, -0.2736076138979405], [-0.4089773454617084, -1.7557581070377826, 0.22807085829011692, -0.0643066777641361, -0.5567275122689096, 0.32447103209261957, 0.09055916641227386, 0.5034836791830563, -0.29828557903818526], [0.19973405055361224, -0.3775319665638507, 0.38418700162057956, 0.14472116661400816, 0.4071352757125825, -0.33899980859673434, 0.034100961544494234, -0.12468848952395994, -0.03012677954472808], [0.3085942383212327, -0.7815079713133952, -1.4393575381396815, -0.5785073537527557, -0.15157365919058968, -0.10899853860138213, -0.1615361388148924, 0.047747423051888185, -0.128206601636722], [-0.3723270683158264, -0.17539483185077637, -0.2870762215979447, 0.36406816216339044, 0.29918135475903646, -0.6699889081670815, 0.12593728468789966, -0.15012469753158658, 0.772518568366367], [0.6643109132833454, 1.6239980618286014, -0.3526599714769406, -0.15053531992382738, 0.1815851048397854, -0.05326467180491016, -0.04755118776803102, -0.2218209950001825, -0.3121806895122586], [0.4169590285280992, 0.89495154556176, 0.805394744498379, -0.09516942267670818, -0.12758292817440592, 0.3752985828084632, -0.20203822829365933, 0.02246576022833944, -0.18845434709971723], [0.7159836826963285, -0.3409498408924565, 0.8327110781139511, 0.1942634592706107, -0.16016615283661736, 0.6023040007023182, -0.16810614322433765, 0.1940285451538154, -0.04326421652575052], [1.5540391463912764, 0.7674144340083483, -0.560988902526357, 0.11097511698011127, 0.01906696285264109, 0.15339674690525282, -0.09374543036605477, -0.19127842717338664, 0.055681226194825], [0.33875085606478605, 1.1936186088802583, 0.45261847097459595, 0.15980210705973674, 0.5570373526950101, -0.5961697886370297, -0.019768938744924854, -0.08900614587847344, -0.1459367620225235], [-0.6658163688001365, 1.4544247866984155, -1.20661256647853, 0.07777038964951212, 0.12962358388121528, 0.2588645555902074, 0.057279018760363606, -0.292830361922556, -0.07832925787287072], [0.24929430106346814, 0.0056780227838315964, -1.1491084046090725, 0.38014150243717393, 0.15061579214052725, 0.2079998985405813, 0.14159940424150388, -0.09881730240866576, -0.31279780476604374], [0.8634918769657195, 0.3439388878837906, -1.121569020587735, -0.08719449458691476, 0.12788733784075484, 0.21312361130246787, -0.23883024407833273, -0.1304564485616264, -0.20347924832982459], [0.33361773287512453, -0.38030436416088614, -1.875963137195203, -0.6398740075072434, 0.1064056975573193, 0.34700265460344293, -0.03188511590163107, 0.6030145749957079, 0.14555718009840288], [-0.7734726032916323, 0.2655799099178683, 0.726004447532527, -0.2097482129355357, -0.19687374659632728, -0.23924324059590768, 0.46965001385008415, 0.5712159854302113, -0.32407864441857], [-0.04051818473431678, 0.0626712080623202, 0.556147838272949, 0.4823714772767792, 0.4050045478820176, -0.9946256991087327, -0.0779280473136144, -0.3412846957835643, 0.4768042354876801], [-0.3635106655198392, 1.1142473085921523, 0.22676400929977436, -0.22472805900966258, 0.052558100129018716, 0.1824761182124185, 0.21828091254689008, -0.2507007547095359, -0.08090337036244295], [0.06958464914142908, 0.5231780475350413, -1.0091983495768484, 0.18381147429304792, -0.07829237446920853, -0.1578738287744701, -0.14195116373924532, -0.2650784748788623, -0.3127877474557214], [-0.7909043640548207, 1.4409510824847531, 0.4180987504835063, -0.23248790990059715, -0.20232056745517302, 0.20837338175628295, -0.04199083673779153, -0.31905103536544127, 0.6739247655253338], [-0.42496260128694147, 0.33798869923742253, -0.41925992506221127, 1.486235792392752, -0.19159785386313125, -0.504081660972418, 0.6373329288485894, 0.17658359924806963, 0.30170120528223576], [0.056413083049482816, -0.5979714933120146, 0.35732630571267654, -0.02330287633343272, 0.4651716111213246, -0.06418153476835062, -0.18534705384479108, -0.20154353034129882, -0.4163110734143158], [-1.5358726617933645, 1.2573005005234268, -0.4513791253657371, -0.5376825042261486, 0.29662271694206704, -0.10507853827750312, 0.13532468135195938, -0.2896156594977572, -0.14364056008918127], [-1.5389080698924702, -0.18727014551648707, -0.30586762745167023, 0.1422167392096474, -0.5446787402108775, -0.28795057307564637, 0.19792196299250833, 0.05010989479370198, -0.3360839132469398], [-0.051812243194712324, -1.0433759087463774, 0.48180992328406597, -0.14476273193718256, -0.6779543865609028, -0.20031123395133307, -0.05414357614451537, 0.07653010761634689, -0.10125158575996879], [2.9257162398858396, -1.1673373298256813, 0.42056582114560875, 0.2541401665012761, -0.3125452990956578, 0.03027860888100888, -0.03786773789825899, -0.12643677269834738, -0.3464152232341371], [-0.449068833688179, 0.19966472184318113, -1.7827086876666698, 0.11503461083771382, 0.5951147277876692, -0.4309570611856423, 0.09747019355441178, 0.4219863783766648, -0.2449621435186962], [-1.1698602459121947, 0.44778919995009026, 0.0350268248667193, 0.1361782654888328, 0.35468119699226813, -0.003907811435770927, -0.1749149594078129, -0.12510074921317724, -0.029117385540630873], [1.2201503964914975, -0.6341389985012651, 0.253268476924012, 1.070202520158107, -0.5313314801116956, 0.08221637545507139, 1.6449074284817453, 0.15935558956633172, 0.11120326173741608], [2.316303751331696, -0.6905965035089612, -0.85202877876122, -0.19700828046067986, 0.33548985711014934, -0.28080405309008877, -0.20946384087902262, -0.24746171508844675, -0.27015950329557537], [-0.21267200460439764, -0.02069719811447844, 0.939681593662583, 0.1706844151192855, -0.23371912241077006, 0.802172657478083, -0.28878348961769007, 0.1147425920077148, 0.4457193168323717], [-0.07138915659282986, -0.6823996310581216, 0.2911137547384869, -0.3101019287886215, 0.19892590517280676, -0.1158711611706286, -0.22899772842525037, 0.04389172134253098, 0.017407732250782983], [2.080819668041177, 1.202346252632345, -2.7773330872653874, -0.17217178166100156, 0.006599134405039067, -0.18757252697003868, -0.2556360801657394, -0.18947371633665516, 0.2611590352859601], [-0.3043582786475476, -0.7923629178716094, 0.7122279927081506, 0.0686570101624053, 0.2701693908224286, 0.20672164836451823, -0.06779394295452722, -0.022503686546064116, 0.008373065286179955], [-0.3311612191264292, 1.8164266981333321, 1.0289270614025294, 0.19496550387502612, 0.09914031994106318, 0.27159520534497006, 0.06975562611031293, -0.18011393138950654, -0.04718173513702816], [0.5812393802724055, 0.19405536489442024, 0.03310018980573841, 0.1423966967341155, -0.04207206773264255, 0.8006819378236135, -0.25915176785991834, 0.17428892324476927, -0.08938259451204648], [0.10926454447643073, 1.224186417456874, 0.622157947997673, -0.09319248980868379, 0.09601916065085529, 0.49601130161495205, -0.0933784397403631, -0.06539859669372061, -0.15758940773682542], [-0.48373524428145404, 1.2054225771683849, 0.27131968638369003, 0.002387716770858852, 0.20581319576258553, -0.2169004174520943, -0.14404457593610032, -0.14138072720004982, -0.3623430548349522], [-0.2491151233299712, -0.7145822869100213, -0.5057396798710443, 0.3033645493868851, -1.0560893638486686, 0.19377843447023474, 0.11135154551049323, -0.16627391598945943, -0.03043746207473464], [-0.7281313313517651, -2.5737468320784718, 1.116678433269161, -0.11820079418147322, -0.3593265051121644, 0.15862310860499124, -0.14418331179527108, 0.6359943303936131, 0.46423257459353917], [0.3033800191292837, -0.17837737671562456, 1.146544569411538, -0.07386616446681396, -0.19167776184057808, 0.7340264455827651, -0.214021550787739, -0.012085249299059372, -0.033921437556357265], [0.1931629771291142, 0.3659405051212724, -2.462240695359627, 0.22050638716774956, 0.010628591716847336, -0.37938700991224167, 0.0101103365573476, 0.47684247550428976, 0.18749235313870605], [-0.3824161638407231, 0.5151783900545026, 1.7243433293602506, -0.2255795760589138, 0.1540182457788358, -0.1489955818820019, -0.19937960027157625, -0.047086832192733345, -0.13334234623863164], [1.3960456411488884, 1.3454917830073423, -1.1162506171392703, -0.2743857747823949, 0.47859541861535876, -0.029355263231957685, -0.06579686501939593, 0.09379614133535676, -0.05002965171723575], [-2.067674674640062, 0.5507457830426296, 0.10271188786341931, 0.53889147033135, -0.33313145230861785, -0.2904593810639703, 0.3190528665294862, -0.16186904151466847, -0.11129144456778271], [0.6431291185437626, -0.09625535902245118, 0.2996555472115063, 0.4932621767005421, 0.20868128993257498, -0.21604274679342667, -0.12918092549661683, -0.09473513113684885, 0.21793736543046208], [-1.4692108949097782, 0.4369649835875348, -0.38161784706457014, -0.31878424723698645, -0.3525667046552781, -0.4422362425946855, 0.08717251715844566, -0.0006632523270964787, -0.052852164999204775], [0.117675526874669, 0.4475536275853683, -0.04574783562258978, -0.4221606181231351, 0.4264066408007433, 0.030465865721697013, -0.13181897750767263, -0.19624423194048687, -0.044567286915032], [0.08921047692161863, 0.008064525921389143, 0.852589154548836, -0.18148064668646133, 0.23640680085357982, 0.18223191350514217, -0.027707393118396942, -0.007184519999170579, 0.4922115849422991], [0.24785141685291706, -0.4877262385654485, -0.5281971446935688, 0.4329909023236004, -0.5593261878327619, 0.11978352013109957, 0.4937697168692841, -0.012898959738646751, -0.046427312079635484], [1.3132209424894707, -0.07368791930944311, 1.0910138972737256, 0.335132661566144, -0.009572077733092446, -0.3335491312280502, -0.23168479043356216, -0.17395575952621056, 0.11364747243817801], [0.15490385989122515, -0.5034248786950767, -0.6932967411563664, 0.6426700789605659, 0.0937513264322095, 0.1749189488562597, 0.08090424017677274, -0.24872698082152112, 0.23625111409290628], [-0.07949541352498843, 0.259171697135073, 0.7041316846020373, -0.1080622300966438, 0.2734991268579942, -0.28154234626916796, 0.10643742886989803, -0.2867496431011753, 0.15336074169980948], [-1.269298533920138, -0.5318290223414871, -0.022832873103082497, -0.003054580495177462, 0.33882749553300984, 0.7698555051213453, -0.22198747962149168, -0.1581005874533398, 0.02100456469306057], [1.1905663746578226, -2.1721981003803785, 0.5244973510405272, -0.1993151521846153, -0.4924542977235856, -0.3301408844812075, -0.057250722670479016, -0.2523928164073755, -0.04026296008098109], [-0.6457828617720379, 0.42151145561638126, -0.4298755698184977, -0.14142760939546442, -0.3093935181460249, -0.12047836104759602, -0.24097171859246821, 0.8537728107021479, 0.4865485354088304], [0.13016981935050465, 1.4744543994598645, 0.4374588624170039, -0.5256760989386834, -0.5810251379032428, -0.04313070489994476, -0.12312334640296568, 0.8050553630106718, 0.30626582491730464]]}}, {"name": "decay_reciprocal_squared", "n_cells": 80, "n_genes": 3, "k": 7, "max_m": 1, "decay": "reciprocal_squared", "k_per_harmonic": [7, 14], "locations": [[6.4285101384599805, 24.963893122005747], [30.074917881167874, 1.4344504185972273], [7.396304228872797, 46.41055114801848], [3.5210288077098415, 6.488697469964899], [47.41642266458875, 31.094179639819142], [18.44965618648955, 25.569501090163133], [33.14214762583996, 13.765440788056466], [6.898403643347767, 39.401979725199595], [33.518029205124186, 25.61911567415802], [40.8368217984829, 27.453763443501316], [49.045681964865274, 10.225473066502245], [27.68651814326139, 24.181234846169385], [17.663742753022404, 29.579765197452172], [11.765061583379028, 40.11013418892417], [43.36667759212073, 6.437983561392552], [23.353660336913556, 13.857244626685217], [4.15584988676212, 44.797215412518376], [21.497434602391767, 7.384564998104704], [33.66811786379554, 10.110801389401908], [45.07155393440885, 10.857412870926408], [1.6537343688714345, 10.038447708060966], [17.287393687781975, 23.44540817112423], [45.30671694477803, 34.86805443681489], [16.966033037122262, 0.8438607548748922], [7.991184705249049, 49.821793776983526], [22.98579899465923, 34.551995815937964], [2.7334030700919, 1.7025139473518802], [42.294505322252874, 29.394097033343026], [15.435487160228101, 15.868831914066872], [4.461862720887439, 8.633480055428771], [1.229305373259315, 41.956242418639086], [23.315159860158257, 6.36014580292652], [36.9623437016846, 9.782641497266049], [3.0960117574226285, 29.919605366201907], [44.78788758706408, 1.34717056923514], [40.25679949458346, 9.508500836417038], [4.645071081827357, 0.8981017826278082], [14.648753350604299, 36.35558719909591], [24.658947550405845, 42.64599972272639], [10.860565176074516, 15.759137357171582], [12.907042592729418, 48.91505686571085], [47.050299732571744, 17.034308792825453], [21.800075179616552, 15.715981435192644], [37.32544586527053, 2.000655127659512], [3.371946654601304, 20.20187937342031], [12.2547025557032, 42.261249085061344], [37.09035482376451, 27.289699126147838], [33.07377571567503, 34.61395533424619], [39.052741169917105, 46.37512985578414], [7.4867586893866465, 31.306507887269074], [7.181072155667756, 22.156547064234843], [39.3142394311866, 44.73488968430727], [37.96140770622649, 1.7704102040796865], [17.970603821688837, 8.152841621076446], [49.94012438162009, 7.200767881501868], [12.215722142324148, 17.860985638976352], [3.044335145459398, 43.51924585216669], [31.818071093156213, 7.987411997920995], [24.91342788562751, 3.933487931747881], [30.548989367994782, 11.583161404872882], [1.931946643237925, 5.761875184695126], [27.763131131011054, 31.84903054790911], [16.240032356709854, 32.17262147805434], [17.603304995430634, 6.53295033951164], [15.76051409616836, 19.763411312690977], [45.63194173515474, 5.783018685987818], [4.308194528362675, 28.07510135358564], [48.1696394234913, 45.36275631283964], [35.012202889228746, 3.337537332282764], [40.32007121404446, 34.16873686910788], [7.1965119625464204, 23.247186301368565], [2.466132768976703, 40.093798264232476], [35.931710859414146, 40.23140499590264], [38.02078203100886, 13.362878848134867], [39.487025724675554, 12.45853229602032], [6.89477389681965, 19.51950168045739], [24.892017644551405, 14.291107381848533], [30.28914522769588, 30.12518646046972], [11.990882910715822, 31.12837439163244], [17.86264587770882, 36.73447993268751]], "features": [[-0.818083666605393, 0.38526930227745887, 0.4581670048370468], [0.5596122240618859, 0.5419022252820672, 0.20205463691158088], [0.17412924424976314, -1.5024999410944402, -0.1654011831842485], [-0.7476197010175331, 0.12608730560642875, -0.46754626006357575], [0.6185207511629426, 0.8190757096799433, 0.30869236500853114], [0.31616814431588613, 0.09294668494996648, -0.4477978929622047], [-0.16450126423277087, -0.49564606330714495, 0.3879871341457924], [0.014113411841972533, 0.5812911986088503, -1.3286483115981003], [0.8877789284048715, -0.7626962368507467, -0.7342821862702664], [-0.19744298486173803, -0.5633845877352657, 0.2911251954982905], [-0.5741647764650408, -1.0694775505189256, -0.8458028083790133], [1.3119833252675124, 0.044258328637274344, -1.1675302849446099], [0.008377403177420764, -1.555946414705409, 1.7895665579723081], [-1.5244781602909778, 0.4787527046455685, 0.5436256643142272], [-1.4500077538405294, 0.30027651841828845, 0.9971720401657596], [0.46757528576185525, 0.261016274083352, 0.9490966814610048], [0.16090454888866232, 0.3364252880770561, -0.12671154648393168], [0.6318057260154758, -0.9413841472373661, 0.7917632588742233], [-0.5053015337885142, -1.090653373060846, 0.3652489557719693], [1.6929555515236436, 0.9616782115907366, -0.5156498276026669], [0.698059671998619, -0.454209119721369, -0.12401945613631439], [0.08952849321707658, -2.317218216900625, 0.19161476616248335], [-1.029609188818006, -0.6973986134552436, -1.4743904107207184], [-1.5165582181462036, -0.9432644007214415, 0.8255972952985817], [1.6660413474635754, -0.025205103519519486, 1.091790933563312], [-0.26398064687868195, -1.9119728247927603, 0.14991661602143025], [0.4456482631425715, -0.42861655475758254, 0.30222423421292294], [0.5725562476093207, -0.8634075676336961, -1.4768340975643026], [-0.22125416534201214, -0.21106054027038276, -0.35266321385541605], [0.9872467528013661, 1.7255887894094382, -0.4166470179838092], [0.6988867031627518, 0.9409311129269357, 0.7131564204233815], [1.0474862871297028, -0.38924397003268574, 0.7398063595133139], [2.024481935859489, 0.8036655593800595, -0.6198936689169603], [0.6077124939345443, 1.2623802917054945, 0.3689862863896283], [-0.5634006961428569, 1.5430805830215768, -1.2497670465629258], [0.5034250466559266, -0.016175574467128036, -1.1936657251775022], [1.2194496835829487, 0.3478875937013457, -1.166798177099069], [0.6017283565618432, -0.43160042891134, -1.9027885021671262], [-0.6889051253999523, 0.2635514475016157, 0.6357028862761235], [0.16556490512827252, 0.04516501126799043, 0.46999000714326233], [-0.210976101965214, 1.176954603942294, 0.14864164821343293], [0.29392155247372515, 0.540798991545746, -1.0571688403044779], [-0.7092268763497593, 1.5285791140398155, 0.33530869036097966], [-0.2826160786151785, 0.3414835288114959, -0.48162223506155016], [0.27856628863229466, -0.6658710549900579, 0.27601881733916134], [-1.5777025523190094, 1.330919793665682, -0.5129578726969883], [-1.5812411969951867, -0.2238416945870532, -0.3709961947182103], [0.15239841860045156, -1.145250608848122, 0.3974655997902583], [3.623567688368005, -1.2786677207432902, 0.3377155756992855], [-0.31071885365042484, 0.19260829481441374, -1.811809037837263], [-1.1510093879783454, 0.4596595352026752, -0.038418019395222595], [1.6352381805909817, -0.7047973922713666, 0.17449952715639466], [2.913121452537828, -0.765561436417932, -0.9038334934759573], [-0.035130084895088134, -0.04456267883565894, 0.8441672801225347], [0.12957587279758478, -0.7567393122486353, 0.21142155200757654], [2.6385967525787044, 1.2717736740410226, -2.7821691176232233], [-0.14201691359430452, -0.8750905219509657, 0.6222625144051509], [-0.17326348062410027, 1.932695747995194, 0.9312355636189067], [0.8904028924592736, 0.18657106002655185, -0.04029765330752769], [0.34017992887452764, 1.295279791418775, 0.534389769872797], [-0.3511325658376627, 1.2750846584688966, 0.19211036905670717], [-0.0776150634716236, -0.7913768386620321, -0.5659922764661505], [-0.636046779726964, -2.79235715975389, 1.0168462003981633], [0.5664775694278109, -0.21427059157909795, 1.045983738409203], [0.43798777953339196, 0.37156747896960074, -2.4747635495786637], [-0.23301591961061885, 0.5321891257672531, 1.6096868317882371], [1.8402948816174964, 1.4258382457202734, -1.1616095185495017], [-2.197671367087202, 0.5704695747069322, 0.027615835350643075], [0.9625532543524465, -0.12588436360404337, 0.2197549635234998], [-1.499989013056637, 0.44800965515897445, -0.44489845287418683], [0.349985357704251, 0.4594059935421338, -0.1172221448808959], [0.31680112211393313, -0.013607030533302129, 0.759199501128509], [0.5017429484459656, -0.5472163690372069, -0.5879018811026014], [1.7437387779906113, -0.10159549531612938, 0.9918077625655023], [0.39338573028374196, -0.5641124904961297, -0.7489737969543596], [0.12012568949433819, 0.2566544207133919, 0.6143637194600546], [-1.2669334275073838, -0.5946832824261059, -0.0948662034142554], [1.6007494601475956, -2.360178570626117, 0.43911164810792375], [-0.540045858613423, 0.43137734284316537, -0.49197890628019864], [0.36455106356938455, 1.5646380406865834, 0.3541965034570923]], "harmonics": [[[0.19498810186168758, 0.5313310243688453, -0.2105193940688805], [0.7297373114339393, 0.1310063279303872, 0.12112058616712225], [0.39898741153017037, 0.2950097459891278, 0.28381992368588504], [0.2533349073897674, 1.06121028108515, -0.056292521974512934], [-0.6146603490368638, -0.468127369926298, -0.9978423279137126], [0.15373949347004512, -1.6646428333489498, 0.1669536402479143], [0.3898535821096163, 0.29072265503631844, 0.3365942572769483], [-0.3073821011536955, 0.1380714611659387, 0.34744665414368225], [-0.05358286822942995, -0.7497836648201833, -0.3121024554747087], [-0.10650701877457926, -0.5339117314927739, -0.9687417156333742], [0.3688796630707358, 0.04408477766286964, 0.06944644342226751], [0.27655783826392394, -0.762560876326497, -0.24044100510710453], [-0.18848190008266974, -1.31341594991108, 0.19359069034123189], [-0.8099844661330684, 0.8582611746158854, -0.6787946928003536], [0.2323927546215261, 0.3658132604911385, 0.3406171975958548], [-0.894894999492345, 0.029010298306936872, 0.10523368300431665], [0.06537400038944607, -0.5580914981195508, 0.44225007966858215], [0.5922214583026035, -0.25203884503015106, 0.709951316836125], [0.5690356713066489, 0.8129285508417996, 0.2660186818541392], [-0.2518205859108783, -0.21565620458750992, -0.13352747301320056], [0.22104876316038596, 0.9423767801928014, -0.23518081988558842], [0.336110610431048, -0.0004220877713755627, -0.6953233659211714], [-0.26104793527433245, 0.192395688356685, -0.2724641259649507], [0.6188305497894063, -0.18790068527401932, 0.6032749579693896], [-0.10517913379208077, -0.2686249155951495, 0.01789532107436099], [0.11676999717267597, -0.6451789172133028, 0.24271985017920403], [0.6787017185867296, 0.48540370572044667, -0.7483315133899253], [-0.42016091567237995, -0.29572196274265755, -0.03351125163757361], [0.8302915269487862, 0.46436311992149454, -1.1612257296950095], [-0.14142849262495905, 0.15700808368884625, -0.2165836940806958], [0.10861143913631585, -0.28649738401959407, 0.46485534566468223], [0.5764040601395809, -0.43444385371954997, 0.5550862603072344], [0.3606733751402016, -0.17234862589607974, -0.00940984047623301], [0.9831603517922697, 0.9746885590033126, -0.9515667083119763], [0.12584497338948075, 0.15069296463076676, 0.4344686249368192], [0.7478602382380822, 0.12743008596596925, -0.025216668960077262], [0.25756348151188, -0.11366901207929542, 0.19263757467564713], [-0.4312324025190186, 0.20540889730996173, 0.3448070418191137], [-0.016134754138915845, -0.3467630425226597, -0.2577654785102775], [1.3263309273684216, 0.6967395173079383, -1.607734115493989], [0.135790944495701, -0.03803957830910731, 0.21473625128212076], [0.4974291142678114, -0.12372243830719236, -0.31737568169715796], [-0.050102797245892575, -0.14103084006056046, 0.36226216006327366], [2.7020949885397014, -0.6777532763168443, -0.8183622069417718], [-0.005622833695344127, 0.46577218987892915, 0.03856858131871156], [-0.8690943722436123, 0.36797137205254427, 0.09585521836966572], [0.3530358515269644, -0.7395522869704834, -0.34828608597146], [0.1736245014872453, -0.9928462944582497, -0.2506788139124182], [1.3367712938699925, -0.6377852754185748, 0.10715748528759798], [0.4008348586938773, 0.797659644602392, -0.46527363532769456], [0.27494453379841777, 0.4055386374760124, -0.0193829425323717], [2.940582472872362, -1.1080013329292742, 0.218382190094642], [-0.2218055183214851, 0.33631779014532176, -0.45057396923515686], [0.5165140276731166, -0.32789689634626606, 0.9107527049824039], [-0.24627700086962634, -0.07859621426819263, -0.17261106900741982], [0.06201238932082521, 0.005150815521745868, -0.2150556548185314], [0.3119560790725976, 0.3686249217157405, 0.15161669752346396], [0.24406121906305503, -0.07587913298745953, 0.2567303401120268], [0.6070092836763158, -0.22430836867097598, 0.7266714686088865], [-0.05437301238899712, 0.012259850943716111, 0.45173712715998865], [-0.13034324969267475, 0.21344695251357085, -0.37076239782436604], [0.8583220654933909, -1.7202977575892817, 0.21243625455376217], [0.06682454904662014, -0.5622555185624204, 0.3046354969324518], [0.0582350194842001, -0.2136551194792838, 0.7802870103240964], [0.5683223649589615, -0.16776982268139365, -0.6193216169848219], [-0.48068386919783423, 0.22142651529213803, 0.10825149880225468], [0.08031075869620559, 0.7725608216631602, 0.030456710215144636], [1.0484662003643361, -0.5670073655231109, -0.29652984679589384], [0.7823552714387064, 0.15173933246091345, -0.38359574636588484], [-0.16902647987972186, -0.5532668286138277, -0.6552717662822417], [-0.8149085378206788, 0.4412076136381367, 0.05426811886475035], [0.25523744193014786, 0.3745374252421197, 0.2971346454752988], [0.8630741556160928, -0.7685613553284798, 0.08473412953950174], [0.553442961921905, -0.2664456794224844, -0.5769320058255932], [1.2913070484623301, 0.029573760423104865, 0.29615776734837357], [-0.11974257278855323, 0.2642641802716766, -0.2042600574297933], [0.2748256118708101, 0.4226336505296784, 0.8087995602407325], [0.04858312539909977, -0.7338874146578666, -0.44415792804844506], [-0.04997198344356053, -0.7053797776196401, -0.21896176610344265], [-0.17804084056131872, -0.8870198254414751, -0.4263742722658291]], [[0.3155980329566163, 0.18963580127491067, 0.23323548363799565], [0.1628499201984269, 0.13984782993207973, 0.25248113655198196], [0.5416997873728883, 0.17917964408496292, 0.35963885035219206], [0.427944005684882, 0.0925412650344158, 0.18792397629757362], [0.2603262462920791, 0.04146818499751334, 0.1082133093071495], [0.10849031332187395, 0.15682635064405925, 0.4521595097362802], [0.38010729574133933, 0.3092686427836897, 0.17200823858069145], [0.4270755292856357, 0.228124579898043, 0.33659409216611963], [0.6918819076151532, 0.34290074439524215, 0.038286003086075895], [0.39293702916469886, 0.08610869711674148, 0.34562049247726423], [0.3391365620813186, 0.3717097804544733, 0.27577081537424547], [0.2827346898815013, 0.45998782691024503, 0.09674487327146764], [0.28442609094775373, 0.4740307353346205, 0.365624369829575], [0.4974020602764272, 0.42046676458612925, 0.18788140135427966], [0.4470240114695132, 0.18237424002332653, 0.6535608155077736], [0.324881846895599, 0.5530732053534881, 0.13345944222294742], [0.0934728866724836, 0.08973032232650505, 0.23454782013512612], [0.34916045667718315, 0.1101835834459442, 0.09286324556628438], [0.46534142703084486, 0.4811038588447611, 0.35609988087380695], [0.38035905004595594, 0.21983798676497274, 0.296394039645872], [0.19619907462163602, 0.1415252367835415, 0.07438111091307588], [0.10126668843676855, 0.3060781856550071, 0.5796437470687796], [0.24356853723601932, 0.29101732540401914, 0.16861025085221923], [0.08502055814285286, 0.1032229987955694, 0.20514807691757914], [0.14263358523333075, 0.4127035975507859, 0.05387612053558101], [0.22125155670883861, 0.5390897953800058, 0.1402830637526437], [0.4909629021204996, 0.16105697048475637, 0.38319928191206787], [0.15527107130622794, 0.24253977042384517, 0.2308317588632119], [0.4581469003055936, 0.14378674656935198, 0.7218853345877396], [0.315797364618837, 0.15988702210021943, 0.07031244405724797], [0.11256142520499458, 0.23215163160068814, 0.042083442112060186], [0.10783481527311015, 0.40460062088257165, 0.27302808755720953], [0.2744570246510944, 0.12346023572978328, 0.3690396997800071], [0.3531826164914895, 0.23100092847256803, 0.10118728303896103], [0.363371036467274, 0.07144720967083229, 0.306491389534983], [0.4374684532731506, 0.19676884195258335, 0.1772735346974343], [0.09526763791417317, 0.17167902772940732, 0.07688576883096092], [0.3373797091907043, 0.6506823071712151, 0.27584220348673255], [0.5067304139088806, 0.5455819169886568, 0.048581152261935684], [0.3777327365267871, 0.13857260628555645, 0.5863858827748119], [0.5684622534142477, 0.19478052209026364, 0.2639631283204646], [0.16919731806353427, 0.09864865210375363, 0.024879395238650542], [0.20502350370240874, 0.06567070535732222, 0.49442393566282294], [0.3545373705598628, 0.1457502252051324, 0.1825952954926643], [0.12945705078119787, 0.09796150428886648, 0.057490086776380823], [0.42388085912398815, 0.11414718634987568, 0.009694858646108851], [0.43386956026311135, 0.20766711744181923, 0.07597152281507993], [0.2479839942320253, 0.37491262819767135, 0.1547354175342778], [0.1120074894993339, 0.04748423661766066, 0.006580229216317871], [0.4524690825755954, 0.49040924351158693, 0.0531307719719594], [0.050244965535448056, 0.09995129765259117, 0.11168252248696497], [1.0651518423993551, 0.23361405821226372, 0.2058849195985256], [0.025096808077854044, 0.020043759089971695, 0.029789270925192218], [0.0555473233800251, 0.13718814592473536, 0.2840210963407277], [0.09348585915862814, 0.4171321245048294, 0.40410386949412275], [0.03770939408637708, 0.06718838991627342, 0.5509832076891867], [0.1823352743002119, 0.20877051337537528, 0.30528573333521136], [0.29052414610008326, 0.22184277482075523, 0.17768813159036162], [0.12771993078440688, 0.3221222302261069, 0.1510368845578], [0.09809241788172357, 0.31389331242520385, 0.1014861758702213], [0.20014564155033232, 0.12511332006392278, 0.06054224165797575], [0.4877581113899872, 0.2291946368031771, 0.09000764197242875], [0.11406244907555085, 0.6608167619493402, 0.7756094423813646], [0.10009977578052427, 0.14945543381242068, 0.05028771985968831], [0.371023246589347, 0.6672548163544176, 0.46174230617155737], [0.2556995015332709, 0.24473045568505286, 0.27428801777962875], [0.37861224879634753, 0.39164690439559496, 0.22544828048510648], [0.6662062382724446, 0.1725065157274253, 0.21429404962791906], [0.18943284817039485, 0.2314717613419159, 0.35837052300894967], [0.27095538869970354, 0.18376172328814244, 0.27628221856314045], [0.18218680126132888, 0.01735986712858432, 0.10510517620085665], [0.23775508328568873, 0.2058628473147947, 0.4742739658430923], [0.8595470660419765, 0.18183519647354202, 0.1934782277814212], [0.08285659221651044, 0.17657441071690672, 0.2677216168511758], [0.3988718592121871, 0.12716919750733816, 0.5609505953603601], [0.3781161746929667, 0.1694794097747248, 0.29520085392129264], [0.09926657476326928, 0.12396820877830889, 0.1350747473545523], [0.18679918378039914, 0.12933832414381033, 0.16104752882968726], [0.07543679510386335, 0.8245162771990144, 0.6673614743688886], [0.13727928533772968, 0.6225627516923531, 0.5379123669923563]]], "banksy": {"0.2": [[-0.8842804481270848, 0.3786712370678177, 0.5440291961160418, -0.038182702449808543, 0.3956807118744111, -0.12041571910927788, 0.03247034012374853, -0.08893198927442146, -0.02209221694335729], [0.297491006008758, 0.5242030916226729, 0.2815126154320329, 0.2742765478521086, 0.1395894486541602, 0.13464320128100923, -0.17592587339772808, -0.16369043889346915, 0.005434947401136843], [-0.03317179460143021, -1.3753058559309848, -0.09513161391681413, 0.08101611116248246, 0.2445038915470394, 0.2597726182657156, 0.34094386978041963, -0.10463228955600962, 0.15870322111166363], [-0.823837280922303, 0.1378582845976939, -0.4048319735493924, -0.004090087095783751, 0.7346491777570722, -0.0018023376238272806, 0.1857453947099952, -0.23472296649336005, -0.08690151776734267], [0.34802205295809463, 0.7817324184339162, 0.390816871133067, -0.5112682974303631, -0.2436816982098103, -0.7259329952895279, -0.04293766883601421, -0.3114110535523269, -0.2009121278547802], [0.0886675159547601, 0.10706644407836709, -0.38458978904445185, -0.06228467216447077, -1.0091032652941094, 0.16989265848974958, -0.2500893837484136, -0.13819657258362508, 0.2910360345272018], [-0.32364509218115756, -0.4398108827839823, 0.47209444405410467, 0.07567912432445645, 0.241761401394889, 0.30036050076551135, 0.12048115648440715, 0.09070107295930167, -0.10966588589527924], [-0.17043150788817124, 0.560800444384134, -1.2874662954288223, -0.33172257908425873, 0.14410907712377155, 0.3087069028684976, 0.1845605211958968, -0.03113968844370215, 0.1257421753782586], [0.5789885745342327, -0.687934369656872, -0.678237759691437, -0.18342517793400437, -0.423859731179103, -0.19854160113855818, 0.5458392667314838, 0.14120089663351876, -0.3009295426506371], [-0.3519021156310685, -0.502748564694852, 0.37281042611254833, -0.21434928236686715, -0.28576453847316735, -0.7035521872046959, 0.13798492669563492, -0.24438170115606092, 0.1386526859187194], [-0.6750496712589404, -0.9729731256506629, -0.792547008514054, 0.0634238560576293, 0.08398496107917715, 0.09490145768538763, 0.06458425795144987, 0.18445871197966415, 0.038746304481936604], [0.9428661547223929, 0.061828784884551215, -1.1223194351415502, 0.00947930102272602, -0.4320334268421365, -0.14342794399940292, -0.012365541229188372, 0.31701140915602827, -0.21731549566669323], [-0.1753517891682148, -1.4249644096680718, 1.9087210344852157, -0.2622480160136232, -0.7844203090420128, 0.1903787809239289, -0.010057941014767414, 0.33809734685611365, 0.16726434289212308], [-1.490217399562744, 0.46552917635513125, 0.6316247904151713, -0.6253981102496898, 0.6048208321478098, -0.48055864293557293, 0.28050791133997555, 0.257669096807042, -0.08696241294539915], [-1.4263375541504097, 0.29970215942096107, 1.0965123112115844, -0.016326794016598322, 0.2897975285136529, 0.30345447880098425, 0.21177649183902889, -0.09983548757613224, 0.5791014417100696], [0.21854279461766674, 0.26322441222236, 1.047234805074113, -0.6750121744152036, 0.0743416827728589, 0.12242484218520101, 0.04513636680641321, 0.4567824901406566, -0.1648024436085746], [-0.04451578391958231, 0.3332889519509195, -0.055474524270016895, -0.113917503454879, -0.3012325499021702, 0.381618677095702, -0.27057785194653655, -0.23894369919532896, -0.020215174756571544], [0.35941774932039716, -0.8539581051925448, 0.885967184695803, 0.19392467522677817, -0.10544794995400641, 0.5875033490538548, 0.07825998618662292, -0.20823238379719736, -0.22286740935038385], [-0.6159795854833837, -0.9926481509718692, 0.44878768660998053, 0.1803769906435491, 0.5758211501629671, 0.24608197240335464, 0.236767177324773, 0.34871789903609896, 0.15364141339451107], [1.2696596835831162, 0.9142282320160291, -0.4541383938966498, -0.29925743638251245, -0.08217365178270561, -0.06120248357217089, 0.12082462811801672, -0.0435823093929765, 0.06824381679682738], [0.4162496108488612, -0.4013107058643097, -0.05271511691037472, -0.02295520038715562, 0.6586303319872492, -0.1393824210118003, -0.13042719337840866, -0.16117175150345345, -0.24930250928228648], [-0.10574133135199588, -2.1322824821944146, 0.2708116907010817, 0.044276574607524655, 0.05551352403711655, -0.4932705768787594, -0.25994466802507493, 0.08591048555267713, 0.47337744783586244], [-1.0657245720918946, -0.6272645944366747, -1.4368527457329872, -0.30464906784782125, 0.17886076766025782, -0.16805640594695684, -0.06580042668956541, 0.06329605616490243, -0.11452604663185022], [-1.4834237656348903, -0.8557050991917735, 0.9206472574498281, 0.2094726304707553, -0.06441819960710247, 0.5054602947021026, -0.2821094723980642, -0.21868395478652405, -0.06226579090621694], [1.2465729934910303, -0.0027115551129737224, 1.1934971954794886, -0.21357338604258735, -0.11605820657978931, 0.05525432707825213, -0.20350727903301308, 0.2460124191790322, -0.278630911001169], [-0.4089773454617084, -1.7557581070377826, 0.22807085829011692, -0.08388631437420031, -0.35694314523822107, 0.2281632195161572, -0.0962477700649921, 0.43578589152837754, -0.15504257980389827], [0.19973405055361224, -0.3775319665638507, 0.38418700162057956, 0.24445594635461648, 0.36630059829754247, -0.5340382818329336, 0.2717228851047541, -0.13184414303713304, 0.1924018373381149], [0.3085942383212327, -0.7815079713133952, -1.4393575381396815, -0.3976203554692576, -0.133392428263539, 0.01571836724753377, -0.18626579435299387, -0.009494755629476747, -0.025530277850416404], [-0.3723270683158264, -0.17539483185077637, -0.2870762215979447, 0.3330313701726479, 0.35284074872022303, -0.8515885149840323, 0.22695159204160195, -0.1577760123153405, 0.6768263811485201], [0.6643109132833454, 1.6239980618286014, -0.3526599714769406, -0.23475424481170343, 0.1562230027100786, -0.12507967371702966, 0.03274229087254433, -0.133600863084231, -0.25512194610284655], [0.4169590285280992, 0.89495154556176, 0.805394744498379, -0.0886534404997815, -0.12749138333955404, 0.39900401988820117, -0.24453511347989837, -0.025092923859692914, -0.2954980445027879], [0.7159836826963285, -0.3409498408924565, 0.8327110781139511, 0.18468241309104103, -0.22213405378060386, 0.4683991502888847, -0.2509836881615185, 0.23384550502935095, 0.03482336563911374], [1.5540391463912764, 0.7674144340083483, -0.560988902526357, 0.05862884088296932, -0.05446940911976574, 0.034254370977600944, -0.023658866296621617, -0.18829700755869722, 0.17214930830516423], [0.33875085606478605, 1.1936186088802583, 0.45261847097459595, 0.42235413596661253, 0.6793004638229683, -0.6903431681293309, 0.08374747051846944, -0.026820746454385435, -0.2109614922820376], [-0.6658163688001365, 1.4544247866984155, -1.20661256647853, -0.07858371604501584, 0.15218316496996936, 0.37563408669276876, 0.09764766284412697, -0.26639645775294984, 0.08268611247178591], [0.24929430106346814, 0.0056780227838315964, -1.1491084046090725, 0.28486595316797364, 0.1373016949122677, 0.022097596016347112, 0.19873972097326695, -0.07822146928836873, -0.1021349035910792], [0.8634918769657195, 0.3439388878837906, -1.121569020587735, -0.0016192894276613756, -0.016931539082494784, 0.18964575515152923, -0.26812924975939745, -0.11589473779009195, -0.24572008313958826], [0.33361773287512453, -0.38030436416088614, -1.875963137195203, -0.404089534699266, 0.18718543298578574, 0.30667681991747875, 0.06218736097179375, 0.6033461062871047, 0.03884841129605498], [-0.7734726032916323, 0.2655799099178683, 0.726004447532527, -0.16154387461557143, -0.1660438602468161, -0.15675191500977098, 0.2932347040989151, 0.4455340482238793, -0.2862043335563265], [-0.04051818473431678, 0.0626712080623202, 0.556147838272949, 0.62287209625677, 0.5014939936454054, -1.1949908597376824, 0.11724151482756659, -0.1656052335750033, 0.48302076201399335], [-0.3635106655198392, 1.1142473085921523, 0.22676400929977436, -0.07277218679028354, 0.031449281294439496, 0.20664148827541318, 0.37745624618107265, -0.08120700387121499, 0.02185770405302765], [0.06958464914142908, 0.5231780475350413, -1.0091983495768484, 0.13853657138055697, -0.023362805115539842, -0.20259715374809134, -0.16726603690667616, -0.22555250270034474, -0.3201050883786839], [-0.7909043640548207, 1.4409510824847531, 0.4180987504835063, -0.1813917380503188, -0.03443514341686934, 0.3201012677523629, -0.1183879113623155, -0.2750700890548192, 0.3514870778669761], [-0.42496260128694147, 0.33798869923742253, -0.41925992506221127, 1.4267446395930268, -0.37778125201912127, -0.5878977504012468, 0.08559577890672918, -0.1548277777375482, -0.09452315954336638], [0.056413083049482816, -0.5979714933120146, 0.35732630571267654, -0.1554016555673953, 0.35374214328462406, 0.0711537956378606, -0.2214841943452617, -0.22658428013402154, -0.273461834997847], [-1.5358726617933645, 1.2573005005234268, -0.4513791253657371, -0.6599366128189429, 0.29117809164365105, 0.11521201741380188, 0.18020199163297299, -0.20228088989191018, -0.3418236154739179], [-1.5389080698924702, -0.18727014551648707, -0.30586762745167023, 0.05416616032236747, -0.417314627913369, -0.2263698434504016, 0.19382970498276905, -0.061857312301806584, -0.2470277342981606], [-0.051812243194712324, -1.0433759087463774, 0.48180992328406597, -0.05066566537384459, -0.5793490537700652, -0.15130167641003467, -0.05977636195764141, 0.1892679043445953, -0.1343712978531208], [2.9257162398858396, -1.1673373298256813, 0.42056582114560875, 0.6289725056291701, -0.3522133669261278, 0.12390440726378087, -0.24529085508291756, -0.30237773325788325, -0.3462784872607694], [-0.449068833688179, 0.19966472184318113, -1.7827086876666698, 0.08209559280623473, 0.5660534952527669, -0.3163430668738039, 0.21920527233505432, 0.3626902725238757, -0.2796969871949173], [-1.1698602459121947, 0.44778919995009026, 0.0350268248667193, 0.008536631272537855, 0.31521020493473145, 0.02658422022686603, -0.3295542603662225, -0.22359653303522867, -0.19595009295922902], [1.2201503964914975, -0.6341389985012651, 0.253268476924012, 1.5660952346515595, -0.6530147544639888, 0.2094455205777579, 1.0550962364302185, -0.022897037118090005, -0.06121188072374086], [2.316303751331696, -0.6905965035089612, -0.85202877876122, -0.2817193356263747, 0.27092901421179577, -0.3050377925187871, -0.36386421481718834, -0.34358060819831265, -0.31308246589149114], [-0.21267200460439764, -0.02069719811447844, 0.939681593662583, 0.14968807497879272, -0.15397501900520835, 0.741936434102932, -0.3223201854071751, -0.16768405115568621, 0.05054672720947961], [-0.07138915659282986, -0.6823996310581216, 0.2911137547384869, -0.29601826483261884, 0.005504841125925717, -0.09126104223015238, -0.270560153416953, 0.25266201345353617, 0.22230178515993732], [2.080819668041177, 1.202346252632345, -2.7773330872653874, -0.11588172603904719, 0.05907855976145929, -0.12390448354772539, -0.3466567016150376, -0.27279123049565646, 0.43238411904468615], [-0.3043582786475476, -0.7923629178716094, 0.7122279927081506, 0.03016284311516268, 0.2915961731667599, 0.1580972650314511, -0.14934175434962246, -0.060200523180180945, 0.08096165570732075], [-0.3311612191264292, 1.8164266981333321, 1.0289270614025294, -0.009508794875484866, 0.007242982149063931, 0.2389384596843111, -0.0017382859915830305, -0.04057204721874423, -0.10154190335048807], [0.5812393802724055, 0.19405536489442024, 0.03310018980573841, 0.20256534780217444, -0.08770851797866194, 0.6003625461171507, -0.223854169484246, 0.11000120195273445, -0.13966133012856763], [0.10926454447643073, 1.224186417456874, 0.622157947997673, -0.18388686697871803, 0.06362627284957685, 0.38891501117800287, -0.2642753661425129, 0.09764518261219793, -0.2105339842040179], [-0.48373524428145404, 1.2054225771683849, 0.27131968638369003, -0.22827702776484365, 0.192327448277972, -0.24365600970658716, -0.12504284139200222, -0.18581484131298212, -0.26909632090456015], [-0.2491151233299712, -0.7145822869100213, -0.5057396798710443, 0.34940989098656744, -1.0447062145498893, 0.2048725981614442, 0.2673505479196474, -0.029532959085698293, -0.22695179504423926], [-0.7281313313517651, -2.5737468320784718, 1.116678433269161, -0.11306993353269135, -0.3038963107562382, 0.27578153744306, -0.24248724732050117, 0.6185633586979339, 0.7536682711641973], [0.3033800191292837, -0.17837737671562456, 1.146544569411538, -0.11808888058203204, -0.0808935398692113, 0.6415973881174737, -0.2615367019604242, -0.14926427226574093, -0.2837634204348919], [0.1931629771291142, 0.3659405051212724, -2.462240695359627, 0.1799601986920242, -0.051540308043269534, -0.4348188666305433, 0.10808767146822851, 0.6282303315209984, 0.3047423615368719], [-0.3824161638407231, 0.5151783900545026, 1.7243433293602506, -0.432984515614063, 0.19743204544644252, 0.12474579528262635, -0.04924999617843024, -0.006205362040742641, 0.036625450839867006], [1.3960456411488884, 1.3454917830073423, -1.1162506171392703, -0.10518980789418007, 0.5499975553394088, 0.06491508737190124, 0.11844144472137956, 0.21439502863410181, -0.03323029689998803], [-2.067674674640062, 0.5507457830426296, 0.10271188786341931, 0.4605129889763828, -0.3069361094536929, -0.18656496082380353, 0.5108096210354975, -0.11465223446766842, -0.049184255298514945], [0.6431291185437626, -0.09625535902245118, 0.2996555472115063, 0.3050217421248725, 0.15285253576272656, -0.2535259295566086, -0.1396584430927651, -0.026113773778199, 0.15688912546231953], [-1.4692108949097782, 0.4369649835875348, -0.38161784706457014, -0.25088002163026635, -0.2981461659759894, -0.4624675423455291, -0.028436193231951654, -0.09775213099516665, 0.03947776730577149], [0.117675526874669, 0.4475536275853683, -0.04574783562258978, -0.6282752940218254, 0.33802796572840177, 0.08322805488208644, -0.14954431802490814, -0.34761056958390013, -0.20535770791402097], [0.08921047692161863, 0.008064525921389143, 0.852589154548836, -0.0029784173531836626, 0.2953784541759891, 0.2700127544594526, -0.07373179663485735, -0.06456648951373849, 0.32266646402533145], [0.24785141685291706, -0.4877262385654485, -0.5281971446935688, 0.35218658422991855, -0.43587198654433706, 0.10665896868738609, 0.7745869973888313, -0.10064488106962391, -0.07895724099534437], [1.3132209424894707, -0.07368791930944311, 1.0910138972737256, 0.17126601638249322, -0.11466412984838072, -0.4022177054245181, -0.2850617989250254, -0.10854414220311964, 0.027233491090972006], [0.15490385989122515, -0.5034248786950767, -0.6932967411563664, 0.6024072975253866, 0.07470213449215071, 0.2692614533641229, 0.1460818916103371, -0.18272786656524248, 0.44664052903690205], [-0.07949541352498843, 0.259171697135073, 0.7041316846020373, -0.2220829474392193, 0.2248356801350219, -0.11560176500040104, 0.11776464444605125, -0.11919754414293532, 0.06653719662234986], [-1.269298533920138, -0.5318290223414871, -0.022832873103082497, 0.008467144014437053, 0.3261460365899564, 0.6635259269930827, -0.2626734488174741, -0.18753426755279207, -0.16249206369977562], [1.1905663746578226, -2.1721981003803785, 0.5244973510405272, -0.12372857772573859, -0.41369075879056433, -0.30010331948843116, -0.14325158527076576, -0.179470844035575, -0.12534304997989837], [-0.6457828617720379, 0.42151145561638126, -0.4298755698184977, -0.1813153022522397, -0.39545417022759477, -0.12690861027136346, -0.29518472349314145, 0.8643641341339761, 0.5988406007934247], [0.13016981935050465, 1.4744543994598645, 0.4374588624170039, -0.2561472017029136, -0.5116509217943108, -0.2864261987707219, -0.2108122191998884, 0.5611235711068434, 0.4136888229385783]]}}, {"name": "decay_scaled_gaussian", "n_cells": 80, "n_genes": 3, "k": 7, "max_m": 1, "decay": "scaled_gaussian", "k_per_harmonic": [7, 14], "locations": [[6.4285101384599805, 24.963893122005747], [30.074917881167874, 1.4344504185972273], [7.396304228872797, 46.41055114801848], [3.5210288077098415, 6.488697469964899], [47.41642266458875, 31.094179639819142], [18.44965618648955, 25.569501090163133], [33.14214762583996, 13.765440788056466], [6.898403643347767, 39.401979725199595], [33.518029205124186, 25.61911567415802], [40.8368217984829, 27.453763443501316], [49.045681964865274, 10.225473066502245], [27.68651814326139, 24.181234846169385], [17.663742753022404, 29.579765197452172], [11.765061583379028, 40.11013418892417], [43.36667759212073, 6.437983561392552], [23.353660336913556, 13.857244626685217], [4.15584988676212, 44.797215412518376], [21.497434602391767, 7.384564998104704], [33.66811786379554, 10.110801389401908], [45.07155393440885, 10.857412870926408], [1.6537343688714345, 10.038447708060966], [17.287393687781975, 23.44540817112423], [45.30671694477803, 34.86805443681489], [16.966033037122262, 0.8438607548748922], [7.991184705249049, 49.821793776983526], [22.98579899465923, 34.551995815937964], [2.7334030700919, 1.7025139473518802], [42.294505322252874, 29.394097033343026], [15.435487160228101, 15.868831914066872], [4.461862720887439, 8.633480055428771], [1.229305373259315, 41.956242418639086], [23.315159860158257, 6.36014580292652], [36.9623437016846, 9.782641497266049], [3.0960117574226285, 29.919605366201907], [44.78788758706408, 1.34717056923514], [40.25679949458346, 9.508500836417038], [4.645071081827357, 0.8981017826278082], [14.648753350604299, 36.35558719909591], [24.658947550405845, 42.64599972272639], [10.860565176074516, 15.759137357171582], [12.907042592729418, 48.91505686571085], [47.050299732571744, 17.034308792825453], [21.800075179616552, 15.715981435192644], [37.32544586527053, 2.000655127659512], [3.371946654601304, 20.20187937342031], [12.2547025557032, 42.261249085061344], [37.09035482376451, 27.289699126147838], [33.07377571567503, 34.61395533424619], [39.052741169917105, 46.37512985578414], [7.4867586893866465, 31.306507887269074], [7.181072155667756, 22.156547064234843], [39.3142394311866, 44.73488968430727], [37.96140770622649, 1.7704102040796865], [17.970603821688837, 8.152841621076446], [49.94012438162009, 7.200767881501868], [12.215722142324148, 17.860985638976352], [3.044335145459398, 43.51924585216669], [31.818071093156213, 7.987411997920995], [24.91342788562751, 3.933487931747881], [30.548989367994782, 11.583161404872882], [1.931946643237925, 5.761875184695126], [27.763131131011054, 31.84903054790911], [16.240032356709854, 32.17262147805434], [17.603304995430634, 6.53295033951164], [15.76051409616836, 19.763411312690977], [45.63194173515474, 5.783018685987818], [4.308194528362675, 28.07510135358564], [48.1696394234913, 45.36275631283964], [35.012202889228746, 3.337537332282764], [40.32007121404446, 34.16873686910788], [7.1965119625464204, 23.247186301368565], [2.466132768976703, 40.093798264232476], [35.931710859414146, 40.23140499590264], [38.02078203100886, 13.362878848134867], [39.487025724675554, 12.45853229602032], [6.89477389681965, 19.51950168045739], [24.892017644551405, 14.291107381848533], [30.28914522769588, 30.12518646046972], [11.990882910715822, 31.12837439163244], [17.86264587770882, 36.73447993268751]], "features": [[-0.818083666605393, 0.38526930227745887, 0.4581670048370468], [0.5596122240618859, 0.5419022252820672, 0.20205463691158088], [0.17412924424976314, -1.5024999410944402, -0.1654011831842485], [-0.7476197010175331, 0.12608730560642875, -0.46754626006357575], [0.6185207511629426, 0.8190757096799433, 0.30869236500853114], [0.31616814431588613, 0.09294668494996648, -0.4477978929622047], [-0.16450126423277087, -0.49564606330714495, 0.3879871341457924], [0.014113411841972533, 0.5812911986088503, -1.3286483115981003], [0.8877789284048715, -0.7626962368507467, -0.7342821862702664], [-0.19744298486173803, -0.5633845877352657, 0.2911251954982905], [-0.5741647764650408, -1.0694775505189256, -0.8458028083790133], [1.3119833252675124, 0.044258328637274344, -1.1675302849446099], [0.008377403177420764, -1.555946414705409, 1.7895665579723081], [-1.5244781602909778, 0.4787527046455685, 0.5436256643142272], [-1.4500077538405294, 0.30027651841828845, 0.9971720401657596], [0.46757528576185525, 0.261016274083352, 0.9490966814610048], [0.16090454888866232, 0.3364252880770561, -0.12671154648393168], [0.6318057260154758, -0.9413841472373661, 0.7917632588742233], [-0.5053015337885142, -1.090653373060846, 0.3652489557719693], [1.6929555515236436, 0.9616782115907366, -0.5156498276026669], [0.698059671998619, -0.454209119721369, -0.12401945613631439], [0.08952849321707658, -2.317218216900625, 0.19161476616248335], [-1.029609188818006, -0.6973986134552436, -1.4743904107207184], [-1.5165582181462036, -0.9432644007214415, 0.8255972952985817], [1.6660413474635754, -0.025205103519519486, 1.091790933563312], [-0.26398064687868195, -1.9119728247927603, 0.14991661602143025], [0.4456482631425715, -0.42861655475758254, 0.30222423421292294], [0.5725562476093207, -0.8634075676336961, -1.4768340975643026], [-0.22125416534201214, -0.21106054027038276, -0.35266321385541605], [0.9872467528013661, 1.7255887894094382, -0.4166470179838092], [0.6988867031627518, 0.9409311129269357, 0.7131564204233815], [1.0474862871297028, -0.38924397003268574, 0.7398063595133139], [2.024481935859489, 0.8036655593800595, -0.6198936689169603], [0.6077124939345443, 1.2623802917054945, 0.3689862863896283], [-0.5634006961428569, 1.5430805830215768, -1.2497670465629258], [0.5034250466559266, -0.016175574467128036, -1.1936657251775022], [1.2194496835829487, 0.3478875937013457, -1.166798177099069], [0.6017283565618432, -0.43160042891134, -1.9027885021671262], [-0.6889051253999523, 0.2635514475016157, 0.6357028862761235], [0.16556490512827252, 0.04516501126799043, 0.46999000714326233], [-0.210976101965214, 1.176954603942294, 0.14864164821343293], [0.29392155247372515, 0.540798991545746, -1.0571688403044779], [-0.7092268763497593, 1.5285791140398155, 0.33530869036097966], [-0.2826160786151785, 0.3414835288114959, -0.48162223506155016], [0.27856628863229466, -0.6658710549900579, 0.27601881733916134], [-1.5777025523190094, 1.330919793665682, -0.5129578726969883], [-1.5812411969951867, -0.2238416945870532, -0.3709961947182103], [0.15239841860045156, -1.145250608848122, 0.3974655997902583], [3.623567688368005, -1.2786677207432902, 0.3377155756992855], [-0.31071885365042484, 0.19260829481441374, -1.811809037837263], [-1.1510093879783454, 0.4596595352026752, -0.038418019395222595], [1.6352381805909817, -0.7047973922713666, 0.17449952715639466], [2.913121452537828, -0.765561436417932, -0.9038334934759573], [-0.035130084895088134, -0.04456267883565894, 0.8441672801225347], [0.12957587279758478, -0.7567393122486353, 0.21142155200757654], [2.6385967525787044, 1.2717736740410226, -2.7821691176232233], [-0.14201691359430452, -0.8750905219509657, 0.6222625144051509], [-0.17326348062410027, 1.932695747995194, 0.9312355636189067], [0.8904028924592736, 0.18657106002655185, -0.04029765330752769], [0.34017992887452764, 1.295279791418775, 0.534389769872797], [-0.3511325658376627, 1.2750846584688966, 0.19211036905670717], [-0.0776150634716236, -0.7913768386620321, -0.5659922764661505], [-0.636046779726964, -2.79235715975389, 1.0168462003981633], [0.5664775694278109, -0.21427059157909795, 1.045983738409203], [0.43798777953339196, 0.37156747896960074, -2.4747635495786637], [-0.23301591961061885, 0.5321891257672531, 1.6096868317882371], [1.8402948816174964, 1.4258382457202734, -1.1616095185495017], [-2.197671367087202, 0.5704695747069322, 0.027615835350643075], [0.9625532543524465, -0.12588436360404337, 0.2197549635234998], [-1.499989013056637, 0.44800965515897445, -0.44489845287418683], [0.349985357704251, 0.4594059935421338, -0.1172221448808959], [0.31680112211393313, -0.013607030533302129, 0.759199501128509], [0.5017429484459656, -0.5472163690372069, -0.5879018811026014], [1.7437387779906113, -0.10159549531612938, 0.9918077625655023], [0.39338573028374196, -0.5641124904961297, -0.7489737969543596], [0.12012568949433819, 0.2566544207133919, 0.6143637194600546], [-1.2669334275073838, -0.5946832824261059, -0.0948662034142554], [1.6007494601475956, -2.360178570626117, 0.43911164810792375], [-0.540045858613423, 0.43137734284316537, -0.49197890628019864], [0.36455106356938455, 1.5646380406865834, 0.3541965034570923]], "harmonics": [[[0.23645437163716232, 0.5495884131019512, -0.24865174353914762], [0.7283046116734172, 0.1556994189228164, 0.11538764424449777], [0.2611747227894105, 0.33251001764759125, 0.22302396747539766], [0.4635027622874004, 0.7819949174876327, -0.14447219482153817], [-0.5643534938247932, -0.4712624172657195, -0.9216293745468609], [0.1658917449546731, -1.2880114712190098, 0.02704840618830753], [0.48168493508578114, 0.29946742626150247, 0.3254506034079306], [-0.3129479064587826, 0.1469721072758803, 0.33326048586789975], [0.16289793395610336, -0.8098728110160266, -0.30347293791055274], [-0.33363895351814277, -0.32859766052357864, -0.7072105762833205], [0.2930788862384631, 0.1835391457189061, 0.10355909022413505], [0.17917224791471467, -0.6921821288392483, -0.23335134429888924], [-0.10720068203269652, -1.0209482757788402, 0.02611789613498674], [-0.27001642501274065, 0.534503589595926, -0.7455421925276153], [0.3714099002295678, 0.3496529500226169, -0.08713975596689648], [-0.30976928400313175, 0.1732471871451069, 0.3283017567887726], [0.24653842786429928, -0.34604100034006113, 0.3461646598061541], [0.5151562587965031, -0.17995260764350765, 0.7002199132911378], [0.5657329533223354, 0.8762513528965471, 0.31601806248735903], [-0.25433800314017896, -0.20096202936361596, -0.10830571684584911], [0.16359894828252008, 0.6943494045659386, -0.1756210969115846], [0.34794396989761983, -0.11374529951025278, -0.6364178852411126], [-0.3156658502539056, 0.06455200698000851, -0.33828017527593457], [0.6144334636783105, -0.217307291339224, 0.621761241483301], [-0.19483024614360392, 0.027629806502280092, 0.06448953442513221], [0.10815820111954579, -0.6954296758973088, 0.27349486176245863], [0.31370585781982024, 0.6229231123560643, -0.4777579313115754], [-0.5792372416236429, -0.12906524467222688, -0.1751205716386473], [0.706354410177964, 0.42571762197519175, -0.9633910106487128], [0.06451804606528228, 0.19852126616553298, -0.14580449946469964], [0.10617148592978598, -0.2088664729647346, 0.22318314012121887], [0.5005921452228009, -0.2639486767756544, 0.5474745968308395], [0.39614260270858975, -0.273149911117738, -0.06258865151292861], [0.22170459187956174, 0.5838248256738788, -0.6692463578898633], [0.21226849856833568, 0.09728868366880332, 0.30535197923088225], [0.7710019212231664, 0.16324716551099278, 3.8336366568099124e-05], [0.06543913026707428, 0.3172824358831735, 0.016770761440481726], [-0.5519164778426364, 0.06158154202744776, 0.33908569117666293], [-0.01207159664397656, -0.3246384096843753, -0.28604808986142494], [0.7489222875625035, 0.45927906548857184, -1.1124088440758952], [-0.03651194435429408, 0.003993894015467957, 0.14012404126370617], [0.4679031191533478, -0.15914201252596358, -0.2900979427418044], [-0.11003289512388069, -0.2987829893217975, 0.05201905729973976], [1.1120483762265956, 0.07844087753081982, -0.3569013303035896], [-0.0994222278925219, 0.4567336270555087, 0.07530294396178676], [-0.37163667997385863, 0.2693668277233268, -0.2594506275475428], [0.35948384819263046, -0.7767870258138901, -0.3791567514787699], [0.12473017625237486, -0.9314007475540097, -0.27464512117974793], [-0.07892225836839131, -0.3194073985008728, -0.17230595810522145], [0.3710190183740928, 0.7899011951742508, -0.43927923727539264], [0.14722811569699829, 0.3001814287262222, 0.12566544955757405], [0.5707907048604964, -0.5150739778561563, -0.15364371463613338], [0.17689808860400544, 0.39349278830915346, -0.2575209075108764], [0.39429079647330334, -0.39979746645070124, 0.7046050319799569], [-0.17722893389100883, 0.16364724939499803, -0.020218122677337216], [0.03167851022045395, 0.013541456895591157, -0.3616909164104341], [0.33918377123512033, 0.23308615039244934, 0.17628255567711287], [0.40644711677583517, 0.07946103939506481, 0.21947565264338087], [0.38772020667478513, -0.1066793396896974, 0.7290972107108916], [0.021715058832305238, 0.07195347762442603, 0.4244854057072494], [0.2091033043693471, 0.272999962027412, -0.32347907818134686], [0.5982688342983865, -1.4354077946849022, 0.08887888550960912], [0.07764515642962207, -0.35380489625474343, 0.13757776651579315], [0.13546477636037052, -0.4197887656721817, 0.7334887505140493], [0.529619473168099, -0.11371648301796018, -0.5641738447712555], [-0.24940558312811215, 0.22422358533393388, -0.14999836069504505], [-0.12184827740115825, 0.5782921462044681, -0.14145329870983753], [0.9150999259337168, -0.5202061126342066, -0.33124491565721376], [0.8453791430013562, 0.21440990518022748, -0.2830668357861775], [-0.1577378488571468, -0.5348883456802712, -0.584124784769363], [-0.2580353729664435, 0.4004687999636142, 0.07335125684215851], [0.2051144630179984, 0.2263861090659322, 0.13579972135453738], [0.9040618434712412, -0.7503692964730505, 0.08836814343890204], [0.6188683121951203, -0.1298704518406662, -0.4721062151698147], [0.9729630149492663, 0.10469126964864285, -0.04503564844017737], [0.06644268213636605, 0.2642143477999027, -0.23047615331253984], [0.15775758518874072, 0.43195211361805186, 0.6537417402029563], [0.1311496879268129, -0.7264850183626342, -0.42345888950139704], [-0.05010795151173037, -0.7625311629393675, -0.22413411519455712], [-0.36958706023785204, -0.9251674954384697, -0.08536838433767392]], [[0.32111827278954747, 0.2724694554948016, 0.3137623883415811], [0.17751382949664588, 0.14954242214103913, 0.29123884631101526], [0.4724976906502715, 0.2599531207870265, 0.2882665054164736], [0.07623496428712152, 0.11649828479569331, 0.01609356608800762], [0.11595446711810793, 0.09337578433727035, 0.025194960914489712], [0.2037026972392224, 0.32996077195156914, 0.5857772843561339], [0.43524230988646095, 0.25915393305517825, 0.2052872866459487], [0.4098473798639619, 0.21486114333432332, 0.3698511723050669], [0.497291987937429, 0.32454816836526007, 0.019011130178370948], [0.19126963600379548, 0.21613928514469494, 0.17919208491751526], [0.29380265886478485, 0.14816630154898, 0.28799810753082133], [0.2500653730898314, 0.46354775512168456, 0.08446715290323488], [0.21162529287381182, 0.13770364195178625, 0.2088025762192258], [0.172988034868297, 0.2362767562647603, 0.24910641089284305], [0.4199698759138312, 0.1533543313877862, 0.3521413128686691], [0.32434391224590636, 0.2571564595008171, 0.3100938180853981], [0.21711792746209324, 0.15833361471159296, 0.25791978557646034], [0.2654278655976951, 0.19332802282054048, 0.13817683641863365], [0.4114359765318158, 0.41264806207212484, 0.32790254086957676], [0.40616116609489233, 0.1902749776842778, 0.3247805863757858], [0.11100746473455732, 0.16716554096354905, 0.10014806996157338], [0.18271185950420704, 0.5130778956939122, 0.6286979182540434], [0.08845168025012079, 0.23909729455096748, 0.14023256768452794], [0.09592080423032324, 0.11858053419395505, 0.25682251367730996], [0.194420810463555, 0.32347859333306345, 0.08588253632505462], [0.2521266029247169, 0.4927335092420808, 0.09369981077486465], [0.09441622740275508, 0.18149256328015956, 0.05109332797485743], [0.15753349993546162, 0.2902011756686593, 0.14302346656555842], [0.37691699027604486, 0.10749292524431986, 0.6723008389744837], [0.15268197159225902, 0.09460178925905888, 0.05056123579279689], [0.09717145712777571, 0.24838001399242077, 0.1644208589806331], [0.13251197139892892, 0.34634919649033474, 0.207312829371446], [0.22328201916022433, 0.1449981014169608, 0.31941195552236], [0.1374618834976426, 0.10594620967723974, 0.20251981259512855], [0.3585044230009725, 0.07260113285756366, 0.24236993710075938], [0.38544503579228956, 0.17505861235262357, 0.10096557832450452], [0.10762561250015995, 0.2027425412910229, 0.17509318139434618], [0.2978331276355716, 0.6718266443629581, 0.3623198615592547], [0.5315762579996174, 0.5520968640465661, 0.04979660256650956], [0.1433452600234007, 0.016173125729788247, 0.46299454766113596], [0.42641881569497314, 0.18463389862111448, 0.199813634746627], [0.1641086256011455, 0.09128958422606746, 0.0398666673639095], [0.21668536762508925, 0.04409937646567968, 0.631308049628496], [0.29773984061708814, 0.11866083232189154, 0.287110178265527], [0.13857567493431014, 0.1261978430475636, 0.012437447996550492], [0.28341462963967556, 0.1194563059559914, 0.20702937666459942], [0.43234405554163785, 0.27322973035716286, 0.05107974717390188], [0.22953819528967415, 0.3120630500785263, 0.16193639171661534], [0.3308300424745341, 0.22503383322219267, 0.09712918720369117], [0.3511130181378624, 0.49660482166738995, 0.10156821730810368], [0.17779857038949412, 0.17017393969812705, 0.29318288181827884], [0.795341814937979, 0.25012473560744664, 0.22922800319454978], [0.22814378536735702, 0.15729866725281746, 0.04095553744409786], [0.08416847467041422, 0.28157391255764835, 0.37279163280929944], [0.1179607595578537, 0.24166766036601567, 0.23448771961553797], [0.06658076121729574, 0.13139125750462324, 0.42947638452405745], [0.22156707378152624, 0.24056900634070208, 0.23893885392517195], [0.292728291797068, 0.11705389458465906, 0.2061405574710298], [0.06588919682357891, 0.38176584465765145, 0.17546348814336019], [0.22581219934813915, 0.20614965326613538, 0.135799507880565], [0.10445823288210575, 0.15091364700467222, 0.011230131025466356], [0.3150567590040897, 0.06702259868678666, 0.257120145812105], [0.13457330005087947, 0.5681495276656578, 0.4930905394953381], [0.1897891796154886, 0.2456924449214913, 0.22335894843385806], [0.26749207898363686, 0.4908230246734951, 0.329048908883832], [0.14998598770366736, 0.2500929938059425, 0.1166951483718073], [0.21603249356921633, 0.19853345306917206, 0.29451050570675336], [0.5584469262944044, 0.16861973729565863, 0.18054216237194937], [0.1987087946908573, 0.21141594690702528, 0.3566994926395703], [0.2788064570308716, 0.23050914627599647, 0.23425933518392433], [0.07565373728435223, 0.1763263888758741, 0.2692195131642492], [0.22149521247385281, 0.2618598466072312, 0.46112348268199194], [0.7104869148424334, 0.19417209097236396, 0.22245425109399625], [0.13554926351101232, 0.06442457650969051, 0.32457243611993386], [0.19982099050169738, 0.10450682924689982, 0.3019946914525268], [0.34544968493182576, 0.0952147042683467, 0.37008077534693357], [0.10774416974079928, 0.15606070232203273, 0.266416340002676], [0.24695063453375912, 0.1363353888428414, 0.22968933245621168], [0.0756205159969299, 0.7214367530919235, 0.5463808522182195], [0.18683041936982878, 0.7073775878042884, 0.412756124321399]]], "banksy": {"0.2": [[-0.8842804481270848, 0.3786712370678177, 0.5440291961160418, 0.04293065719170701, 0.4496179212201359, -0.16712964375315648, 0.13066418782514555, 0.0598048070127538, 0.12263612552543465], [0.297491006008758, 0.5242030916226729, 0.2815126154320329, 0.5238133547487706, 0.15469346961193162, 0.17274209977946461, -0.1268528002812122, -0.1519322131216693, 0.08393137160117929], [-0.03317179460143021, -1.3753058559309848, -0.09513161391681413, 0.06709978059352688, 0.28708043557957524, 0.27323272269433535, 0.4021235581266378, 0.03824590868318432, 0.07882366151072746], [-0.823837280922303, 0.1378582845976939, -0.4048319735493924, 0.26491620011596867, 0.6236323310387428, -0.06986630892923645, -0.30846994059761973, -0.20884945079941383, -0.3888819341390931], [0.34802205295809463, 0.7817324184339162, 0.390816871133067, -0.7400203616791458, -0.3147443122243492, -0.7954300103744192, -0.23724340676916983, -0.24867705593679482, -0.3732419763274651], [0.0886675159547601, 0.10706644407836709, -0.38458978904445185, -0.02605852590452622, -0.9262853057488991, 0.09026747788952667, -0.07988991954897362, 0.15883135713805616, 0.5900701374445043], [-0.32364509218115756, -0.4398108827839823, 0.47209444405410467, 0.2826929369984992, 0.26233978964057164, 0.36885951613147927, 0.33531578237081444, 0.03686933898770852, -0.06376893067489132], [-0.17043150788817124, 0.560800444384134, -1.2874662954288223, -0.49422075197564375, 0.14815889352698536, 0.37615092046169446, 0.28977662116793174, -0.039423263648726774, 0.2190198372112517], [0.5789885745342327, -0.687934369656872, -0.678237759691437, -0.02898557928740574, -0.568278902328257, -0.21831139918623504, 0.4465856417028363, 0.14950835858137704, -0.3838683532368304], [-0.3519021156310685, -0.502748564694852, 0.37281042611254833, -0.5144504188849287, -0.20792405126814045, -0.5952459279440049, -0.10218536117231311, -0.03722171423478723, -0.10861127208514447], [-0.6750496712589404, -0.9729731256506629, -0.792547008514054, 0.09829252776297222, 0.17553846980131219, 0.16169881321960553, 0.08168078268193811, -0.15430252716536455, 0.07836244301747879], [0.9428661547223929, 0.061828784884551215, -1.1223194351415502, -0.013074158777108304, -0.48015798396465253, -0.15284499890142314, 0.003249406587673517, 0.3889297250355991, -0.2713878539890537], [-0.1753517891682148, -1.4249644096680718, 1.9087210344852157, -0.2930613903585754, -0.726321692589131, 0.08939874201970172, -0.0656828176026727, -0.1723240502213655, -0.05772821036005137], [-1.490217399562744, 0.46552917635513125, 0.6316247904151713, -0.45224657990576345, 0.43832315704579666, -0.6310328061845388, -0.13496862855752254, -0.0025357057004802555, 0.011530434711371187], [-1.4263375541504097, 0.29970215942096107, 1.0965123112115844, 0.17487687446908737, 0.29991620912079187, -0.016340024113910043, 0.3079286688003583, -0.14536634812917149, 0.18858697942233366], [0.21854279461766674, 0.26322441222236, 1.047234805074113, -0.49111300816143677, 0.16783236406287244, 0.37152138872863244, 0.1364485280479918, 0.03342876870256548, 0.11633200564825394], [-0.04451578391958231, 0.3332889519509195, -0.055474524270016895, 0.05278985368303185, -0.220984754932412, 0.38819841928302873, -0.05583321487792921, -0.13678972682282478, 0.02667545488221061], [0.35941774932039716, -0.8539581051925448, 0.885967184695803, 0.31541789904310696, -0.0966260425581278, 0.7187488496676157, 0.030798016572968434, -0.07651322382585689, -0.179092420127361], [-0.6159795854833837, -0.9926481509718692, 0.44878768660998053, 0.3648668070995696, 0.6942068531358895, 0.36005317748736876, 0.292625353559778, 0.30125698912034066, 0.1469347515277216], [1.2696596835831162, 0.9142282320160291, -0.4541383938966498, -0.43691776395772325, -0.11235685065628583, -0.036100830963053034, 0.28316636144643537, -0.08177197498783932, 0.14156994344021367], [0.4162496108488612, -0.4013107058643097, -0.05271511691037472, -0.02830019655731177, 0.5580077382820466, -0.09894731504487907, -0.24611456092537204, -0.12157707834659826, -0.244441557743729], [-0.10574133135199588, -2.1322824821944146, 0.2708116907010817, 0.15193420013414857, -0.04705330929517355, -0.5291529826713334, -0.1175314937746761, 0.47424346022858754, 0.6638255250756881], [-1.0657245720918946, -0.6272645944366747, -1.4368527457329872, -0.49687808959107505, 0.08644682936558253, -0.2508078730511919, -0.2865624576033387, 0.002322561481303009, -0.17555982420293406], [-1.4834237656348903, -0.8557050991917735, 0.9206472574498281, 0.41248136715480255, -0.12459536834981723, 0.6454988484934814, -0.2731685383967331, -0.20526285742986725, 0.024789888269864217], [1.2465729934910303, -0.0027115551129737224, 1.1934971954794886, -0.3787369430883995, 0.05880132545716421, 0.12522298534478268, -0.0965345544335563, 0.14766605730761445, -0.26895564030900015], [-0.4089773454617084, -1.7557581070377826, 0.22807085829011692, -0.08250469597637279, -0.4825895853785644, 0.32035298334368223, 0.006945682877621118, 0.43920104810612787, -0.255522332016385], [0.19973405055361224, -0.3775319665638507, 0.38418700162057956, 0.11845954798389302, 0.5045272898011116, -0.3810260574527768, -0.27586660319281814, -0.09689934123739437, -0.3287378782264085], [0.3085942383212327, -0.7815079713133952, -1.4393575381396815, -0.7545722236254615, -0.058524120849527746, -0.09848001836516804, -0.16268229254472164, 0.09034700337948276, -0.17076390647955053], [-0.3723270683158264, -0.17539483185077637, -0.2870762215979447, 0.502352610709535, 0.3568696452256066, -0.8344191982233636, 0.23072458524622336, -0.22436083136905255, 0.7387533634491209], [0.6643109132833454, 1.6239980618286014, -0.3526599714769406, -0.12517173926734662, 0.18675633504240086, -0.07111016527331154, -0.17138223899488775, -0.2465653102798197, -0.3296522325026464], [0.4169590285280992, 0.89495154556176, 0.805394744498379, -0.08444711031708525, -0.11827530415150506, 0.27338132827514167, -0.27092581971802515, 0.018311683643072285, -0.13399434301913646], [0.7159836826963285, -0.3409498408924565, 0.8327110781139511, 0.30117854394523597, -0.15951811365462829, 0.576143904258091, -0.2075518559007998, 0.18705977916911526, -0.06028821113943606], [1.5540391463912764, 0.7674144340083483, -0.560988902526357, 0.1990580737811212, -0.16640753943844047, 0.006581195282768733, -0.044779529545390565, -0.15975962831587157, 0.13234441684186504], [0.33875085606478605, 1.1936186088802583, 0.45261847097459595, 0.028509775994851813, 0.47525244097576014, -0.5598020569502817, -0.19867548393191814, -0.22702498860309717, -0.06852459485876591], [-0.6658163688001365, 1.4544247866984155, -1.20661256647853, 0.019284093792138905, 0.11095842162278333, 0.3500951882293566, 0.19770646436321376, -0.28446058278711267, -4.561136903492097e-05], [0.24929430106346814, 0.0056780227838315964, -1.1491084046090725, 0.5655585766138629, 0.16034484615784053, 0.0650505375492462, 0.2460174031104866, -0.10798157075128088, -0.24303674050959542], [0.8634918769657195, 0.3439388878837906, -1.121569020587735, -0.12427119389889812, 0.275678781134903, 0.08067213970065894, -0.25217902788511976, -0.06029708297745806, -0.11565488236669916], [0.33361773287512453, -0.38030436416088614, -1.875963137195203, -0.7278606730011062, 0.08422269322544719, 0.3815894052827421, 0.08890837365830347, 0.7476819877534484, 0.20607793274754962], [-0.7734726032916323, 0.2655799099178683, 0.726004447532527, -0.2000535447296053, -0.20495956152664663, -0.2020433422506824, 0.5080655079478673, 0.5414521112657797, -0.3309661883993521], [-0.04051818473431678, 0.0626712080623202, 0.556147838272949, 0.5439712865577907, 0.3819987817834609, -0.9735441186686495, -0.188125187798541, -0.38165562406802594, 0.3790786511375371], [-0.3635106655198392, 1.1142473085921523, 0.22676400929977436, -0.2239489083575742, 0.04110393194922994, 0.19583631064169704, 0.3194931546257146, -0.09148851364162379, -0.07317492683405569], [0.06958464914142908, 0.5231780475350413, -1.0091983495768484, 0.26921843544628904, -0.08104410591256928, -0.20582433575219664, -0.1508915253579836, -0.2522704542552833, -0.3480299210031703], [-0.7909043640548207, 1.4409510824847531, 0.4180987504835063, -0.29583044923154594, -0.18560031111797703, 0.1135803913136947, -0.05660889774572074, -0.3335537464498803, 0.6683108095136805], [-0.42496260128694147, 0.33798869923742253, -0.41925992506221127, 0.8990001934406308, 0.09684612356061781, -0.26819281720344845, 0.08874108780364301, -0.2051245470365568, 0.07683661356895224], [0.056413083049482816, -0.5979714933120146, 0.35732630571267654, -0.2854563843927852, 0.3800928843223295, 0.13531852026788632, -0.19667819046681087, -0.19214234004566352, -0.39516465605094114], [-1.5358726617933645, 1.2573005005234268, -0.4513791253657371, -0.5516008514997692, 0.2398019613484898, -0.1772116174606859, 0.06305257078911573, -0.20375437472958274, -0.0607753000374776], [-1.5389080698924702, -0.18727014551648707, -0.30586762745167023, 0.16321675598605967, -0.5435059150121168, -0.28897075786506926, 0.3301185216696067, 0.06111435080835009, -0.32876121565523586], [-0.051812243194712324, -1.0433759087463774, 0.48180992328406597, -0.06630225170159516, -0.6592729655496353, -0.19139738750692611, -0.03356071488355731, 0.1280032293194425, -0.13826368457989896], [2.9257162398858396, -1.1673373298256813, 0.42056582114560875, -0.265413534268579, -0.2010428410103348, -0.09585225982837892, 0.14807970520826272, -0.0219012021066542, -0.2496292459906061], [-0.449068833688179, 0.19966472184318113, -1.7827086876666698, 0.1744947087084829, 0.6295521578057928, -0.34510186553893896, 0.1844519140542061, 0.4458692327566544, -0.24200115767214844], [-1.1698602459121947, 0.44778919995009026, 0.0350268248667193, -0.04430598347001209, 0.262874399107874, 0.18233758787406637, -0.12634219200589974, -0.11639522887006715, 0.08727202804973172], [1.2201503964914975, -0.6341389985012651, 0.253268476924012, 0.3698117781604051, -0.34754822569281707, -0.07842895499126924, 0.9810600075012135, 0.02131689857139943, -0.0226288852270451], [2.316303751331696, -0.6905965035089612, -0.85202877876122, -0.015297607654408346, 0.33274129551903997, -0.17541000660372713, -0.03606122416549034, -0.13857238345203166, -0.34615879218817397], [-0.21267200460439764, -0.02069719811447844, 0.939681593662583, 0.19724756012210193, -0.26123491810621563, 0.7228428515376887, -0.29424326590588307, 0.07548687918056769, 0.224072763615361], [-0.07138915659282986, -0.6823996310581216, 0.2911137547384869, -0.3615281144092711, 0.1606444090342632, 0.0461388530335562, -0.23364564632042034, 0.0067499163395908415, -0.013590518636681658], [2.080819668041177, 1.202346252632345, -2.7773330872653874, -0.15727900139335246, 0.04825267128499973, -0.27266443493372633, -0.3257822273214914, -0.18319688621455807, 0.3214805942043452], [-0.3043582786475476, -0.7923629178716094, 0.7122279927081506, 0.14336934111598887, 0.2126367980057511, 0.22959435372613832, -0.047854835284980315, 0.004857527634421879, -0.005941630291127531], [-0.3311612191264292, 1.8164266981333321, 1.0289270614025294, 0.2091328122244864, 0.09760996993056037, 0.26991997141238633, 0.07975418650528082, -0.20789243460969936, -0.06230265875057797], [0.5812393802724055, 0.19405536489442024, 0.03310018980573841, 0.19082348488607187, -0.04176267067373706, 0.7457090571394369, -0.32702236708087423, 0.24806357419698405, -0.11501854232845704], [0.10926454447643073, 1.224186417456874, 0.622157947997673, -0.16702028235757127, 0.0919886817736402, 0.4613196510987485, -0.04024231352047103, -0.054428465496073566, -0.18317765307776412], [-0.48373524428145404, 1.2054225771683849, 0.27131968638369003, 0.016189478804069762, 0.2425222712786626, -0.23698938295219515, -0.2578588943344269, -0.14957033177922807, -0.39723932557720726], [-0.2491151233299712, -0.7145822869100213, -0.5057396798710443, 0.3966771854171764, -1.0366483280969516, 0.147993189764632, 0.119794449134592, -0.29406939030334983, 0.025301343285312517], [-0.7281313313517651, -2.5737468320784718, 1.116678433269161, -0.1123373443046285, -0.2267979733234278, 0.1934590765644861, -0.20385540240830619, 0.5691021982091877, 0.43079600342912644], [0.3033800191292837, -0.17837737671562456, 1.146544569411538, -0.055807017508461905, -0.2762034068097849, 0.7498090538424835, -0.10484017227284434, 0.0136824507480882, -0.032714346917408085], [0.1931629771291142, 0.3659405051212724, -2.462240695359627, 0.32955860484381266, -0.04703173294165197, -0.4617050393489909, 0.03449964308094728, 0.4359103129559433, 0.1489046855566666], [-0.3824161638407231, 0.5151783900545026, 1.7243433293602506, -0.4320953297128761, 0.20600095090580395, -0.07502560677860953, -0.17621678056653917, 0.02126222455641008, -0.21600683832152037], [1.3960456411488884, 1.3454917830073423, -1.1162506171392703, -0.3073823657290277, 0.47110984627889524, -0.06704782961227491, -0.05777965650934937, -0.06754707326244948, 0.08955343458151238], [-2.067674674640062, 0.5507457830426296, 0.10271188786341931, 0.7064434061357356, -0.3513909124836735, -0.2442396663321971, 0.556251019544921, -0.11907228188604115, -0.10629128104724979], [0.6431291185437626, -0.09625535902245118, 0.2996555472115063, 0.6382772949027051, 0.19865295621602624, -0.19926000601160965, -0.08884517687710959, -0.04535748011350182, 0.1964198161109784], [-1.4692108949097782, 0.4369649835875348, -0.38161784706457014, -0.3424716521237046, -0.36238423698241584, -0.48033148744724286, 0.054789019162979714, -0.012470188938222916, -0.013982977478800748], [0.117675526874669, 0.4475536275853683, -0.04574783562258978, -0.4405326878333102, 0.3379645854357636, 0.13349640066644244, -0.30951221912136945, -0.10579787514010529, 0.04609305692290972], [0.08921047692161863, 0.008064525921389143, 0.852589154548836, 0.01228958279299466, 0.2076201409191692, 0.19179907127573176, -0.04798369973436019, 0.04153016953589412, 0.37586338821415743], [0.24785141685291706, -0.4877262385654485, -0.5281971446935688, 0.6956514568016836, -0.5237256356600164, 0.14751635455423479, 0.8288949505043253, -0.07505934935755221, -0.03426899084809008], [1.3132209424894707, -0.07368791930944311, 1.0910138972737256, 0.41681732502251295, -0.05912701985430411, -0.3757495442964772, -0.202105267349862, -0.29854438216651796, 0.14121225527460077], [0.15490385989122515, -0.5034248786950767, -0.6932967411563664, 0.7630162327195569, 0.11650110913842857, 0.022968899357567844, -0.08685074474935245, -0.22950426525075615, 0.10241435881893805], [-0.07949541352498843, 0.259171697135073, 0.7041316846020373, -0.12329001977157047, 0.2359440411265629, -0.15016068449393766, 0.1742962080299388, -0.24550958808331313, 0.2194143901294228], [-1.269298533920138, -0.5318290223414871, -0.022832873103082497, -0.03401130577978534, 0.36153772190710487, 0.6753562436645549, -0.25196642650017953, -0.14070472975799786, 0.04127604691273764], [1.1905663746578226, -2.1721981003803785, 0.5244973510405272, -0.060025885767982366, -0.5058422783490253, -0.3303317902073216, -0.0023360618930091176, -0.1746808128322707, -0.02183613089353703], [-0.6457828617720379, 0.42151145561638126, -0.4298755698184977, -0.23724174439927498, -0.5328318352520759, -0.14423967807253865, -0.30957179280642994, 0.8331334649772281, 0.5223707849482446], [0.13016981935050465, 1.4744543994598645, 0.4374588624170039, -0.5495969352923796, -0.6546058169644293, -0.014686249318458812, -0.11014593447295315, 0.8089171011525653, 0.29274827688874766]]}}, {"name": "decay_ranked", "n_cells": 80, "n_genes": 3, "k": 7, "max_m": 0, "decay": "ranked", "k_per_harmonic": [7], "locations": [[6.4285101384599805, 24.963893122005747], [30.074917881167874, 1.4344504185972273], [7.396304228872797, 46.41055114801848], [3.5210288077098415, 6.488697469964899], [47.41642266458875, 31.094179639819142], [18.44965618648955, 25.569501090163133], [33.14214762583996, 13.765440788056466], [6.898403643347767, 39.401979725199595], [33.518029205124186, 25.61911567415802], [40.8368217984829, 27.453763443501316], [49.045681964865274, 10.225473066502245], [27.68651814326139, 24.181234846169385], [17.663742753022404, 29.579765197452172], [11.765061583379028, 40.11013418892417], [43.36667759212073, 6.437983561392552], [23.353660336913556, 13.857244626685217], [4.15584988676212, 44.797215412518376], [21.497434602391767, 7.384564998104704], [33.66811786379554, 10.110801389401908], [45.07155393440885, 10.857412870926408], [1.6537343688714345, 10.038447708060966], [17.287393687781975, 23.44540817112423], [45.30671694477803, 34.86805443681489], [16.966033037122262, 0.8438607548748922], [7.991184705249049, 49.821793776983526], [22.98579899465923, 34.551995815937964], [2.7334030700919, 1.7025139473518802], [42.294505322252874, 29.394097033343026], [15.435487160228101, 15.868831914066872], [4.461862720887439, 8.633480055428771], [1.229305373259315, 41.956242418639086], [23.315159860158257, 6.36014580292652], [36.9623437016846, 9.782641497266049], [3.0960117574226285, 29.919605366201907], [44.78788758706408, 1.34717056923514], [40.25679949458346, 9.508500836417038], [4.645071081827357, 0.8981017826278082], [14.648753350604299, 36.35558719909591], [24.658947550405845, 42.64599972272639], [10.860565176074516, 15.759137357171582], [12.907042592729418, 48.91505686571085], [47.050299732571744, 17.034308792825453], [21.800075179616552, 15.715981435192644], [37.32544586527053, 2.000655127659512], [3.371946654601304, 20.20187937342031], [12.2547025557032, 42.261249085061344], [37.09035482376451, 27.289699126147838], [33.07377571567503, 34.61395533424619], [39.052741169917105, 46.37512985578414], [7.4867586893866465, 31.306507887269074], [7.181072155667756, 22.156547064234843], [39.3142394311866, 44.73488968430727], [37.96140770622649, 1.7704102040796865], [17.970603821688837, 8.152841621076446], [49.94012438162009, 7.200767881501868], [12.215722142324148, 17.860985638976352], [3.044335145459398, 43.51924585216669], [31.818071093156213, 7.987411997920995], [24.91342788562751, 3.933487931747881], [30.548989367994782, 11.583161404872882], [1.931946643237925, 5.761875184695126], [27.763131131011054, 31.84903054790911], [16.240032356709854, 32.17262147805434], [17.603304995430634, 6.53295033951164], [15.76051409616836, 19.763411312690977], [45.63194173515474, 5.783018685987818], [4.308194528362675, 28.07510135358564], [48.1696394234913, 45.36275631283964], [35.012202889228746, 3.337537332282764], [40.32007121404446, 34.16873686910788], [7.1965119625464204, 23.247186301368565], [2.466132768976703, 40.093798264232476], [35.931710859414146, 40.23140499590264], [38.02078203100886, 13.362878848134867], [39.487025724675554, 12.45853229602032], [6.89477389681965, 19.51950168045739], [24.892017644551405, 14.291107381848533], [30.28914522769588, 30.12518646046972], [11.990882910715822, 31.12837439163244], [17.86264587770882, 36.73447993268751]], "features": [[-0.818083666605393, 0.38526930227745887, 0.4581670048370468], [0.5596122240618859, 0.5419022252820672, 0.20205463691158088], [0.17412924424976314, -1.5024999410944402, -0.1654011831842485], [-0.7476197010175331, 0.12608730560642875, -0.46754626006357575], [0.6185207511629426, 0.8190757096799433, 0.30869236500853114], [0.31616814431588613, 0.09294668494996648, -0.4477978929622047], [-0.16450126423277087, -0.49564606330714495, 0.3879871341457924], [0.014113411841972533, 0.5812911986088503, -1.3286483115981003], [0.8877789284048715, -0.7626962368507467, -0.7342821862702664], [-0.19744298486173803, -0.5633845877352657, 0.2911251954982905], [-0.5741647764650408, -1.0694775505189256, -0.8458028083790133], [1.3119833252675124, 0.044258328637274344, -1.1675302849446099], [0.008377403177420764, -1.555946414705409, 1.7895665579723081], [-1.5244781602909778, 0.4787527046455685, 0.5436256643142272], [-1.4500077538405294, 0.30027651841828845, 0.9971720401657596], [0.46757528576185525, 0.261016274083352, 0.9490966814610048], [0.16090454888866232, 0.3364252880770561, -0.12671154648393168], [0.6318057260154758, -0.9413841472373661, 0.7917632588742233], [-0.5053015337885142, -1.090653373060846, 0.3652489557719693], [1.6929555515236436, 0.9616782115907366, -0.5156498276026669], [0.698059671998619, -0.454209119721369, -0.12401945613631439], [0.08952849321707658, -2.317218216900625, 0.19161476616248335], [-1.029609188818006, -0.6973986134552436, -1.4743904107207184], [-1.5165582181462036, -0.9432644007214415, 0.8255972952985817], [1.6660413474635754, -0.025205103519519486, 1.091790933563312], [-0.26398064687868195, -1.9119728247927603, 0.14991661602143025], [0.4456482631425715, -0.42861655475758254, 0.30222423421292294], [0.5725562476093207, -0.8634075676336961, -1.4768340975643026], [-0.22125416534201214, -0.21106054027038276, -0.35266321385541605], [0.9872467528013661, 1.7255887894094382, -0.4166470179838092], [0.6988867031627518, 0.9409311129269357, 0.7131564204233815], [1.0474862871297028, -0.38924397003268574, 0.7398063595133139], [2.024481935859489, 0.8036655593800595, -0.6198936689169603], [0.6077124939345443, 1.2623802917054945, 0.3689862863896283], [-0.5634006961428569, 1.5430805830215768, -1.2497670465629258], [0.5034250466559266, -0.016175574467128036, -1.1936657251775022], [1.2194496835829487, 0.3478875937013457, -1.166798177099069], [0.6017283565618432, -0.43160042891134, -1.9027885021671262], [-0.6889051253999523, 0.2635514475016157, 0.6357028862761235], [0.16556490512827252, 0.04516501126799043, 0.46999000714326233], [-0.210976101965214, 1.176954603942294, 0.14864164821343293], [0.29392155247372515, 0.540798991545746, -1.0571688403044779], [-0.7092268763497593, 1.5285791140398155, 0.33530869036097966], [-0.2826160786151785, 0.3414835288114959, -0.48162223506155016], [0.27856628863229466, -0.6658710549900579, 0.27601881733916134], [-1.5777025523190094, 1.330919793665682, -0.5129578726969883], [-1.5812411969951867, -0.2238416945870532, -0.3709961947182103], [0.15239841860045156, -1.145250608848122, 0.3974655997902583], [3.623567688368005, -1.2786677207432902, 0.3377155756992855], [-0.31071885365042484, 0.19260829481441374, -1.811809037837263], [-1.1510093879783454, 0.4596595352026752, -0.038418019395222595], [1.6352381805909817, -0.7047973922713666, 0.17449952715639466], [2.913121452537828, -0.765561436417932, -0.9038334934759573], [-0.035130084895088134, -0.04456267883565894, 0.8441672801225347], [0.12957587279758478, -0.7567393122486353, 0.21142155200757654], [2.6385967525787044, 1.2717736740410226, -2.7821691176232233], [-0.14201691359430452, -0.8750905219509657, 0.6222625144051509], [-0.17326348062410027, 1.932695747995194, 0.9312355636189067], [0.8904028924592736, 0.18657106002655185, -0.04029765330752769], [0.34017992887452764, 1.295279791418775, 0.534389769872797], [-0.3511325658376627, 1.2750846584688966, 0.19211036905670717], [-0.0776150634716236, -0.7913768386620321, -0.5659922764661505], [-0.636046779726964, -2.79235715975389, 1.0168462003981633], [0.5664775694278109, -0.21427059157909795, 1.045983738409203], [0.43798777953339196, 0.37156747896960074, -2.4747635495786637], [-0.23301591961061885, 0.5321891257672531, 1.6096868317882371], [1.8402948816174964, 1.4258382457202734, -1.1616095185495017], [-2.197671367087202, 0.5704695747069322, 0.027615835350643075], [0.9625532543524465, -0.12588436360404337, 0.2197549635234998], [-1.499989013056637, 0.44800965515897445, -0.44489845287418683], [0.349985357704251, 0.4594059935421338, -0.1172221448808959], [0.31680112211393313, -0.013607030533302129, 0.759199501128509], [0.5017429484459656, -0.5472163690372069, -0.5879018811026014], [1.7437387779906113, -0.10159549531612938, 0.9918077625655023], [0.39338573028374196, -0.5641124904961297, -0.7489737969543596], [0.12012568949433819, 0.2566544207133919, 0.6143637194600546], [-1.2669334275073838, -0.5946832824261059, -0.0948662034142554], [1.6007494601475956, -2.360178570626117, 0.43911164810792375], [-0.540045858613423, 0.43137734284316537, -0.49197890628019864], [0.36455106356938455, 1.5646380406865834, 0.3541965034570923]], "harmonics": [[[0.23240985765162936, 0.547146453106029, -0.1835880226203177], [0.7005471617664393, 0.2949510712947089, 0.1283561304650708], [0.3121490153267798, 0.2468003878891843, 0.3043747877002705], [0.4496698733902989, 0.6475289924280562, -0.089140399737853], [-0.5741676791520982, -0.4092368544381036, -0.8398554314678884], [0.12281290532986955, -1.220082255327901, -0.042301836215406195], [0.5407635857811545, 0.30776738692232664, 0.3712429529476952], [-0.3757900434345619, 0.11629885144015883, 0.41910699811691143], [0.18628513538897662, -0.8412641847052214, -0.2486069888610515], [-0.38502674973916245, -0.23088670112650533, -0.6602199196087026], [0.2580357552398664, 0.19269284418893162, 0.18996753930999427], [0.4125136325454891, -0.9019609670906364, -0.28950736214986034], [-0.1496434771863753, -0.9402445412208332, 0.08625048349059844], [-0.22303464021461367, 0.516875370124423, -0.7959714812740405], [0.3625147017104185, 0.3798233017023189, -0.16558553673724666], [-0.22640061835296377, 0.07759234737855496, 0.3841904924509832], [0.2203745565502588, -0.32474201624073074, 0.2896157405283968], [0.42877395889597, -0.16698720962229352, 0.6920566866533896], [0.66252295476425, 0.8445460964570037, 0.27059816929047464], [-0.3819944579524753, -0.22409805957340395, -0.0858337573840733], [0.21316435943918313, 0.6777147003796247, -0.21667838792666944], [0.4716559203881079, -0.13033324752026174, -0.7112777618745437], [-0.22631478336823108, 0.06373810219137058, -0.3198272413096384], [0.5665737596878023, -0.24508322590678636, 0.6676612855804823], [-0.14068466657633696, 2.7425091889613346e-05, 0.05969096173500243], [-0.034471669758302424, -0.6478136943633719, 0.3299376608353517], [0.23776938159065672, 0.5524736343214827, -0.3485309688076165], [-0.5438995562208523, -0.06177108745843213, -0.17852272178565495], [0.7691984037217707, 0.44338568262574496, -1.1072736673994679], [0.07893124309011917, 0.14858375381687125, -0.13921888274855826], [0.14428785948435172, -0.18940233755192867, 0.2076792398193673], [0.4397010473378404, -0.23994989894719823, 0.5891338279750749], [0.31228606529684055, -0.19481291653034136, -0.1213142105771881], [0.19381319752595377, 0.608476186705497, -0.6909378533809453], [0.1914135794369744, 0.07727165967839095, 0.37334081669243924], [0.6709799351080863, 0.16145855870767548, 0.024610090292732156], [0.02914559980504117, 0.343121172896009, 0.04753060833618788], [-0.549333888994349, -0.03391938114199738, 0.3805083487010243], [0.06713783464368882, -0.4560887377221205, -0.1441594349698088], [0.6652615805991249, 0.43771831748385254, -1.0548621554283593], [-0.0037596145455452796, -0.046288572432374074, 0.2160772198457629], [0.6400550593696077, -0.1444593637522639, -0.40909200247892824], [-0.09621830986379896, -0.21409046390923092, -0.045085072912220504], [1.034257745480335, 0.14398370286964673, -0.30324981668211715], [-0.031143174086173404, 0.48310132578204873, 0.03534869396869236], [-0.26617065082658947, 0.18159006843852463, -0.5145542284299244], [0.39189012916785915, -0.8322901192595922, -0.3634089095765291], [0.20244679478386013, -0.9819027451183787, -0.2530342760823195], [-0.1591792611060377, -0.267905339425336, -0.23779482510859495], [0.3394289791852683, 0.7988514423992968, -0.41350576777847153], [0.3198911113681401, 0.36371310777527255, -0.004777241860524038], [0.37689215255497693, -0.422625911160951, -0.19379031904844335], [-0.014042739640839033, 0.4628496756082481, -0.24143319284902004], [0.34781255242412273, -0.46178617198446187, 0.7826672450393306], [-0.10425559118308385, 0.21031801196277264, -0.01906713468016615], [0.009201022471543795, 0.06378127580917545, -0.33912026172431486], [0.3346563211002559, 0.1960655755360231, 0.17748160688771705], [0.49402380788521033, 0.1336946872156286, 0.18248535068683996], [0.5494852023123298, -0.11128922495989467, 0.7183935851940969], [-0.10847536373668377, -0.026416414256830247, 0.376729021927863], [0.33453157311209797, 0.31161581408878714, -0.2551779566158593], [0.6085753408120993, -1.4523861763456396, 0.08966063967820839], [0.05382271492767959, -0.35085696107929837, 0.03327049833052584], [0.22763747671469245, -0.4090154242580581, 0.7007045886261286], [0.47004239377103907, -0.25909178740970584, -0.5096338200071587], [-0.20741756874254202, 0.3129179920665926, -0.22223491044980193], [-0.14306503111852228, 0.547034533880383, -0.1502263299028451], [1.0839026838352732, -0.6360024868492472, -0.2956219213047653], [0.858154388235807, 0.28764090319266017, -0.24965199823192888], [-0.1814437710176291, -0.6878475970669367, -0.6997827875373301], [-0.11684869568715851, 0.40619388970733944, 0.005936789540874396], [0.0657497500384606, 0.13310839104837913, 0.07251157354481702], [0.8683661280512487, -0.7555890325587358, 0.05861078096306076], [0.7097288748136322, -0.04059590112280494, -0.49716171368112466], [1.0983370497305547, 0.1335434257932847, -0.1152235802405099], [-0.11983362494892005, 0.1892851523996372, -0.08727151404603688], [0.19239751676891742, 0.4808809711432279, 0.6539802802964879], [0.15776580882522037, -0.7288700920586145, -0.3927730619671885], [-0.023214801143416442, -0.7702002631679061, -0.28188935667393733], [-0.3434677867602049, -1.1191031142616605, -0.054623949629284796]]], "banksy": {"0.2": [[-0.8842804481270848, 0.3786712370678177, 0.5440291961160418, 0.03851039265208984, 0.5464916543694892, -0.1261958690825657], [0.297491006008758, 0.5242030916226729, 0.2815126154320329, 0.5906021361779897, 0.31879305813960784, 0.22278042242215806], [-0.03317179460143021, -1.3753058559309848, -0.09513161391681413, 0.13254974862993302, 0.2753194507317213, 0.4196949586621333], [-0.823837280922303, 0.1378582845976939, -0.4048319735493924, 0.29473321410493775, 0.6371236204485384, -0.02053599102760793], [0.34802205295809463, 0.7817324184339162, 0.390816871133067, -0.9127165116528603, -0.3169941677000532, -0.8603714075878488], [0.0886675159547601, 0.10706644407836709, -0.38458978904445185, -0.09074137164996184, -1.0490787848568888, 0.03186296575937069], [-0.32364509218115756, -0.4398108827839823, 0.47209444405410467, 0.40216341899580943, 0.33036447176458433, 0.49450131132803415], [-0.17043150788817124, 0.560800444384134, -1.2874662954288223, -0.6787623836285314, 0.15749407089381026, 0.5480474887907527], [0.5789885745342327, -0.687934369656872, -0.678237759691437, -0.015886208750541753, -0.7070568878348852, -0.19893349692953213], [-0.3519021156310685, -0.502748564694852, 0.37281042611254833, -0.6896555750988974, -0.15596790601847543, -0.6594106454413893], [-0.6750496712589404, -0.9729731256506629, -0.792547008514054, 0.06873196729386671, 0.2264675976267669, 0.291705968102116], [0.9428661547223929, 0.061828784884551215, -1.1223194351415502, 0.2509134765822721, -0.7618579394860587, -0.24468931716309916], [-0.1753517891682148, -1.4249644096680718, 1.9087210344852157, -0.41205932246479937, -0.7964228709511009, 0.17567624564171913], [-1.490217399562744, 0.46552917635513125, 0.6316247904151713, -0.4986122521277525, 0.5191609274871598, -0.8112778180983383], [-1.4263375541504097, 0.29970215942096107, 1.0965123112115844, 0.19194787683934886, 0.3954212960713003, -0.10605623607710081], [0.21854279461766674, 0.26322441222236, 1.047234805074113, -0.50258187540438, 0.12254729043933246, 0.5089859050454599], [-0.04451578391958231, 0.3332889519509195, -0.055474524270016895, 0.024316714193845727, -0.2407066643047425, 0.4031838059534178], [0.35941774932039716, -0.8539581051925448, 0.885967184695803, 0.27008988454256455, -0.09827523769595357, 0.8534001268533612], [-0.6159795854833837, -0.9926481509718692, 0.44878768660998053, 0.5457587738663208, 0.8150036343428064, 0.38190858274953776], [1.2696596835831162, 0.9142282320160291, -0.4541383938966498, -0.6860794805542489, -0.14983867343361595, -0.016836803931004063], [0.4162496108488612, -0.4013107058643097, -0.05271511691037472, 0.015813460427846083, 0.6643772651323239, -0.1632145240402889], [-0.10574133135199588, -2.1322824821944146, 0.2708116907010817, 0.3206621774957421, -0.06518162726997041, -0.7165297684316159], [-1.0657245720918946, -0.6272645944366747, -1.4368527457329872, -0.5024806470127093, 0.11003876566663627, -0.2786085904798021], [-1.4834237656348903, -0.8557050991917735, 0.9206472574498281, 0.4326023175573588, -0.16878546334484684, 0.8261086501195011], [1.2465729934910303, -0.0027115551129737224, 1.1934971954794886, -0.40149386372835705, 0.05251657142098452, 0.1459637368008503], [-0.4089773454617084, -1.7557581070377826, 0.22807085829011692, -0.276232924078911, -0.5323970476171282, 0.4482925027374167], [0.19973405055361224, -0.3775319665638507, 0.38418700162057956, 0.04483107867723245, 0.5513013843332538, -0.31071985230513477], [0.3085942383212327, -0.7815079713133952, -1.4393575381396815, -0.8770201879130425, -0.0032791947652912505, -0.12052924612088278], [-0.3723270683158264, -0.17539483185077637, -0.2870762215979447, 0.6715651005330842, 0.45280959876480914, -1.1595359321769427], [0.6643109132833454, 1.6239980618286014, -0.3526599714769406, -0.14249264889664087, 0.18664300652378935, -0.0765594911073625], [0.4169590285280992, 0.89495154556176, 0.805394744498379, -0.06541515906857967, -0.11851309109054749, 0.3115202954388153], [0.7159836826963285, -0.3409498408924565, 0.8327110781139511, 0.28297660657156665, -0.16415075776740018, 0.738258883854037], [1.5540391463912764, 0.7674144340083483, -0.560988902526357, 0.13271137675966324, -0.12339811804594661, -0.056529283670641486], [0.33875085606478605, 1.1936186088802583, 0.45261847097459595, -0.007008084930792214, 0.6018641760526939, -0.6937752280261144], [-0.6658163688001365, 1.4544247866984155, -1.20661256647853, -0.00983804384006128, 0.12225775246829158, 0.49684822087091807], [0.24929430106346814, 0.0056780227838315964, -1.1491084046090725, 0.5557324054952322, 0.19826722810673247, 0.10671827476032177], [0.8634918769657195, 0.3439388878837906, -1.121569020587735, -0.20120671069479287, 0.3622841975732106, 0.13235977919968464], [0.33361773287512453, -0.38030436416088614, -1.875963137195203, -0.8834290987805343, 0.02186715956249625, 0.504866639279654], [-0.7734726032916323, 0.2655799099178683, 0.726004447532527, -0.15640105434536788, -0.35929513284016124, -0.0820865560486486], [-0.04051818473431678, 0.0626712080623202, 0.556147838272949, 0.5489885372258122, 0.447692728353215, -1.1009024399350598], [-0.3635106655198392, 1.1142473085921523, 0.22676400929977436, -0.2400130544794646, 0.01069943922959669, 0.3209152332722552], [0.06958464914142908, 0.5231780475350413, -1.0091983495768484, 0.519261548730117, -0.07793561512298136, -0.3784703285723464], [-0.7909043640548207, 1.4409510824847531, 0.4180987504835063, -0.34905303453169684, -0.14080315712874852, 0.028749319899279042], [-0.42496260128694147, 0.33798869923742253, -0.41925992506221127, 0.9841594459164723, 0.18248977764328358, -0.26006319345282886], [0.056413083049482816, -0.5979714933120146, 0.35732630571267654, -0.27230750526953224, 0.4886674964396482, 0.1187317010409861], [-1.5358726617933645, 1.2573005005234268, -0.4513791253657371, -0.5494841546618793, 0.2164432806291058, -0.4964523972926329], [-1.5389080698924702, -0.18727014551648707, -0.30586762745167023, 0.22659141158705096, -0.6989545106629922, -0.32736401294545564], [-0.051812243194712324, -1.0433759087463774, 0.48180992328406597, 0.0031738375973235176, -0.834034640368932, -0.20388636512924935], [2.9257162398858396, -1.1673373298256813, 0.42056582114560875, -0.42330522729617653, -0.1893907701266362, -0.18683777796139597], [-0.449068833688179, 0.19966472184318113, -1.7827086876666698, 0.16472202517694962, 0.7737474919447109, -0.38340806960891344], [-1.1698602459121947, 0.44778919995009026, 0.0350268248667193, 0.1416802905979606, 0.38087595223576554, 0.0738422548361604], [1.2201503964914975, -0.6341389985012651, 0.253268476924012, 0.20890373964810183, -0.32908268969731747, -0.13760932093638067], [2.316303751331696, -0.6905965035089612, -0.85202877876122, -0.2521403265700548, 0.47038297321486144, -0.19090807089244], [-0.21267200460439764, -0.02069719811447844, 0.939681593662583, 0.17460908507525902, -0.3644391516335654, 0.9547674271343264], [-0.07138915659282986, -0.6823996310581216, 0.2911137547384869, -0.3585316994827042, 0.24238075960299305, 0.057855951669793196], [2.080819668041177, 1.202346252632345, -2.7773330872653874, -0.22472809294130836, 0.1100777456515104, -0.3001919625342087], [-0.3043582786475476, -0.7923629178716094, 0.7122279927081506, 0.15909345189247304, 0.2295127215607484, 0.27773778068905625], [-0.3311612191264292, 1.8164266981333321, 1.0289270614025294, 0.3470414595967854, 0.17320017684179087, 0.28333553893323693], [0.5812393802724055, 0.19405536489442024, 0.03310018980573841, 0.4124491459283505, -0.04798742976951829, 0.8828635839868447], [0.10926454447643073, 1.224186417456874, 0.622157947997673, -0.36350823428546875, 0.02864133209111928, 0.5006386535051577], [-0.48373524428145404, 1.2054225771683849, 0.27131968638369003, 0.15894633194779426, 0.333839085205966, -0.20628453055522805], [-0.2491151233299712, -0.7145822869100213, -0.5057396798710443, 0.4821363451811661, -1.258818060550723, 0.17949123511349882], [-0.7281313313517651, -2.5737468320784718, 1.116678433269161, -0.17210407052171764, -0.264284956015141, 0.11640679448429829], [0.3033800191292837, -0.17837737671562456, 1.146544569411538, 0.03288214621865225, -0.3167942459536787, 0.8630746558672668], [0.1931629771291142, 0.3659405051212724, -2.462240695359627, 0.318759285512102, -0.18143331504817864, -0.4909478675007399], [-0.3824161638407231, 0.5151783900545026, 1.7243433293602506, -0.4801944585829978, 0.3350147772248214, -0.16943068358232866], [1.3960456411488884, 1.3454917830073423, -1.1162506171392703, -0.40430111621341, 0.5463906063233762, -0.08887367635123772], [-2.067674674640062, 0.5507457830426296, 0.10271188786341931, 1.042707569154461, -0.5217331117772639, -0.25152976009802697], [0.6431291185437626, -0.09625535902245118, 0.2996555472115063, 0.7764742033876019, 0.3121929570470103, -0.20010256354363418], [-1.4692108949097782, 0.4369649835875348, -0.38161784706457014, -0.4495625923636389, -0.5685422909666883, -0.7036701797024605], [0.117675526874669, 0.4475536275853683, -0.04574783562258978, -0.3733832162512831, 0.4192303992649187, 0.08582819176924253], [0.08921047692161863, 0.008064525921389143, 0.852589154548836, -0.15803807417507573, 0.17267083005796457, 0.16030633473050626], [0.24785141685291706, -0.4877262385654485, -0.5281971446935688, 0.7885172881612037, -0.6297037192898273, 0.14475532344795208], [1.3132209424894707, -0.07368791930944311, 1.0910138972737256, 0.6014304720534319, 0.0158391577156266, -0.47699514753512295], [0.15490385989122515, -0.5034248786950767, -0.6932967411563664, 1.0597305540005102, 0.17306360807005494, -0.04971561023968502], [-0.07949541352498843, 0.259171697135073, 0.7041316846020373, -0.37690345440778616, 0.2233909091036323, -0.018445242438395862], [-1.269298533920138, -0.5318290223414871, -0.022832873103082497, -0.008677649929262371, 0.4866628140748844, 0.8108035179641373], [1.1905663746578226, -2.1721981003803785, 0.5244973510405272, -0.04952011185625792, -0.6055801005267407, -0.36021410134466614], [-0.6457828617720379, 0.42151145561638126, -0.4298755698184977, -0.2629572800197693, -0.6428957003443742, -0.23616694777949168], [0.13016981935050465, 1.4744543994598645, 0.4374588624170039, -0.6406435435250283, -0.9579081674405706, 0.01807804496459339]]}}]} \ No newline at end of file diff --git a/tools/gen_banksy_fixtures.py b/tools/gen_banksy_fixtures.py new file mode 100644 index 0000000..bed3798 --- /dev/null +++ b/tools/gen_banksy_fixtures.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +"""Reference fixtures for the BANKSY feature augmentation, from `banksy-py` itself. + +Calls the reference implementation's own functions rather than reimplementing them, so the +Rust side is checked against what BANKSY actually computes and not against a reading of it. + + uv venv && uv pip install banksy-py + uv run tools/gen_banksy_fixtures.py tests/fixtures/banksy_reference.json + +Fixtures are committed, so the test suite needs no Python. +""" + +import json +import sys + +import numpy as np +import anndata +from banksy.embed_banksy import create_nbr_matrix +from banksy.main import concatenate_all, generate_spatial_weights_fixed_nbrs + +DECAYS = ["uniform", "reciprocal", "reciprocal_squared", "scaled_gaussian", "ranked"] + + +def case(name, n_cells, n_genes, k, max_m, lambdas, decay, seed): + """One synthetic dataset put through the reference, with every intermediate captured.""" + rng = np.random.default_rng(seed) + + if name.startswith("grid"): + side = int(np.sqrt(n_cells)) + xs, ys = np.meshgrid(np.arange(side), np.arange(side)) + locations = np.column_stack([xs.ravel(), ys.ravel()]).astype(float) + n_cells = locations.shape[0] + else: + locations = rng.uniform(0, 50, size=(n_cells, 2)) + + features = rng.normal(size=(n_cells, n_genes)) + + # Go through the reference's own matrix builder rather than a raw matmul: the AGF + # centring lives in create_nbr_matrix, not in the weight construction, so a matmul + # against the weights silently omits it. + weights = {} + for m in range(max_m + 1): + w, _dist, _theta = generate_spatial_weights_fixed_nbrs( + locations, + m=m, + num_neighbours=k, + decay_type=decay, + verbose=False, + ) + weights[m] = w + + adata = anndata.AnnData(features.copy()) + banksy_dict = {decay: {"weights": weights}} + nbr_matrices = create_nbr_matrix(adata, banksy_dict, decay, max_m, verbose=False) + harmonics = [nbr_matrices[m] for m in range(max_m + 1)] + + # Python derives the harmonic-m neighbourhood as k*(m+1); record what it actually used + # so the Rust side can be given the same k explicitly. + k_per_harmonic = [int(np.diff(weights[m].indptr).max()) for m in range(max_m + 1)] + + out = { + "name": name, + "n_cells": int(n_cells), + "n_genes": int(n_genes), + "k": int(k), + "max_m": int(max_m), + "decay": decay, + "k_per_harmonic": k_per_harmonic, + "locations": locations.tolist(), + "features": features.tolist(), + # As create_nbr_matrix returns them: H_0 is real and signed, and the m >= 1 + # harmonics have already had their magnitude taken inside it. Applying abs() here + # would flip the sign of every negative H_0 entry. + "harmonics": [np.asarray(h).tolist() for h in harmonics], + "banksy": {}, + } + + for lam in lambdas: + mat_list = [features] + harmonics + combined = concatenate_all(mat_list, lam, adata=None) + out["banksy"][str(lam)] = np.asarray(combined).tolist() + + return out + + +def main(): + cases = [ + case("uniform_small", 60, 4, 6, 1, [0.0, 0.2, 0.5, 1.0], "scaled_gaussian", 1), + case("uniform_mid", 200, 8, 12, 1, [0.2, 0.8], "scaled_gaussian", 2), + case("grid_regular", 100, 5, 8, 1, [0.2], "scaled_gaussian", 3), + case("mean_only", 120, 6, 10, 0, [0.2, 0.5], "scaled_gaussian", 4), + case("harmonic_two", 120, 4, 10, 2, [0.2], "scaled_gaussian", 5), + ] + # Every decay type, so none of the kernels can drift unnoticed. + # + # `ranked` is capped at max_m = 0: the reference crashes for m > 0, because it builds a + # weight profile of length `num_neighbours` while the row holds `num_neighbours * (m+1)` + # entries. An upstream bug, not a usage error -- so there is no reference behaviour to + # match above m = 0. + for decay in DECAYS: + max_m = 0 if decay == "ranked" else 1 + cases.append(case(f"decay_{decay}", 80, 3, 7, max_m, [0.2], decay, 11)) + + # To a file, not stdout: the reference print()s unconditionally, so stdout is not clean. + out = sys.argv[1] if len(sys.argv) > 1 else "banksy_reference.json" + with open(out, "w") as fh: + json.dump({"cases": cases}, fh) + print(f"\nwrote {out}", file=sys.stderr) + for c in cases: + print( + f" {c['name']:22} n={c['n_cells']:4} genes={c['n_genes']} " + f"k={c['k']} m={c['max_m']} decay={c['decay']}", + file=sys.stderr, + ) + + +if __name__ == "__main__": + main() From f44a5292cc9a19019434048d564ffce6edb9f045 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 2 Aug 2026 12:15:23 +0200 Subject: [PATCH 09/20] feat(spatial): graph fusion and per-sample construction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes the spatial layer. fuse() blends an expression graph with a spatial one over the same cells, alpha*a + (1-alpha)*b, as the union of both edge sets. Normalisation::TotalWeight scales each to unit total weight first, and is the default because without it the graph with heavier weights wins at every alpha and the parameter stops meaning anything — the same failure the BANKSY blocks avoid by z-scoring. There is a test that fusing a graph with a 1000x-scaled copy of itself gives back uniform weights when normalised, and is dominated when not. per_sample() runs a builder separately within each slice. Building globally and deleting cross-sample edges afterwards is not equivalent for kNN: a cell at a section's edge loses neighbours instead of taking k from its own section. There is a test asserting both halves of that — every cell keeps full degree under per_sample, and the filter-afterwards approach demonstrably starves some. It matters because sections are routinely stored overlapping in one coordinate frame, so cells from different slices can sit arbitrarily close. 8 tests including endpoint recovery, edge-set union, symmetry, sample labels being arbitrary, and single-cell samples. --- src/spatial/combine.rs | 417 +++++++++++++++++++++++++++++++++++++++++ src/spatial/mod.rs | 2 + 2 files changed, 419 insertions(+) create mode 100644 src/spatial/combine.rs diff --git a/src/spatial/combine.rs b/src/spatial/combine.rs new file mode 100644 index 0000000..a4ee9c7 --- /dev/null +++ b/src/spatial/combine.rs @@ -0,0 +1,417 @@ +//! Combining graphs, and building them per sample. +//! +//! Two operations that both exist because real experiments are not one clean tissue section: +//! you usually have an expression graph *and* a spatial graph over the same cells, and you +//! usually have several slices rather than one. + +use crate::error::{ClusteringError, Result}; +use crate::network::CSRNetwork; + +/// How to put two graphs on comparable footing before mixing them. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum Normalization { + /// Mix the weights as they are. + /// + /// Almost never what you want across an expression and a spatial graph: their weights + /// live on unrelated scales, so whichever is larger dominates at every `alpha` and the + /// parameter stops meaning anything. + None, + /// Scale each graph so its total edge weight is 1, so `alpha` divides a fixed budget. + #[default] + TotalWeight, +} + +/// Blends two graphs over the same nodes: `alpha · a + (1 − alpha) · b`. +/// +/// An edge present in only one contributes only its own side, so the result is the union of +/// the two edge sets. Both graphs must cover the same nodes. +/// +/// With [`Normalization::TotalWeight`] each graph is first scaled to unit total weight, which +/// is what makes `alpha` behave like a proportion rather than an arbitrary knob. It is the +/// same problem the BANKSY blocks solve by z-scoring, and the same fix. +/// +/// # Errors +/// +/// If the graphs have different node counts, or `alpha` is outside `[0, 1]`. +pub fn fuse( + a: &CSRNetwork, + b: &CSRNetwork, + alpha: f64, + normalization: Normalization, +) -> Result { + if !(0.0..=1.0).contains(&alpha) || !alpha.is_finite() { + return Err(ClusteringError::InvalidConfig(format!( + "alpha must be in [0, 1], got {alpha}" + ))); + } + if a.node_count() != b.node_count() { + return Err(ClusteringError::InvalidConfig(format!( + "graphs cover different node sets: {} vs {} nodes", + a.node_count(), + b.node_count() + ))); + } + let n = a.node_count(); + if n == 0 { + return CSRNetwork::from_csr_parts(vec![0], Vec::new(), Vec::new(), None); + } + + let (sa, sb) = match normalization { + Normalization::None => (1.0, 1.0), + Normalization::TotalWeight => ( + scale_to_unit(a.total_weight()), + scale_to_unit(b.total_weight()), + ), + }; + let (wa, wb) = (alpha * sa, (1.0 - alpha) * sb); + + // Merge each node's two neighbour lists. Both are sorted ascending, so this is a linear + // two-pointer walk and the output stays sorted. + let mut node_ptrs = Vec::with_capacity(n + 1); + node_ptrs.push(0usize); + let mut neighbors: Vec = Vec::new(); + let mut weights: Vec = Vec::new(); + + let (mut ra, mut rb) = (Vec::new(), Vec::new()); + for v in 0..n { + ra.clear(); + rb.clear(); + ra.extend(a.neighbors(v)); + rb.extend(b.neighbors(v)); + + let (mut i, mut j) = (0usize, 0usize); + while i < ra.len() || j < rb.len() { + let take_a = j >= rb.len() || (i < ra.len() && ra[i].0 <= rb[j].0); + let take_b = i >= ra.len() || (j < rb.len() && rb[j].0 <= ra[i].0); + let u = if take_a { ra[i].0 } else { rb[j].0 }; + + let mut w = 0.0; + if take_a { + w += wa * ra[i].1; + i += 1; + } + if take_b { + w += wb * rb[j].1; + j += 1; + } + if w > 0.0 { + neighbors.push(u as u32); + weights.push(w as f32); + } + } + node_ptrs.push(neighbors.len()); + } + + CSRNetwork::from_csr_parts(node_ptrs, neighbors, weights, None) +} + +/// Reciprocal of a total weight, or 1.0 when there is nothing to scale. +fn scale_to_unit(total: f64) -> f64 { + if total > 0.0 && total.is_finite() { + 1.0 / total + } else { + 1.0 + } +} + +/// Runs a graph builder separately within each sample and reassembles one graph. +/// +/// Spatial neighbours are only meaningful within a slice: two cells on different sections are +/// not adjacent however close their stored coordinates happen to be, and sections are often +/// laid out overlapping in the same coordinate space. Building globally and deleting +/// cross-sample edges afterwards is **not** equivalent for k-nearest builders — a cell at a +/// section's edge would lose neighbours rather than take k from its own section. So the +/// builder runs per sample. +/// +/// `samples` labels each point. Node indices in the result are the caller's original ones. +/// +/// # Errors +/// +/// If `samples` does not match the point count, or the builder fails on a sample. +pub fn per_sample(points: &[[f64; 2]], samples: &[u32], build: F) -> Result +where + F: Fn(&[[f64; 2]]) -> Result, +{ + if samples.len() != points.len() { + return Err(ClusteringError::CoordinateLengthMismatch { + got: samples.len(), + expected: points.len(), + }); + } + let n = points.len(); + if n == 0 { + return CSRNetwork::from_csr_parts(vec![0], Vec::new(), Vec::new(), None); + } + + // Group point indices by sample, keeping each group in ascending original order so the + // result never depends on how the samples were labelled. + let mut order: Vec = (0..n as u32).collect(); + order.sort_by_key(|&v| (samples[v as usize], v)); + + let mut rows: Vec> = vec![Vec::new(); n]; + let mut start = 0usize; + while start < n { + let sample = samples[order[start] as usize]; + let mut end = start; + while end < n && samples[order[end] as usize] == sample { + end += 1; + } + + let members = &order[start..end]; + let subset: Vec<[f64; 2]> = members.iter().map(|&v| points[v as usize]).collect(); + let sub = build(&subset)?; + if sub.node_count() != subset.len() { + return Err(ClusteringError::InvalidConfig(format!( + "builder returned {} nodes for a sample of {}", + sub.node_count(), + subset.len() + ))); + } + + for local in 0..sub.node_count() { + let global = members[local] as usize; + for (u, w) in sub.neighbors(local) { + rows[global].push((members[u], w as f32)); + } + } + start = end; + } + + let mut node_ptrs = Vec::with_capacity(n + 1); + node_ptrs.push(0usize); + let mut neighbors = Vec::new(); + let mut weights = Vec::new(); + for row in &mut rows { + row.sort_unstable_by_key(|&(u, _)| u); + for &(u, w) in row.iter() { + neighbors.push(u); + weights.push(w); + } + node_ptrs.push(neighbors.len()); + } + + CSRNetwork::from_csr_parts(node_ptrs, neighbors, weights, None) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::spatial::{ + HullPruning, SpatialWeight, Symmetry, delaunay_graph, knn_graph, radius_graph, + }; + use rand::{Rng, SeedableRng}; + use std::collections::HashSet; + + fn edge_set(g: &CSRNetwork) -> HashSet<(usize, usize)> { + let mut out = HashSet::new(); + for v in 0..g.node_count() { + for (u, _) in g.neighbors(v) { + out.insert((v.min(u), v.max(u))); + } + } + out + } + + fn two_slices(seed: u64) -> (Vec<[f64; 2]>, Vec) { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + let mut pts = Vec::new(); + let mut samples = Vec::new(); + // Deliberately overlapping coordinates: two sections stored in the same frame. + for s in 0..2u32 { + for _ in 0..300 { + pts.push([rng.random::() * 50.0, rng.random::() * 50.0]); + samples.push(s); + } + } + (pts, samples) + } + + #[test] + fn fusion_endpoints_recover_each_input() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); + let pts: Vec<[f64; 2]> = (0..200) + .map(|_| [rng.random::() * 30.0, rng.random::() * 30.0]) + .collect(); + let a = radius_graph(&pts, 4.0, SpatialWeight::Uniform, None).unwrap(); + let b = knn_graph(&pts, 5, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + + let at_one = fuse(&a, &b, 1.0, Normalization::TotalWeight).unwrap(); + assert_eq!(edge_set(&at_one), edge_set(&a)); + let at_zero = fuse(&a, &b, 0.0, Normalization::TotalWeight).unwrap(); + assert_eq!(edge_set(&at_zero), edge_set(&b)); + } + + #[test] + fn fusion_is_the_union_of_both_edge_sets() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(2); + let pts: Vec<[f64; 2]> = (0..150) + .map(|_| [rng.random::() * 30.0, rng.random::() * 30.0]) + .collect(); + let a = radius_graph(&pts, 3.0, SpatialWeight::Uniform, None).unwrap(); + let b = delaunay_graph(&pts, HullPruning::default(), SpatialWeight::Uniform).unwrap(); + + let f = fuse(&a, &b, 0.5, Normalization::TotalWeight).unwrap(); + let union: HashSet<_> = edge_set(&a).union(&edge_set(&b)).copied().collect(); + assert_eq!(edge_set(&f), union); + f.validate_symmetry().unwrap(); + } + + /// The point of normalising: without it, the graph with heavier weights wins whatever + /// alpha says. + #[test] + fn normalisation_stops_one_graph_dominating() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(3); + let pts: Vec<[f64; 2]> = (0..200) + .map(|_| [rng.random::() * 30.0, rng.random::() * 30.0]) + .collect(); + let light = radius_graph(&pts, 3.0, SpatialWeight::Uniform, None).unwrap(); + // Same shape, weights a thousand times larger. + let heavy = { + let (ptrs, nbrs, w) = light.to_csr_parts(); + CSRNetwork::from_csr_parts(ptrs, nbrs, w.iter().map(|x| x * 1000.0).collect(), None) + .unwrap() + }; + + // Normalised, an even blend of a graph with itself is that graph, whatever the scale. + let fused = fuse(&light, &heavy, 0.5, Normalization::TotalWeight).unwrap(); + let first = fused.neighbors(0).next().unwrap().1; + for v in 0..fused.node_count() { + for (_, w) in fused.neighbors(v) { + assert!( + (w / first - 1.0).abs() < 1e-4, + "normalised weights should be uniform here, saw {w} vs {first}" + ); + } + } + + // Unnormalised, the heavy graph contributes ~1000x as much. + let raw = fuse(&light, &heavy, 0.5, Normalization::None).unwrap(); + let w = raw.neighbors(0).next().unwrap().1; + assert!(w > 400.0, "expected the heavy graph to dominate, got {w}"); + } + + #[test] + fn fusion_rejects_mismatched_inputs() { + let a = radius_graph(&[[0.0, 0.0], [1.0, 0.0]], 2.0, SpatialWeight::Uniform, None).unwrap(); + let b = radius_graph( + &[[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]], + 2.0, + SpatialWeight::Uniform, + None, + ) + .unwrap(); + assert!(fuse(&a, &b, 0.5, Normalization::TotalWeight).is_err()); + assert!(fuse(&a, &a, 1.5, Normalization::TotalWeight).is_err()); + assert!(fuse(&a, &a, f64::NAN, Normalization::TotalWeight).is_err()); + } + + /// Cells in different sections must never be joined, even where their coordinates + /// coincide — which they do here by construction. + #[test] + fn per_sample_never_joins_two_slices() { + let (pts, samples) = two_slices(5); + + for name in ["knn", "radius", "delaunay"] { + let g = per_sample(&pts, &samples, |sub| match name { + "knn" => knn_graph(sub, 6, Symmetry::Union, SpatialWeight::Uniform), + "radius" => radius_graph(sub, 4.0, SpatialWeight::Uniform, None), + _ => delaunay_graph(sub, HullPruning::default(), SpatialWeight::Uniform), + }) + .unwrap(); + + g.validate_symmetry() + .unwrap_or_else(|e| panic!("{name}: {e}")); + for (a, b) in edge_set(&g) { + assert_eq!( + samples[a], samples[b], + "{name}: joined sample {} to {}", + samples[a], samples[b] + ); + } + assert!(g.edge_count() > 100, "{name} produced almost nothing"); + } + } + + /// The reason it builds per sample rather than filtering afterwards: with kNN, a cell at + /// a section's edge must take k neighbours from its own section, not lose them. + #[test] + fn per_sample_knn_keeps_every_cell_at_full_degree() { + let (pts, samples) = two_slices(6); + let k = 6; + let g = per_sample(&pts, &samples, |sub| { + knn_graph(sub, k, Symmetry::Union, SpatialWeight::Uniform) + }) + .unwrap(); + for v in 0..g.node_count() { + assert!(g.degree(v) >= k, "node {v} has degree {}", g.degree(v)); + } + + // Build globally and delete cross-sample edges, and cells lose neighbours instead. + let global = knn_graph(&pts, k, Symmetry::Union, SpatialWeight::Uniform).unwrap(); + let starved = (0..global.node_count()) + .filter(|&v| { + global + .neighbors(v) + .filter(|&(u, _)| samples[u] == samples[v]) + .count() + < k + }) + .count(); + assert!( + starved > 0, + "the filter-afterwards approach should starve some cells; if it no longer does, \ + this test's premise needs revisiting" + ); + } + + #[test] + fn per_sample_handles_edge_cases() { + let pts = vec![[0.0, 0.0], [1.0, 0.0], [50.0, 50.0]]; + // A sample of one has no neighbours, and must not break the reassembly. + let samples = vec![0u32, 0, 1]; + let g = per_sample(&pts, &samples, |sub| { + radius_graph(sub, 5.0, SpatialWeight::Uniform, None) + }) + .unwrap(); + assert_eq!(g.node_count(), 3); + assert_eq!(g.edge_count(), 1); + assert_eq!(g.degree(2), 0); + + let none: Vec<[f64; 2]> = Vec::new(); + assert_eq!( + per_sample(&none, &[], |sub| radius_graph( + sub, + 1.0, + SpatialWeight::Uniform, + None + )) + .unwrap() + .node_count(), + 0 + ); + assert!( + per_sample(&pts, &[0, 1], |sub| radius_graph( + sub, + 1.0, + SpatialWeight::Uniform, + None + )) + .is_err() + ); + } + + /// Sample labels are arbitrary; only the grouping matters. + #[test] + fn per_sample_is_independent_of_label_values() { + let (pts, samples) = two_slices(7); + let build = |sub: &[[f64; 2]]| radius_graph(sub, 4.0, SpatialWeight::Uniform, None); + + let a = per_sample(&pts, &samples, build).unwrap(); + let relabelled: Vec = samples + .iter() + .map(|&s| if s == 0 { 77 } else { 3 }) + .collect(); + let b = per_sample(&pts, &relabelled, build).unwrap(); + assert_eq!(edge_set(&a), edge_set(&b)); + } +} diff --git a/src/spatial/mod.rs b/src/spatial/mod.rs index 1af9f54..6c284e9 100644 --- a/src/spatial/mod.rs +++ b/src/spatial/mod.rs @@ -24,11 +24,13 @@ //! Neither affects `array_row` / `array_col`, which is what [`lattice_graph`] wants. pub mod banksy; +pub mod combine; pub mod delaunay; pub(crate) mod grid; pub mod lattice; pub mod points; +pub use combine::{Normalization, fuse, per_sample}; pub use delaunay::{HullPruning, delaunay_graph}; pub use lattice::{Lattice, lattice_graph, visium_isometric_coords}; pub use points::{SpatialWeight, Symmetry, knn_graph, radius_graph}; From c682ed348391f9b88d0a740021029c4d78ee7416 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 2 Aug 2026 12:31:40 +0200 Subject: [PATCH 10/20] docs: report measured accuracy and performance in the README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds what the crate has actually been measured against, with the comparison named in each case rather than left implicit. Accuracy: 160 committed leidenalg fixtures (-0.09% mean modularity single-seed, +0.42% best-of-2), igraph (+0.03%), exhaustive brute force (93.5% exact optimum against igraph's 94.4-96.3%), banksy-py (elementwise to 1e-6), and PBMC3k where cluster counts track scanpy within one at every resolution and agreement with the authors' cell types is 0.8599 against scanpy's 0.8609. States plainly that the leidenalg mean is noise — both are stochastic heuristics and leidenalg's own two fixture seeds differ by up to 3.5% on hard instances — and that what the fixtures pin exactly is the quality function's definition, not the optimiser's luck. Performance is framed against scanpy/igraph as a C implementation called from Python, not as an interpreter-overhead comparison: 2-3x on PBMC3k, 1.33x geometric mean on synthetic graphs. Also records what is *not* measured: spatial domain detection has no comparative result yet, so nothing in the README should be read as a claim about it, and points at the pre-registered benchmark target. --- README.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c0ddc23..8c8e259 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,85 @@ reproducible, and fast enough for single-cell-scale graphs. you already hold - **k-NN graph construction** from high-dimensional data (optional `knn` feature) +## Accuracy + +Correctness is checked against the implementations people actually use, not against itself. +Fixtures generated from `leidenalg` and `banksy-py` are committed, so the test suite needs no +Python. + +**Against `leidenalg`** — 160 committed fixtures spanning karate, LFR at several mixing +parameters, SBM and a real k-NN graph, across resolutions and seeds, for both RB and CPM: + +| | modularity vs `leidenalg` | +|---|---| +| single seed | −0.09% mean (70 better, 70 equal, 20 worse) | +| best of 2 seeds | +0.42% mean | + +Both libraries are stochastic heuristics over the same landscape — `leidenalg`'s own two +fixture seeds differ by up to 3.5% on the harder instances — so a single-run comparison is +mostly noise, and the sign of the mean is not meaningful. What the fixtures do pin exactly is +the *definition*: on the same membership our quality function reproduces `leidenalg`'s value +to floating point, which is what caught the 0.6.x factor-of-two resolution bug. + +**Against `igraph`**: +0.03% mean modularity. + +**Against brute force** — every set partition enumerated on graphs small enough to allow it, +so this compares to the true optimum rather than to another heuristic: + +| | reaches the exact optimum | +|---|---| +| this crate | 93.5% | +| `igraph` | 94.4–96.3% | + +**Against `banksy-py`**: the feature augmentation reproduces the reference elementwise to +**1e-6** across five decay kernels, harmonics 0–2, and λ from 0 to 1. The residual is the +reference's own precision — it stores azimuths as `float32`. + +### On real data + +PBMC3k (2,638 cells, 15-NN), clustering the *same* connectivity matrix `scanpy` did, so +every difference is the algorithm rather than graph construction: + +| resolution | clusters (ours / scanpy) | modularity (ours / scanpy) | +|---|---|---| +| 0.1 | 3 / 3 | 0.9511 / 0.9511 | +| 0.5 | 6 / 5 | 0.8063 / 0.8048 | +| 1.0 | 8 / 8 | 0.6715 / 0.6696 | +| 2.0 | 20 / 19 | 0.5304 / 0.5315 | +| 4.0 | 50 / 49 | 0.4217 / 0.4240 | + +Cluster counts track `scanpy` within one at every resolution, so resolution means the same +thing in both. Against the authors' cell-type annotations — the only measure here about +biology rather than about matching another implementation — **ours scores ARI 0.8599 and +`scanpy` 0.8609**, both peaking at resolution 0.75. + +## Performance + +Timings are against `scanpy`/`igraph`, which is a C implementation called from Python, not +interpreted code — so these are not interpreter-overhead numbers. + +| workload | this crate | `scanpy` / `igraph` | +|---|---|---| +| PBMC3k, per resolution | 7–11 ms | 22–24 ms | +| synthetic k-NN graphs | — | **1.33× slower** (geometric mean) | + +Single-threaded scaling on synthetic k-NN graphs: + +| nodes | edges | time | +|---|---|---| +| 20k | 170k | 18 ms | +| 100k | 840k | 111 ms | +| 3M | 25M | 6.8 s | +| 8M | 57M | 20.1 s | + +Spatial graph construction: + +| | | +|---|---| +| Visium HD lattice, 10.5M bins / 21.1M edges | 954 ms, 591 MB | +| 500k cells, k-NN (k=6) | 299 ms | +| 500k cells, radius | 80 ms | + ## Usage ```rust @@ -112,13 +191,27 @@ single-clustering = { version = "0.7", default-features = false } - ✅ **CSR network representation** - ✅ **Quality functions**: RB configuration model and CPM - ✅ **Reproducibility**: deterministic under a fixed seed +- ✅ **Spatial neighbour graphs**: Visium/HD lattice, radius, k-NN, Delaunay with adaptive + pruning, graph fusion, and per-sample construction for multi-slice experiments +- ✅ **BANKSY feature augmentation**: neighbourhood mean and azimuthal gradient, so ordinary + Leiden finds spatial domains - 🚧 **Louvain**: available as `LeidenConfig { refine: false, .. }`; no separate entry point - 🚧 **Benchmarks**: `cargo run --release --example scaling` - ❌ **Parallel local moving**: planned, deliberately deferred until the sequential path is - measured -- ❌ **DBSCAN / HDBSCAN / spatial-aware clustering**: planned + measured. Profiling puts 94% of a pass in level 0, of which local moving is 65% and + refinement 29%, so that is where it would go +- ❌ **DBSCAN / HDBSCAN**: planned - ❌ **Python bindings**: PyO3 integration (planned) +### Not yet measured + +Spatial *domain detection* has no comparative result. The pieces exist and each is verified +against its reference, but the end-to-end number — ARI against manual annotations on the +DLPFC benchmark — has not been produced. Until it has, nothing here should be read as a claim +about spatial domain accuracy. The target is pre-registered in +[`docs/spatial-benchmark.md`](docs/spatial-benchmark.md), along with what the established +methods score and which of their published numbers reproduce independently. + ## Contributing This project is in active development. Contributions, bug reports, and feature requests are From de0e52a9b84227ec7674be34e40c3fc059460359 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 2 Aug 2026 13:01:00 +0200 Subject: [PATCH 11/20] docs: clarify the speedup column in the performance table --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8c8e259..b7942d4 100644 --- a/README.md +++ b/README.md @@ -77,10 +77,10 @@ biology rather than about matching another implementation — **ours scores ARI Timings are against `scanpy`/`igraph`, which is a C implementation called from Python, not interpreted code — so these are not interpreter-overhead numbers. -| workload | this crate | `scanpy` / `igraph` | -|---|---|---| -| PBMC3k, per resolution | 7–11 ms | 22–24 ms | -| synthetic k-NN graphs | — | **1.33× slower** (geometric mean) | +| workload | this crate | `scanpy` / `igraph` | speedup | +|---|---|---|---| +| PBMC3k, per resolution | 7–11 ms | 22–24 ms | 2–3× | +| synthetic k-NN graphs, geometric mean | — | — | 1.33× | Single-threaded scaling on synthetic k-NN graphs: From 1128f2c9b890887a53f534e3cf86591a5aa72783 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 2 Aug 2026 22:06:28 +0200 Subject: [PATCH 12/20] version update --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c06d49..848b2ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1248,7 +1248,7 @@ dependencies = [ [[package]] name = "single-clustering" -version = "0.7.0" +version = "1.0.0" dependencies = [ "anyhow", "criterion", diff --git a/Cargo.toml b/Cargo.toml index e4e9a5b..d72b331 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "single-clustering" -version = "0.7.0" +version = "1.0.0" edition = "2024" authors = ["Ian F. Diks"] homepage = "https://singlerust.com" From df0750b324352be3f6f7ca71d0f40401a00379a4 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 2 Aug 2026 22:23:59 +0200 Subject: [PATCH 13/20] ci: run the ignored tests too The #[ignore]d tests were running nowhere. Three of the four are real coverage, not diagnostics: the Visium HD scale run is the only thing exercising the 10.5M-bin path, the Xenium run the only 500k-cell one, and the exhaustive optimality sweep over Bell(12) is the strongest evidence the optimiser actually reaches optima. They cost 11 seconds together, so there was no reason for the gap beyond nobody having added the job. --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9eef049..a726131 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,18 @@ jobs: - name: Test (release) run: cargo test --no-default-features --release + # the #[ignore]d tests: scale runs and the exhaustive optimality sweep. ~11s total, and + # without this the HD-scale path and the Bell(12) optimality check never execute anywhere. + scale: + name: Scale and exhaustive + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Ignored tests + run: cargo test --no-default-features --release -- --ignored --nocapture + # separate so an hnsw breakage doesn't take the core red knn: name: With kNN feature From b248a52724d99c801c9ac9fec92547805bfecc93 Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 17 Aug 2026 00:26:52 +0200 Subject: [PATCH 14/20] perf: measure how much node ordering is worth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Leiden's inner loop is a scatter-gather over CSR, so at scale it should be memory-latency bound and reordering nodes for locality should pay. Measured rather than assumed, since the answer decides whether it is worth doing. n morton bfs edge span (orig -> morton) 200k 1.07x 1.01x 5555 -> 314 1M 1.13x 1.09x 27778 -> 701 Locality improves ~40x and buys 13%. It does grow with size — at 200k the membership array still fits in L3, so there is nothing to fix — but slowly, and extrapolates to roughly 1.2x at 8M. That ranks reordering below parallelism: refinement alone is worth ~1.4x for comparable effort, and communities are independent during it so there is no shared-state hazard. Modularity is identical across all three orderings, which is the expected result of a pure relabelling and a decent check that the experiment measured what it claimed to. --- examples/reorder.rs | 234 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 examples/reorder.rs diff --git a/examples/reorder.rs b/examples/reorder.rs new file mode 100644 index 0000000..26a09f0 --- /dev/null +++ b/examples/reorder.rs @@ -0,0 +1,234 @@ +//! Measures how much of Leiden's runtime is node ordering rather than work. +//! +//! ```text +//! cargo run --release --no-default-features --example reorder -- 1000000 +//! ``` +//! +//! The inner loop is a scatter-gather over CSR: every visited node reads `membership` and the +//! community aggregates at its neighbours' indices. If those indices are scattered, each is a +//! cache miss. Relabelling nodes so that neighbours sit near each other in memory changes no +//! arithmetic at all — the clustering must come out identical up to the permutation — so any +//! difference in wall time is pure locality. +//! +//! Two orderings are compared against whatever order the data arrived in: +//! +//! * **Morton (Z-order)** on coordinates — needs positions, so spatial data only, but nearly +//! free to compute. +//! * **BFS** over the graph — works for any graph, including expression k-NN where there are +//! no coordinates. +//! +//! # What it measured +//! +//! ```text +//! n morton bfs edge span (orig -> morton) +//! 200k 1.07x 1.01x 5555 -> 314 +//! 1M 1.13x 1.09x 27778 -> 701 +//! ``` +//! +//! Locality improves by a factor of ~40 and buys 13%. The gain grows with size — at 200k the +//! membership array is under a megabyte and still fits in L3, so there is nothing to fix — +//! but slowly, and extrapolates to only ~1.2x at 8M. +//! +//! So reordering is real but small, and it was ranked below parallelism on the strength of +//! these numbers rather than on a guess: parallel refinement alone is worth ~1.4x for +//! comparable effort. Kept here because the conclusion is scale-dependent and someone should +//! re-measure before believing it at 75M. + +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use single_clustering::community_search::leiden::{LeidenConfig, leiden, modularity}; +use single_clustering::network::CSRNetwork; +use std::time::Instant; + +/// Interleaves the low 21 bits of each coordinate: nearby points get nearby keys. +fn morton(x: u32, y: u32) -> u64 { + fn spread(mut v: u64) -> u64 { + v &= 0x1f_ffff; + v = (v | (v << 32)) & 0x1f00000000ffff; + v = (v | (v << 16)) & 0x1f0000ff0000ff; + v = (v | (v << 8)) & 0x100f00f00f00f00f; + v = (v | (v << 4)) & 0x10c30c30c30c30c3; + (v | (v << 2)) & 0x1249249249249249 + } + spread(x as u64) | (spread(y as u64) << 1) +} + +type Edges = Vec<(usize, usize, f64)>; + +/// Points in blobs joined to their k nearest, plus the coordinates themselves. +fn knn_graph(n: usize, blocks: usize, k: usize, seed: u64) -> (Edges, Vec<[f64; 2]>) { + let mut rng = ChaCha8Rng::seed_from_u64(seed); + let n_per = n / blocks; + let centers: Vec<(f64, f64)> = (0..blocks) + .map(|b| { + let a = 2.0 * std::f64::consts::PI * (b as f64) / (blocks as f64); + (40.0 * a.cos(), 40.0 * a.sin()) + }) + .collect(); + let pts: Vec<[f64; 2]> = (0..n) + .map(|i| { + let c = centers[(i / n_per).min(blocks - 1)]; + [ + c.0 + rng.random::() * 12.0 - 6.0, + c.1 + rng.random::() * 12.0 - 6.0, + ] + }) + .collect(); + + let cell = 3.0; + let mut grid: std::collections::HashMap<(i64, i64), Vec> = + std::collections::HashMap::new(); + for (i, p) in pts.iter().enumerate() { + grid.entry(((p[0] / cell) as i64, (p[1] / cell) as i64)) + .or_default() + .push(i); + } + let mut edges = std::collections::HashSet::new(); + let mut cand = Vec::new(); + for i in 0..n { + let (gx, gy) = ((pts[i][0] / cell) as i64, (pts[i][1] / cell) as i64); + cand.clear(); + for dx in -1..=1 { + for dy in -1..=1 { + if let Some(b) = grid.get(&(gx + dx, gy + dy)) { + cand.extend(b.iter().copied().filter(|&j| j != i)); + } + } + } + let d = |j: &usize| { + let (dx, dy) = (pts[*j][0] - pts[i][0], pts[*j][1] - pts[i][1]); + dx * dx + dy * dy + }; + if cand.len() > k { + cand.select_nth_unstable_by(k, |a, b| d(a).partial_cmp(&d(b)).unwrap()); + cand.truncate(k); + } + for &j in &cand { + edges.insert(if i < j { (i, j) } else { (j, i) }); + } + } + (edges.into_iter().map(|(a, b)| (a, b, 1.0)).collect(), pts) +} + +/// Applies a permutation to an edge list. `perm[old] = new`. +fn relabel(edges: &[(usize, usize, f64)], perm: &[usize]) -> Edges { + edges + .iter() + .map(|&(a, b, w)| (perm[a], perm[b], w)) + .collect() +} + +fn morton_permutation(pts: &[[f64; 2]]) -> Vec { + let (mut lo, mut hi) = ([f64::INFINITY; 2], [f64::NEG_INFINITY; 2]); + for p in pts { + for d in 0..2 { + lo[d] = lo[d].min(p[d]); + hi[d] = hi[d].max(p[d]); + } + } + let scale = |v: f64, d: usize| { + let span = (hi[d] - lo[d]).max(1e-12); + (((v - lo[d]) / span) * ((1u32 << 21) - 1) as f64) as u32 + }; + let mut order: Vec = (0..pts.len()).collect(); + order.sort_unstable_by_key(|&i| morton(scale(pts[i][0], 0), scale(pts[i][1], 1))); + + let mut perm = vec![0usize; pts.len()]; + for (new, &old) in order.iter().enumerate() { + perm[old] = new; + } + perm +} + +fn bfs_permutation(graph: &CSRNetwork) -> Vec { + let n = graph.node_count(); + let mut perm = vec![usize::MAX; n]; + let mut next = 0usize; + let mut queue = std::collections::VecDeque::new(); + for start in 0..n { + if perm[start] != usize::MAX { + continue; + } + perm[start] = next; + next += 1; + queue.push_back(start); + while let Some(v) = queue.pop_front() { + for (u, _) in graph.neighbors(v) { + if perm[u] == usize::MAX { + perm[u] = next; + next += 1; + queue.push_back(u); + } + } + } + } + perm +} + +/// Mean absolute distance between an edge's endpoints in index space — the thing the +/// reordering is trying to shrink. +fn mean_edge_span(graph: &CSRNetwork) -> f64 { + let mut total = 0.0f64; + let mut count = 0usize; + for v in 0..graph.node_count() { + for (u, _) in graph.neighbors(v) { + total += (u as f64 - v as f64).abs(); + count += 1; + } + } + if count == 0 { + 0.0 + } else { + total / count as f64 + } +} + +fn time_clustering(graph: &CSRNetwork, label: &str, baseline: Option) -> f64 { + let config = LeidenConfig::default(); + // One warm run, then the measured one, so allocator state is comparable. + let _ = leiden(graph, &config).unwrap(); + let t = Instant::now(); + let c = leiden(graph, &config).unwrap(); + let secs = t.elapsed().as_secs_f64(); + + let q = modularity(graph, c.labels(), 1.0); + let speedup = baseline.map_or(String::from("—"), |b| format!("{:.2}x", b / secs)); + println!( + " {label:22} {:>8.3}s {speedup:>7} span {:>10.0} Q {q:.4} k {}", + secs, + mean_edge_span(graph), + c.n_clusters() + ); + secs +} + +fn main() { + let n: usize = std::env::args() + .nth(1) + .and_then(|s| s.parse().ok()) + .unwrap_or(1_000_000); + + println!("building a {n}-node 15-NN graph..."); + let (edges, pts) = knn_graph(n, 12, 15, 7); + println!(" {} edges\n", edges.len()); + + println!( + " {:22} {:>8} {:>7} {:>15}", + "ordering", "time", "vs orig", "locality" + ); + let original = CSRNetwork::from_edges(n, &edges).unwrap(); + let base = time_clustering(&original, "as-generated", None); + + let perm = morton_permutation(&pts); + let morton_graph = CSRNetwork::from_edges(n, &relabel(&edges, &perm)).unwrap(); + time_clustering(&morton_graph, "morton (coords)", Some(base)); + + let perm = bfs_permutation(&original); + let bfs_graph = CSRNetwork::from_edges(n, &relabel(&edges, &perm)).unwrap(); + time_clustering(&bfs_graph, "bfs (graph only)", Some(base)); + + println!( + "\nRelabelling changes no arithmetic, so any difference is locality alone.\n\ + Modularity should agree to f32 storage precision across all three." + ); +} From 76c0152a32a52c9c9333811782aff626fd20a0ad Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 23 Aug 2026 23:24:02 +0200 Subject: [PATCH 15/20] perf: measure against igraph properly, and correct the README The README claimed 2-3x against scanpy on PBMC3k. That number included scanpy converting its sparse matrix into an igraph object inside the timed call, so it measured the pipeline, not the algorithm. Adds examples/vs_igraph.rs and tools/igraph_bench.py, which write one graph both sides read and time only the clustering call: nodes ours igraph speedup 20k 0.030s 0.041s 1.38x 100k 0.166s 0.257s 1.55x 500k 1.605s 1.846s 1.15x 1M 3.457s 4.211s 1.22x Geometric mean 1.32x, and modularity is identical to four decimals at every size. The pre-existing 1.33x claim therefore survives a clean re-measurement; the 2-3x one did not, and is now stated as what it is. Worth noting the margin narrows above 100k. Both implementations end up memory-latency bound on the same scatter-gather pattern, which is consistent with the reordering experiment and says the remaining headroom is parallelism rather than single-threaded tuning. --- README.md | 31 ++++++++++++---- examples/vs_igraph.rs | 83 +++++++++++++++++++++++++++++++++++++++++++ tools/igraph_bench.py | 39 ++++++++++++++++++++ 3 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 examples/vs_igraph.rs create mode 100644 tools/igraph_bench.py diff --git a/README.md b/README.md index b7942d4..05135bc 100644 --- a/README.md +++ b/README.md @@ -74,13 +74,30 @@ biology rather than about matching another implementation — **ours scores ARI ## Performance -Timings are against `scanpy`/`igraph`, which is a C implementation called from Python, not -interpreted code — so these are not interpreter-overhead numbers. - -| workload | this crate | `scanpy` / `igraph` | speedup | -|---|---|---|---| -| PBMC3k, per resolution | 7–11 ms | 22–24 ms | 2–3× | -| synthetic k-NN graphs, geometric mean | — | — | 1.33× | +The comparison is against `igraph`, which is C called from Python — so these are not +interpreter-overhead numbers. Both sides cluster the identical graph and **only the +clustering call is timed**; graph construction is excluded, because including it measures the +pipeline rather than the algorithm. + +| nodes | edges | this crate | `igraph` | speedup | +|---|---|---|---|---| +| 20k | 158k | 0.030 s | 0.041 s | 1.38× | +| 100k | 798k | 0.166 s | 0.257 s | 1.55× | +| 500k | 4.0M | 1.605 s | 1.846 s | 1.15× | +| 1M | 8.0M | 3.457 s | 4.211 s | 1.22× | + +**Geometric mean 1.32×**, and modularity is identical to four decimals at every size — this is +the same answer computed faster, not a different tradeoff. Reproduce with +`examples/vs_igraph.rs` and `tools/igraph_bench.py`. + +Note the margin narrows above 100k: both implementations become memory-latency bound on the +same scatter-gather access pattern, so the remaining headroom is parallelism rather than +single-threaded tuning. + +End to end through `scanpy`, `sc.tl.leiden` takes 22–24 ms per resolution on PBMC3k against +7–11 ms here, but that gap is **not** the algorithm — most of it is `scanpy` converting its +sparse matrix into an igraph object inside the timed call. The table above is the honest +algorithmic comparison. Single-threaded scaling on synthetic k-NN graphs: diff --git a/examples/vs_igraph.rs b/examples/vs_igraph.rs new file mode 100644 index 0000000..e52eccf --- /dev/null +++ b/examples/vs_igraph.rs @@ -0,0 +1,83 @@ +//! Head-to-head against igraph, clustering only. +//! +//! ```text +//! cargo run --release --no-default-features --example vs_igraph -- 200000 /tmp/bench +//! uv run tools/igraph_bench.py /tmp/bench +//! ``` +//! +//! Writes the graph to `/edges.tsv` so both sides cluster the identical input, and +//! times only `leiden()` — graph construction is excluded on both sides, because including +//! it measures the pipeline rather than the algorithm. + +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use single_clustering::community_search::leiden::{LeidenConfig, leiden, modularity}; +use single_clustering::network::CSRNetwork; +use std::io::Write; +use std::time::Instant; + +/// Ring lattice with long-range noise: bounded degree and local structure, like a kNN graph, +/// but generated in linear time so large sizes are practical. +fn synthetic(n: usize, k: usize, seed: u64) -> Vec<(usize, usize, f64)> { + let mut rng = ChaCha8Rng::seed_from_u64(seed); + let block = 2_000usize; + let mut edges = Vec::with_capacity(n * k); + for i in 0..n { + for d in 1..=k / 2 { + let j = (i + d) % n; + if i != j { + edges.push((i.min(j), i.max(j), 1.0)); + } + } + // one cross-block edge, so communities stay detectable + let j = rng.random_range(0..n); + let same_block = i / block == j / block; + if i != j && !same_block { + edges.push((i.min(j), i.max(j), 1.0)); + } + } + edges.sort_unstable_by_key(|&(a, b, _)| (a, b)); + edges.dedup_by_key(|e| (e.0, e.1)); + edges +} + +fn main() { + let mut args = std::env::args().skip(1); + let n: usize = args.next().and_then(|s| s.parse().ok()).unwrap_or(200_000); + let dir = args.next().unwrap_or_else(|| "/tmp/bench".into()); + std::fs::create_dir_all(&dir).unwrap(); + + let edges = synthetic(n, 14, 7); + println!("{n} nodes, {} edges", edges.len()); + + let path = format!("{dir}/edges.tsv"); + let mut out = std::io::BufWriter::new(std::fs::File::create(&path).unwrap()); + for &(a, b, _) in &edges { + writeln!(out, "{a}\t{b}").unwrap(); + } + out.flush().unwrap(); + drop(out); + + let graph = CSRNetwork::from_edges(n, &edges).unwrap(); + let config = LeidenConfig::default(); + + // Warm once, then take the best of five: the fairest thing to compare against igraph's + // own best, and least sensitive to a stray scheduling hiccup. + let _ = leiden(&graph, &config).unwrap(); + let mut best = f64::INFINITY; + let mut clustering = None; + for _ in 0..5 { + let t = Instant::now(); + let c = leiden(&graph, &config).unwrap(); + best = best.min(t.elapsed().as_secs_f64()); + clustering = Some(c); + } + let c = clustering.unwrap(); + println!( + "rust {:.4}s Q {:.4} k {}", + best, + modularity(&graph, c.labels(), 1.0), + c.n_clusters() + ); + println!("wrote {path}"); +} diff --git a/tools/igraph_bench.py b/tools/igraph_bench.py new file mode 100644 index 0000000..68969b8 --- /dev/null +++ b/tools/igraph_bench.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +"""Times igraph's Leiden on the graph written by `examples/vs_igraph.rs`. + + cargo run --release --no-default-features --example vs_igraph -- 200000 /tmp/bench + uv run tools/igraph_bench.py /tmp/bench + +Graph construction is excluded on both sides — only the clustering call is timed, so this +compares the algorithms rather than the surrounding pipeline. +""" + +import sys +import time + +import igraph as ig + +directory = sys.argv[1] if len(sys.argv) > 1 else "/tmp/bench" +edges = [] +with open(f"{directory}/edges.tsv") as fh: + for line in fh: + a, b = line.split() + edges.append((int(a), int(b))) + +n = max(max(a, b) for a, b in edges) + 1 +build = time.perf_counter() +g = ig.Graph(n=n, edges=edges, directed=False) +build = time.perf_counter() - build +print(f"{n} nodes, {len(edges)} edges (igraph build {build:.3f}s, excluded)") + +# Best of five, matching the Rust side. n_iterations=2 is our default; igraph's own default +# is 2 as well. +best, part = float("inf"), None +g.community_leiden(objective_function="modularity", resolution=1.0, n_iterations=2) +for _ in range(5): + t = time.perf_counter() + p = g.community_leiden(objective_function="modularity", resolution=1.0, n_iterations=2) + best = min(best, time.perf_counter() - t) + part = p + +print(f"igraph {best:.4f}s Q {g.modularity(part.membership):.4f} k {len(part)}") From 4cebd75e406b060bb5ac48a7abdbf7f3086147d3 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 23 Aug 2026 23:38:38 +0200 Subject: [PATCH 16/20] perf: measure the ceiling on multi-threading before building it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runs N independent clusterings concurrently, each on its own graph. Nothing is shared, so the only thing that can stop linear scaling is the memory system — which makes it an upper bound on any parallel local-move, since that does share state. threads throughput vs 1 1 0.78/s 1.00x 2 1.44/s 1.85x 4 2.48/s 3.17x 8 4.01/s 5.14x 16 6.21/s 7.95x Worth knowing because the igraph comparison showed the margin narrowing above 100k, which suggested a bandwidth wall that would make parallelism pointless. It isn't one: latency-bound is not the same as bandwidth-saturated, and the misses overlap fine across threads. With 89% of a run parallelisable (level-0 local moving and refinement), that ceiling puts the realistic target at 2.5-3.5x on 8 threads rather than the 9.3x Amdahl alone suggests. --- examples/scaling_ceiling.rs | 97 +++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 examples/scaling_ceiling.rs diff --git a/examples/scaling_ceiling.rs b/examples/scaling_ceiling.rs new file mode 100644 index 0000000..abbee55 --- /dev/null +++ b/examples/scaling_ceiling.rs @@ -0,0 +1,97 @@ +//! Upper bound on what multi-threading could buy, without writing any of it. +//! +//! ```text +//! cargo run --release --no-default-features --example scaling_ceiling -- 500000 +//! ``` +//! +//! Runs N *independent* clusterings concurrently, each on its own graph, and measures +//! aggregate throughput against one thread. Nothing is shared, so there is no contention and +//! no coordination — the only thing that can stop this scaling linearly is the memory system. +//! +//! That makes it a ceiling: a real parallel local-move, which does share state, cannot beat +//! it. If throughput flattens at 4x on 8 cores, no amount of clever lock-free work gets 8x. + +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use single_clustering::community_search::leiden::{LeidenConfig, leiden}; +use single_clustering::network::CSRNetwork; +use std::time::Instant; + +fn synthetic(n: usize, k: usize, seed: u64) -> Vec<(usize, usize, f64)> { + let mut rng = ChaCha8Rng::seed_from_u64(seed); + let mut edges = Vec::with_capacity(n * k); + for i in 0..n { + for d in 1..=k / 2 { + let j = (i + d) % n; + if i != j { + edges.push((i.min(j), i.max(j), 1.0)); + } + } + let j = rng.random_range(0..n); + if i != j && i / 2000 != j / 2000 { + edges.push((i.min(j), i.max(j), 1.0)); + } + } + edges.sort_unstable_by_key(|&(a, b, _)| (a, b)); + edges.dedup_by_key(|e| (e.0, e.1)); + edges +} + +fn main() { + let n: usize = std::env::args() + .nth(1) + .and_then(|s| s.parse().ok()) + .unwrap_or(500_000); + let cores = std::thread::available_parallelism().map_or(8, |c| c.get()); + + println!("building {n}-node graph, {cores} cores available"); + let edges = synthetic(n, 14, 7); + let graph = CSRNetwork::from_edges(n, &edges).unwrap(); + drop(edges); + println!( + " {} edges, {:.0} MB\n", + graph.edge_count(), + graph.memory_bytes() as f64 / 1e6 + ); + + let config = LeidenConfig::default(); + let _ = leiden(&graph, &config).unwrap(); + + println!( + "{:>7} {:>10} {:>12} {:>10}", + "threads", "wall", "throughput", "vs 1" + ); + let mut base = 0.0f64; + let mut t = 1; + while t <= cores { + // Each thread gets its own copy, so nothing is shared but the memory system. + let copies: Vec = (0..t).map(|_| graph.clone()).collect(); + + let start = Instant::now(); + std::thread::scope(|s| { + for g in &copies { + let cfg = config.clone(); + s.spawn(move || { + let _ = leiden(g, &cfg).unwrap(); + }); + } + }); + let wall = start.elapsed().as_secs_f64(); + let throughput = t as f64 / wall; + if t == 1 { + base = throughput; + } + println!( + "{t:>7} {:>9.3}s {:>10.2}/s {:>9.2}x", + wall, + throughput, + throughput / base + ); + t *= 2; + } + + println!( + "\nThis is the ceiling: independent work, zero sharing. A parallel local-move shares\n\ + partition state, so it lands below whatever this shows." + ); +} From ce384ab8c4f7f37f7edda31cba402370511a4cf2 Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 24 Aug 2026 01:11:17 +0200 Subject: [PATCH 17/20] feat: parallel refinement behind a `parallel` feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refinement is constrained within each community of the working partition, so two communities share no state at all. That was always true; the obstacle was that the borrow checker could not see it, because everything went through one global Partition. Restructured so each community refines on local state: - Objective gains delta_insert_view, taking the three aggregates a move actually depends on (total weight, community strength, community weight). delta_insert now reads those out of a Partition and delegates, so there is still exactly one copy of each formula and the two paths cannot drift. - refine_into() works a single community with local ids and local arrays, and returns labels. The caller rebuilds one Partition from all the labels, so every aggregate is exact rather than incrementally maintained across a split. - rayon over communities when the feature is on. One behavioural change: refinement randomness is now one draw per node, taken up front in node order. Previously each select() pulled from a shared stream, so a node's randomness depended on how many nodes before it happened to need one — which couples communities that are otherwise independent and would make results depend on how the work was divided. Clustering quality is unaffected; the leidenalg differential fixtures still pass. Measured on a quiet machine, clustering only: nodes seq par igraph par/seq par/igraph 100k 0.150s 0.117s 0.199s 1.28x 1.70x 500k 1.113s 0.912s 1.469s 1.22x 1.61x 1M 2.568s 2.202s 3.410s 1.17x 1.55x Note the earlier igraph figures in the README were measured while a background job was running and were ~25% slow; the corrected single-threaded ratio is a consistent 1.33x at every size, which is what the original geometric mean said. Off by default because local moving is still sequential, so this is 1.2-1.3x rather than the several-x a fully parallel implementation would give. tests/thread_invariance.rs demands byte-identical labels across 1/2/4/8/16 threads over three objectives, two seeds and four graphs. That is the test the pre-0.7 parallel path lacked: a staleness bug does not crash, it returns a slightly different and entirely plausible clustering. --- .github/workflows/ci.yml | 6 + Cargo.toml | 3 + README.md | 49 +++-- src/community_search/leiden/objective.rs | 57 ++++- src/community_search/leiden/refine.rs | 262 ++++++++++++++++++----- tests/thread_invariance.rs | 94 ++++++++ 6 files changed, 395 insertions(+), 76 deletions(-) create mode 100644 tests/thread_invariance.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a726131..d17cb36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,12 @@ jobs: - name: Test (release) run: cargo test --no-default-features --release + # the parallel path must give byte-identical results, so it needs its own run + - name: Clippy (parallel) + run: cargo clippy --no-default-features --features parallel --all-targets -- -D warnings + - name: Test (parallel) + run: cargo test --no-default-features --features parallel --release + # the #[ignore]d tests: scale runs and the exhaustive optimality sweep. ~11s total, and # without this the HD-scale path and the Bell(12) optimality check never execute anywhere. scale: diff --git a/Cargo.toml b/Cargo.toml index d72b331..6df1f14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,9 @@ default = ["knn"] # clustering core can be built and tested without the HNSW/kd-tree stack, which does not # compile on every target. knn = ["dep:hnsw_rs", "dep:kiddo", "dep:ndarray"] +# Multi-threaded refinement. Off by default until local moving is parallel too, since +# refinement alone is worth about 1.25x. +parallel = [] # Spatial neighbour graphs are always available: the uniform-grid index they use has no # dependencies, so there is no build to opt out of. diff --git a/README.md b/README.md index 05135bc..eb756c4 100644 --- a/README.md +++ b/README.md @@ -79,20 +79,23 @@ interpreter-overhead numbers. Both sides cluster the identical graph and **only clustering call is timed**; graph construction is excluded, because including it measures the pipeline rather than the algorithm. -| nodes | edges | this crate | `igraph` | speedup | -|---|---|---|---|---| -| 20k | 158k | 0.030 s | 0.041 s | 1.38× | -| 100k | 798k | 0.166 s | 0.257 s | 1.55× | -| 500k | 4.0M | 1.605 s | 1.846 s | 1.15× | -| 1M | 8.0M | 3.457 s | 4.211 s | 1.22× | - -**Geometric mean 1.32×**, and modularity is identical to four decimals at every size — this is -the same answer computed faster, not a different tradeoff. Reproduce with -`examples/vs_igraph.rs` and `tools/igraph_bench.py`. - -Note the margin narrows above 100k: both implementations become memory-latency bound on the -same scatter-gather access pattern, so the remaining headroom is parallelism rather than -single-threaded tuning. +| nodes | edges | this crate | + `parallel` | `igraph` | speedup | +|---|---|---|---|---|---| +| 100k | 798k | 0.150 s | 0.117 s | 0.199 s | 1.33× / **1.70×** | +| 500k | 4.0M | 1.113 s | 0.912 s | 1.469 s | 1.32× / **1.61×** | +| 1M | 8.0M | 2.568 s | 2.202 s | 3.410 s | 1.33× / **1.55×** | + +Single-threaded it is a consistent **1.33×**; with the `parallel` feature, which multi-threads +refinement, **1.55–1.70×**. Modularity is identical to four decimals throughout — the same +answer computed faster, not a different tradeoff. Reproduce with `examples/vs_igraph.rs` and +`tools/igraph_bench.py`. + +Both implementations are memory-latency bound on the same scatter-gather access pattern, so +single-threaded tuning is close to exhausted — node reordering for cache locality was measured +at only 1.13× (`examples/reorder.rs`). The remaining headroom is parallelism: `examples/scaling_ceiling.rs` +measures the memory system sustaining 5.1× on 8 threads and 8× on 16, and 89% of a run is +parallelisable, so the ceiling is real. Refinement is done; local moving is the larger half and +is not yet parallel. End to end through `scanpy`, `sc.tl.leiden` takes 22–24 ms per resolution on PBMC3k against 7–11 ms here, but that gap is **not** the algorithm — most of it is `scanpy` converting its @@ -202,6 +205,17 @@ clustering core — useful in CI, or on targets where the HNSW stack does not co single-clustering = { version = "0.7", default-features = false } ``` +Multi-threaded refinement is behind an off-by-default `parallel` feature. It is off because +local moving — the larger half of the work — is still sequential, so the gain is 1.2-1.3x +rather than the several-x a fully parallel implementation would give: + +```toml +single-clustering = { version = "0.7", features = ["parallel"] } +``` + +Results are byte-identical regardless of thread count; `tests/thread_invariance.rs` asserts it +across thread counts, objectives and seeds. + ## Current status - ✅ **Leiden algorithm**: local moving, refinement, and aggregation @@ -214,9 +228,10 @@ single-clustering = { version = "0.7", default-features = false } Leiden finds spatial domains - 🚧 **Louvain**: available as `LeidenConfig { refine: false, .. }`; no separate entry point - 🚧 **Benchmarks**: `cargo run --release --example scaling` -- ❌ **Parallel local moving**: planned, deliberately deferred until the sequential path is - measured. Profiling puts 94% of a pass in level 0, of which local moving is 65% and - refinement 29%, so that is where it would go +- ✅ **Parallel refinement** (`parallel` feature): communities refine independently, so there + is no shared state to race on. 1.2-1.3x, and byte-identical across thread counts +- ❌ **Parallel local moving**: the other 65% of a pass, and the harder half — it mutates + shared community aggregates, which is what the pre-0.7 parallel path got wrong - ❌ **DBSCAN / HDBSCAN**: planned - ❌ **Python bindings**: PyO3 integration (planned) diff --git a/src/community_search/leiden/objective.rs b/src/community_search/leiden/objective.rs index 8b17f8a..6fb0754 100644 --- a/src/community_search/leiden/objective.rs +++ b/src/community_search/leiden/objective.rs @@ -40,21 +40,58 @@ impl InsertContext { } } +/// The community aggregates a move actually depends on. +/// +/// Only three numbers, which is what lets refinement work on per-community local state +/// instead of the whole partition — the basis of running it in parallel. +#[derive(Debug, Clone, Copy, Default)] +pub struct CommunityView { + /// Total edge weight of the graph, each edge once. Global, not per community. + pub total_weight: f64, + /// Summed node strength of the community — `K_c` in the RB null model. + pub strength: f64, + /// Summed node weight of the community — `n_c` in CPM. + pub weight: f64, +} + /// A quality function to maximize. pub trait Objective: Send + Sync { - /// Change in quality from inserting a currently-removed node into `community`. + /// Change in quality from inserting a currently-removed node into a community. + /// + /// The one place each objective's formula lives. [`delta_insert`](Self::delta_insert) + /// reads the view out of a [`Partition`] and calls this, so the partition-backed and + /// local-state paths can never drift apart. /// /// `weight_to_comm` excludes the node's self-loop; that gets added here, since it becomes /// internal to whichever community the node lands in. + fn delta_insert_view( + &self, + view: CommunityView, + ctx: &InsertContext, + weight_to_comm: f64, + ) -> f64; + + /// Change in quality from inserting a currently-removed node into `community`. /// /// `community` may name an unallocated slot, which reads as empty. + #[inline] fn delta_insert( &self, partition: &Partition, ctx: &InsertContext, community: usize, weight_to_comm: f64, - ) -> f64; + ) -> f64 { + self.delta_insert_view( + CommunityView { + total_weight: partition.total_weight(), + strength: partition.strength(community), + weight: partition.weight(community), + }, + ctx, + weight_to_comm, + ) + } /// Total quality of the partition, in the same units as [`delta_insert`](Self::delta_insert). fn quality(&self, partition: &Partition) -> f64; @@ -88,18 +125,17 @@ impl Default for Rb { impl Objective for Rb { #[inline] - fn delta_insert( + fn delta_insert_view( &self, - partition: &Partition, + view: CommunityView, ctx: &InsertContext, - community: usize, weight_to_comm: f64, ) -> f64 { - let four_m = 4.0 * partition.total_weight(); + let four_m = 4.0 * view.total_weight; if four_m == 0.0 { return 0.0; } - let k_c = partition.strength(community); + let k_c = view.strength; let k = ctx.node_strength; // d/dK of γ·K²/(4m) discretised: ((K+k)² − K²) = k·(2K + k) (weight_to_comm + ctx.self_loop) - self.resolution * k * (2.0 * k_c + k) / four_m @@ -155,14 +191,13 @@ impl Default for Cpm { impl Objective for Cpm { #[inline] - fn delta_insert( + fn delta_insert_view( &self, - partition: &Partition, + view: CommunityView, ctx: &InsertContext, - community: usize, weight_to_comm: f64, ) -> f64 { - let n_c = partition.weight(community); + let n_c = view.weight; let a = ctx.node_weight; // ((n+a)(n+a-1) - n(n-1)) / 2 = a(2n + a - 1) / 2 (weight_to_comm + ctx.self_loop) - self.resolution * a * (2.0 * n_c + a - 1.0) / 2.0 diff --git a/src/community_search/leiden/refine.rs b/src/community_search/leiden/refine.rs index 56bce7e..be9754e 100644 --- a/src/community_search/leiden/refine.rs +++ b/src/community_search/leiden/refine.rs @@ -17,7 +17,7 @@ use rand::Rng; use rand_chacha::ChaCha8Rng; -use crate::community_search::leiden::objective::{InsertContext, Objective}; +use crate::community_search::leiden::objective::{CommunityView, InsertContext, Objective}; use crate::community_search::leiden::partition::{MoveScratch, Partition}; use crate::network::CSRNetwork; @@ -36,9 +36,8 @@ pub fn refine( randomness: f64, ) -> Partition { let n = graph.node_count(); - let mut refined = Partition::singleton(graph); if n == 0 { - return refined; + return Partition::singleton(graph); } // relative to a typical edge, so rescaling weights doesn't change behaviour @@ -49,57 +48,90 @@ pub fn refine( }; let randomness = randomness * mean_edge_weight; - // snapshot — the loop body needs `scratch` mutably - let order: Vec = scratch.shuffled_order(n, rng).to_vec(); - let mut candidates: Vec<(usize, f64)> = Vec::new(); - let mut exp_buf: Vec = Vec::new(); - - for v in order { - let own = refined.membership(v); - // rule 1: singletons only - if refined.size(own) != 1 { - continue; - } - - let ctx = InsertContext::for_node(graph, v); - // rule 2: stay inside the constraint - scratch.weights.ensure_capacity(refined.slots() + 1); - scratch - .weights - .collect_constrained(graph, refined.membership_raw(), v, constraint); + // One draw per node, taken up front in node order. Previously each `select` pulled from a + // shared stream, so a node's randomness depended on how many nodes before it happened to + // need one — which couples communities that are otherwise independent, and would make the + // result depend on how the work was divided. Drawing per node decouples them. + let draws: Vec = (0..n).map(|_| rng.random::()).collect(); - let weight_to_own = scratch.weights.weight_to(own); - refined.remove_node(v, graph, weight_to_own); + // Visit order stays globally shuffled; bucketing preserves each community's relative + // order within it, so the sequence a community sees is what it would have seen anyway. + let order = scratch.shuffled_order(n, rng); + // Sized by the largest constraint id, not by the node count: these ids are inherited from + // the previous level's working partition, so at level 1 and above they routinely exceed + // the number of nodes in the current graph. + let slots = constraint + .iter() + .copied() + .max() + .map_or(0, |m| m as usize + 1); + let mut members: Vec> = vec![Vec::new(); slots]; + for &v in order.iter() { + members[constraint[v] as usize].push(v as u32); + } - let base_gain = objective.delta_insert(&refined, &ctx, own, weight_to_own); + let total_weight = graph.total_weight(); + let mut labels = vec![0u32; n]; - // candidates that don't lose quality - candidates.clear(); - let mut best_rel = 0.0f64; - for i in 0..scratch.weights.touched().len() { - let c = scratch.weights.touched()[i]; - if c == own { - continue; - } - if let Some(limit) = max_community_weight - && refined.weight(c) + ctx.node_weight > limit - { - continue; + #[cfg(feature = "parallel")] + { + use rayon::prelude::*; + // Each community writes only its own members' labels, so the output slices are + // disjoint. Collected per community and merged, which keeps that obvious. + let refined: Vec<(Vec, Vec)> = members + .par_iter() + .filter(|m| !m.is_empty()) + .map(|m| { + let mut sorted = m.clone(); + sorted.sort_unstable(); + let mut out = vec![0u32; sorted.len()]; + refine_into( + graph, + m, + &sorted, + objective, + total_weight, + &draws, + max_community_weight, + randomness, + &mut out, + ); + (sorted, out) + }) + .collect(); + for (sorted, out) in refined { + for (i, &g) in sorted.iter().enumerate() { + labels[g as usize] = out[i]; } - let rel = - objective.delta_insert(&refined, &ctx, c, scratch.weights.weight_to(c)) - base_gain; - // `>=` takes ties, like libleidenalg - if rel >= 0.0 { - candidates.push((c, rel)); - best_rel = best_rel.max(rel); + } + } + #[cfg(not(feature = "parallel"))] + { + for m in members.iter().filter(|m| !m.is_empty()) { + let mut sorted = m.clone(); + sorted.sort_unstable(); + let mut out = vec![0u32; sorted.len()]; + refine_into( + graph, + m, + &sorted, + objective, + total_weight, + &draws, + max_community_weight, + randomness, + &mut out, + ); + for (i, &g) in sorted.iter().enumerate() { + labels[g as usize] = out[i]; } } - - let target = select(&candidates, best_rel, randomness, rng, &mut exp_buf).unwrap_or(own); - refined.insert_node(v, target, graph, scratch.weights.weight_to(target)); } - refined + // Rebuild a full partition from the labels, so every aggregate is exactly right rather + // than incrementally maintained across a parallel split. + let as_usize: Vec = labels.iter().map(|&c| c as usize).collect(); + Partition::from_membership(graph, &as_usize) } /// Draws a candidate with probability proportional to `exp(gain / randomness)`. @@ -111,7 +143,7 @@ fn select( candidates: &[(usize, f64)], best_rel: f64, randomness: f64, - rng: &mut ChaCha8Rng, + draw: f64, weights: &mut Vec, ) -> Option { if candidates.is_empty() { @@ -141,7 +173,7 @@ fn select( .min(); } - let mut threshold = rng.random::() * total; + let mut threshold = draw * total; for (&(c, _), &w) in candidates.iter().zip(weights.iter()) { threshold -= w; if threshold <= 0.0 { @@ -152,6 +184,140 @@ fn select( candidates.last().map(|&(c, _)| c) } +/// Refines one constraining community, independently of every other. +/// +/// This is the whole basis for running refinement in parallel: a node may only merge with +/// refined communities inside its own constraining community, so two constraining communities +/// share no state at all. Working on local ids rather than the global partition is what makes +/// that disjointness visible to the compiler instead of merely true. +/// +/// `members` are the community's global node ids in the order they should be visited; +/// `sorted` is the same set ascending, for global-to-local lookup. Writes each member's +/// refined label into `out`, as a global node id — the id of the member that community formed +/// around, so labels from different communities can never collide. +#[allow(clippy::too_many_arguments)] +fn refine_into( + graph: &CSRNetwork, + members: &[u32], + sorted: &[u32], + objective: &dyn Objective, + total_weight: f64, + draws: &[f64], + max_community_weight: Option, + randomness: f64, + out: &mut [u32], +) { + let k = sorted.len(); + if k == 0 { + return; + } + let local_of = + |g: u32| -> usize { sorted.binary_search(&g).expect("member of this community") }; + + // Local singleton partition: community i starts as node i. Only the three aggregates + // `delta_insert_view` reads are tracked; `internal` is never consulted during refinement, + // and the caller rebuilds a full partition from the labels afterwards. + let mut membership: Vec = (0..k as u32).collect(); + let mut size = vec![1u32; k]; + let mut strength = vec![0.0f64; k]; + let mut weight = vec![0.0f64; k]; + for (local, &g) in sorted.iter().enumerate() { + strength[local] = graph.strength(g as usize); + weight[local] = graph.node_weight(g as usize); + } + + // Weight from the current node to each local community, cleared via `touched`. + let mut to_comm = vec![0.0f64; k]; + let mut touched: Vec = Vec::new(); + let mut candidates: Vec<(usize, f64)> = Vec::new(); + let mut exp_buf: Vec = Vec::new(); + + for &g in members { + let v = local_of(g); + let own = membership[v] as usize; + // rule 1: singletons only + if size[own] != 1 { + continue; + } + + for &c in &touched { + to_comm[c] = 0.0; + } + touched.clear(); + + // rule 2: stay inside the constraint — neighbours outside it are simply not in + // `sorted`, so the binary search filters them out. + for (u, w) in graph.neighbors(g as usize) { + if u == g as usize { + continue; + } + if let Ok(local_u) = sorted.binary_search(&(u as u32)) { + let c = membership[local_u] as usize; + if to_comm[c] == 0.0 { + touched.push(c); + } + to_comm[c] += w; + } + } + + let ctx = InsertContext::for_node(graph, g as usize); + let weight_to_own = to_comm[own]; + + // Take the node out. Its own community is a singleton, so it empties. + size[own] -= 1; + strength[own] -= ctx.node_strength; + weight[own] -= ctx.node_weight; + + let view_of = |c: usize| CommunityView { + total_weight, + strength: strength[c], + weight: weight[c], + }; + let base_gain = objective.delta_insert_view(view_of(own), &ctx, weight_to_own); + + // candidates that don't lose quality + candidates.clear(); + let mut best_rel = 0.0f64; + for &c in &touched { + if c == own { + continue; + } + if let Some(limit) = max_community_weight + && weight[c] + ctx.node_weight > limit + { + continue; + } + let rel = objective.delta_insert_view(view_of(c), &ctx, to_comm[c]) - base_gain; + // `>=` takes ties, like libleidenalg + if rel >= 0.0 { + candidates.push((c, rel)); + best_rel = best_rel.max(rel); + } + } + + let target = select( + &candidates, + best_rel, + randomness, + draws[g as usize], + &mut exp_buf, + ) + .unwrap_or(own); + + size[target] += 1; + strength[target] += ctx.node_strength; + weight[target] += ctx.node_weight; + membership[v] = target as u32; + } + + // Label each member by the global id its refined community formed around, so labels are + // unique across communities without any coordination between them. + // `out` is indexed locally, matching `sorted`; the caller scatters it to global ids. + for local in 0..k { + out[local] = sorted[membership[local] as usize]; + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/tests/thread_invariance.rs b/tests/thread_invariance.rs new file mode 100644 index 0000000..485b6a6 --- /dev/null +++ b/tests/thread_invariance.rs @@ -0,0 +1,94 @@ +//! Results must not depend on how the work was divided. +//! +//! The single most important test for the parallel path. A staleness bug — a thread reading a +//! community aggregate another thread has already changed — does not crash or produce an +//! obviously wrong answer. It produces a *slightly different* clustering, which looks entirely +//! plausible. Comparing across thread counts is what makes that visible. +//! +//! Runs the same inputs under 1, 2, 4, 8 and 16 rayon threads and demands byte-identical +//! labels. Requires the `parallel` feature to be meaningful, but is written to pass either +//! way so a default build still exercises the comparison logic. + +mod common; + +use common::{karate, sbm}; +use single_clustering::community_search::leiden::{LeidenConfig, ObjectiveKind, leiden}; +use single_clustering::network::CSRNetwork; + +/// Clusters `graph` inside a rayon pool of exactly `threads` workers. +fn labels_with_threads(graph: &CSRNetwork, config: &LeidenConfig, threads: usize) -> Vec { + let pool = rayon::ThreadPoolBuilder::new() + .num_threads(threads) + .build() + .expect("pool"); + pool.install(|| leiden(graph, config).unwrap().labels().to_vec()) +} + +fn graphs() -> Vec<(String, CSRNetwork)> { + let mut out = vec![("karate".to_string(), karate())]; + for (name, n_per, blocks, p_in, p_out, seed) in [ + ("sbm_small", 40, 5, 0.30, 0.02, 4u64), + ("sbm_mid", 80, 8, 0.25, 0.01, 11), + ("sbm_sparse", 60, 6, 0.12, 0.02, 19), + ] { + let (edges, _) = sbm(n_per, blocks, p_in, p_out, seed); + out.push(( + name.to_string(), + CSRNetwork::from_edges(n_per * blocks, &edges).unwrap(), + )); + } + out +} + +#[test] +fn labels_are_identical_across_thread_counts() { + let configs = [ + ("rb_1.0", ObjectiveKind::Rb { resolution: 1.0 }), + ("rb_0.5", ObjectiveKind::Rb { resolution: 0.5 }), + ("cpm_0.1", ObjectiveKind::Cpm { resolution: 0.1 }), + ]; + + for (gname, graph) in graphs() { + for (cname, objective) in configs { + for seed in [1u64, 42] { + let config = LeidenConfig { + objective, + seed: Some(seed), + ..Default::default() + }; + let reference = labels_with_threads(&graph, &config, 1); + for threads in [2usize, 4, 8, 16] { + let got = labels_with_threads(&graph, &config, threads); + assert_eq!( + got, reference, + "{gname}/{cname}/seed {seed}: {threads} threads disagreed with 1" + ); + } + } + } + } +} + +/// Refinement randomness is the part most likely to depend on scheduling, so exercise it +/// specifically — including the greedy `0.0` case and a strongly exploratory one. +#[test] +fn randomised_refinement_is_thread_independent() { + let (edges, _) = sbm(50, 6, 0.28, 0.02, 7); + let graph = CSRNetwork::from_edges(300, &edges).unwrap(); + + for randomness in [0.0, 0.01, 0.5] { + let config = LeidenConfig { + refine_randomness: randomness, + seed: Some(5), + ..Default::default() + }; + let reference = labels_with_threads(&graph, &config, 1); + for threads in [2usize, 8, 16] { + assert_eq!( + labels_with_threads(&graph, &config, threads), + reference, + "randomness {randomness}: {threads} threads disagreed with 1" + ); + } + } +} From adea1d6547d4d817fa41daa9b100bf97c6154893 Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 24 Aug 2026 01:38:45 +0200 Subject: [PATCH 18/20] refactor: cut dead code and duplication - neighborhood: 625 -> 252 lines. Dropped 21 println!s from library code, the per-call rayon ThreadPool that only ever matched the default one, and ~180 lines duplicated between the kiddo and hnsw paths. The kd-tree path was also writing *squared* distances into `distances` where hnsw wrote real ones; both are real distances now. Connectivities are bit-identical either way. - grouping: 255 -> 58 lines. `NetworkGrouping` abstracted exactly one type and 10 of its 12 methods were unreachable. Gone; `aggregate` takes `&VectorGrouping`. - hnsw_rs `simdeez_f` is now x86-only. anndists imports simdeez::{avx2,sse2} unguarded, so it could not build on aarch64 at all - `cargo test --all-features` now works on Apple Silicon. - shared test fixtures behind a `testdata` feature instead of two copies that had already started to drift. - dropped the unused num-traits dep, `collect_constrained`, a no-op `free.clear()`, an `#[allow(unused_imports)]`, and an index loop that never needed to be one. - refine: one body for the parallel and sequential paths instead of two. --- Cargo.lock | 2 +- Cargo.toml | 13 +- src/community_search/leiden/local_move.rs | 5 +- src/community_search/leiden/partition.rs | 37 +- src/community_search/leiden/refine.rs | 84 ++- src/lib.rs | 5 +- src/neighborhood/mod.rs | 672 +++++----------------- src/network/csr_network.rs | 6 +- src/network/grouping.rs | 259 +-------- tests/common/mod.rs | 118 +--- 10 files changed, 244 insertions(+), 957 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 848b2ee..4809e56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1257,11 +1257,11 @@ dependencies = [ "kiddo", "nalgebra-sparse", "ndarray", - "num-traits", "rand", "rand_chacha", "rayon", "serde_json", + "single-clustering", "single-utilities", ] diff --git a/Cargo.toml b/Cargo.toml index 6df1f14..4f84b8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,13 +18,14 @@ knn = ["dep:hnsw_rs", "dep:kiddo", "dep:ndarray"] # Multi-threaded refinement. Off by default until local moving is parallel too, since # refinement alone is worth about 1.25x. parallel = [] +# Shared test fixtures, so unit tests and integration tests use one copy. Not public API. +testdata = [] # Spatial neighbour graphs are always available: the uniform-grid index they use has no # dependencies, so there is no build to opt out of. [dependencies] anyhow = "1.0.100" nalgebra-sparse = "0.10.0" -num-traits = "0.2.19" rayon = "1.10.0" single-utilities = "0.8.6" rand = "0.9.0" @@ -32,13 +33,21 @@ rand_chacha = { version = "0.9.0" } kiddo = { version = "5.2.2", optional = true } ndarray = { version = "0.16.1", features = ["rayon"], optional = true } -hnsw_rs = { version = "0.3.2", features = ["simdeez_f"], optional = true } delaunator = "1.1.0" [dev-dependencies] +single-clustering = { path = ".", default-features = false, features = ["testdata"] } serde_json = "1.0" criterion = { version = "0.5", features = ["html_reports"] } [[bench]] name = "leiden" harness = false + +# simdeez_f is x86-only: anndists imports simdeez::{avx2,sse2} unguarded, so it cannot +# compile on aarch64. Keep the SIMD where it works, drop it where it doesn't. +[target.'cfg(target_arch = "x86_64")'.dependencies] +hnsw_rs = { version = "0.3.2", features = ["simdeez_f"], optional = true } + +[target.'cfg(not(target_arch = "x86_64"))'.dependencies] +hnsw_rs = { version = "0.3.2", optional = true } diff --git a/src/community_search/leiden/local_move.rs b/src/community_search/leiden/local_move.rs index cf27017..b91a204 100644 --- a/src/community_search/leiden/local_move.rs +++ b/src/community_search/leiden/local_move.rs @@ -9,8 +9,6 @@ use rand_chacha::ChaCha8Rng; use crate::community_search::leiden::objective::{InsertContext, Objective}; -#[allow(unused_imports)] -use crate::community_search::leiden::partition::NeighborWeights; use crate::community_search::leiden::partition::{MoveScratch, Partition}; use crate::network::CSRNetwork; @@ -77,8 +75,7 @@ pub fn local_move( None => true, }; - for i in 0..scratch.weights.touched().len() { - let c = scratch.weights.touched()[i]; + for &c in scratch.weights.touched() { if c == old || !fits(partition, c) { continue; } diff --git a/src/community_search/leiden/partition.rs b/src/community_search/leiden/partition.rs index 3dd14e8..1f4cf6c 100644 --- a/src/community_search/leiden/partition.rs +++ b/src/community_search/leiden/partition.rs @@ -13,7 +13,7 @@ use rand::seq::SliceRandom; use rand_chacha::ChaCha8Rng; use crate::network::CSRNetwork; -use crate::network::grouping::{NetworkGrouping, VectorGrouping}; +use crate::network::grouping::VectorGrouping; /// Membership value for a node that has been removed from its community. /// @@ -52,7 +52,7 @@ impl Partition { /// Creates a partition where every node is alone in its own community. pub fn singleton(graph: &CSRNetwork) -> Self { let n = graph.node_count(); - let mut p = Self { + Self { membership: (0..n as u32).collect(), size: vec![1; n], weight: (0..n).map(|v| graph.node_weight(v)).collect(), @@ -62,10 +62,7 @@ impl Partition { free: Vec::new(), total_weight: graph.total_weight(), total_node_weight: graph.total_node_weight(), - }; - // no nodes, no communities - p.free.clear(); - p + } } /// Creates a partition from an explicit membership vector. @@ -439,34 +436,6 @@ impl NeighborWeights { &self.touched } - /// Like [`collect`](Self::collect), but only counts neighbours that share the node's - /// group in `constraint`. - /// - /// What keeps refinement inside the communities local moving found — a node can only - /// merge with refined communities inside its own working community. - pub fn collect_constrained( - &mut self, - graph: &CSRNetwork, - membership: &[u32], - node: usize, - constraint: &[u32], - ) -> &[usize] { - self.begin(); - let own = constraint[node]; - - for (u, w) in graph.neighbors(node) { - if u == node || constraint[u] != own { - continue; - } - let c = membership[u]; - if c == UNASSIGNED { - continue; - } - self.add(c as usize, w); - } - &self.touched - } - /// Weight from the last collected node to `community`, or `0.0` if untouched. #[inline] pub fn weight_to(&self, community: usize) -> f64 { diff --git a/src/community_search/leiden/refine.rs b/src/community_search/leiden/refine.rs index be9754e..1a7feb9 100644 --- a/src/community_search/leiden/refine.rs +++ b/src/community_search/leiden/refine.rs @@ -71,60 +71,44 @@ pub fn refine( } let total_weight = graph.total_weight(); - let mut labels = vec![0u32; n]; + + // Each community writes only its own members' labels, so the slices are disjoint. Refine + // one at a time and merge, which keeps that obvious whether or not it runs in parallel. + let refine_one = |m: &Vec| { + let mut sorted = m.clone(); + sorted.sort_unstable(); + let mut out = vec![0u32; sorted.len()]; + refine_into( + graph, + m, + &sorted, + objective, + total_weight, + &draws, + max_community_weight, + randomness, + &mut out, + ); + (sorted, out) + }; + let nonempty = members.iter().filter(|m| !m.is_empty()); #[cfg(feature = "parallel")] - { + let refined: Vec<(Vec, Vec)> = { use rayon::prelude::*; - // Each community writes only its own members' labels, so the output slices are - // disjoint. Collected per community and merged, which keeps that obvious. - let refined: Vec<(Vec, Vec)> = members - .par_iter() - .filter(|m| !m.is_empty()) - .map(|m| { - let mut sorted = m.clone(); - sorted.sort_unstable(); - let mut out = vec![0u32; sorted.len()]; - refine_into( - graph, - m, - &sorted, - objective, - total_weight, - &draws, - max_community_weight, - randomness, - &mut out, - ); - (sorted, out) - }) - .collect(); - for (sorted, out) in refined { - for (i, &g) in sorted.iter().enumerate() { - labels[g as usize] = out[i]; - } - } - } + nonempty + .collect::>() + .into_par_iter() + .map(refine_one) + .collect() + }; #[cfg(not(feature = "parallel"))] - { - for m in members.iter().filter(|m| !m.is_empty()) { - let mut sorted = m.clone(); - sorted.sort_unstable(); - let mut out = vec![0u32; sorted.len()]; - refine_into( - graph, - m, - &sorted, - objective, - total_weight, - &draws, - max_community_weight, - randomness, - &mut out, - ); - for (i, &g) in sorted.iter().enumerate() { - labels[g as usize] = out[i]; - } + let refined: Vec<(Vec, Vec)> = nonempty.map(refine_one).collect(); + + let mut labels = vec![0u32; n]; + for (sorted, out) in refined { + for (&g, &label) in sorted.iter().zip(out.iter()) { + labels[g as usize] = label; } } diff --git a/src/lib.rs b/src/lib.rs index 139351e..9955aba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,9 @@ pub mod error; pub mod neighborhood; pub mod network; pub mod spatial; -#[cfg(test)] -pub(crate) mod testdata; +#[cfg(any(test, feature = "testdata"))] +#[doc(hidden)] +pub mod testdata; pub mod community_search; diff --git a/src/neighborhood/mod.rs b/src/neighborhood/mod.rs index 42b3763..2994381 100644 --- a/src/neighborhood/mod.rs +++ b/src/neighborhood/mod.rs @@ -1,14 +1,8 @@ -//! # Neighborhood Module +//! kNN graph construction with Gaussian connectivity weights. //! -//! This module provides K-nearest neighbor (KNN) algorithms with Gaussian connectivity weighting -//! for clustering applications. It supports both KD-tree and HNSW-based approaches depending -//! on dataset size. -//! -//! ## Key Features -//! - Adaptive algorithm selection (KD-tree for small datasets, HNSW for large datasets) -//! - Gaussian connectivity weighting for community detection -//! - Parallel processing with optimized memory usage -//! - CSR matrix output format for efficient sparse matrix operations +//! Two backends: an exact kd-tree for small inputs, approximate HNSW for large ones. +//! [`knn_arrayd_adaptive`] picks between them. Both produce the same pair of matrices — +//! distances, and the Gaussian connectivities `scanpy` clusters on. use hnsw_rs::{ hnsw::{Hnsw, Neighbour}, @@ -19,35 +13,19 @@ use nalgebra_sparse::{CooMatrix, CsrMatrix}; use ndarray::ArrayViewD; use rayon::prelude::*; use single_utilities::traits::FloatOpsTS; -use std::time::Instant; -/// Result structure containing distance and connectivity matrices from KNN computation. -/// -/// The distances matrix contains raw distances to nearest neighbors, while the -/// connectivities matrix contains Gaussian-weighted connectivity values used -/// for community detection algorithms. +/// Distance and connectivity matrices from a kNN search. pub struct NeighborResult { - /// Sparse matrix of distances to k-nearest neighbors + /// Distances to each node's k nearest neighbours. pub distances: CsrMatrix, - /// Sparse matrix of Gaussian-weighted connectivity values + /// Gaussian-weighted connectivities, which is what clustering wants. pub connectivities: CsrMatrix, } -/// Computes K-nearest neighbors using KD-tree with Gaussian connectivity weighting. -/// -/// This function is optimized for smaller datasets (< 250k samples) and uses the kiddo -/// KD-tree implementation for efficient nearest neighbor search. It applies Gaussian -/// weighting to create connectivity matrices suitable for community detection. -/// -/// # Arguments -/// * `data` - 2D array view containing the input data points -/// * `k` - Number of nearest neighbors to find +/// Exact kNN via a kd-tree. Good up to ~250k points. /// -/// # Returns -/// `NeighborResult` containing distance and connectivity CSR matrices -/// -/// # Errors -/// Returns error if data is not 2D or has insufficient features for K-dimensional search +/// `D` must be a *squared* metric — [`kiddo::float::distance::SquaredEuclidean`] is the one +/// this was written for. pub fn knn_arrayd_kiddo_gaussian( data: ArrayViewD, k: u64, @@ -56,270 +34,98 @@ where T: FloatOpsTS + Send + Sync + 'static, D: DistanceMetric, { - if data.ndim() != 2 { - return Err(anyhow::anyhow!("The input array must have two dimensions.")); - } - - let shape = data.shape(); - let n_samples = shape[0]; - let n_features = shape[1]; - - if n_features < K { - return Err(anyhow::anyhow!( - "The data must have at least K features for KNN calculation" - )); - } - - let start_time = Instant::now(); + let n_samples = check_shape::(&data)?; - let kdtree_start = Instant::now(); let mut kdtree: kiddo::KdTree = kiddo::KdTree::new(); - - for i in 0..n_samples { - let mut point = [T::zero(); K]; - for (j, slot) in point.iter_mut().enumerate() { - *slot = *data.get([i, j]).unwrap_or(&T::zero()); - } - kdtree.add(&point, i as u64); - } - println!("KD-tree construction: {:?}", kdtree_start.elapsed()); - - let knn_search_start = Instant::now(); - let (knn_indices, knn_distances_sq) = - knn_search_large_batches::(&kdtree, data, n_samples, k); - println!("KNN search: {:?}", knn_search_start.elapsed()); - - let distance_matrix_start = Instant::now(); - let mut distance_triplets = Vec::with_capacity(n_samples * (k as usize + 1)); for i in 0..n_samples { - for (idx, &j) in knn_indices[i].iter().enumerate() { - distance_triplets.push((i, j, knn_distances_sq[i][idx])); - } + kdtree.add(&point_at::(&data, i), i as u64); } - println!( - "Distance matrix triplets: {:?}", - distance_matrix_start.elapsed() - ); - - let sigma_start = Instant::now(); - let sigmas: Vec = knn_distances_sq - .par_iter() - .map(|distances| { - let mut dist_wo_self: Vec = distances - .iter() - .filter(|&&d| d > T::zero()) - .copied() - .collect(); - - if dist_wo_self.is_empty() { - T::one() - } else { - let mid = dist_wo_self.len() / 2; - dist_wo_self.select_nth_unstable_by(mid, |a, b| { - a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal) - }); - dist_wo_self[mid].sqrt() - } - }) - .collect(); - println!("Sigma computation: {:?}", sigma_start.elapsed()); - - let connectivity_start = Instant::now(); - let min_weight = T::from_f64(1e-14).unwrap(); - let chunk_size = n_samples.div_ceil(rayon::current_num_threads()); - let connectivity_chunks: Vec> = (0..n_samples) + // kd-tree hands back squared distances; everything downstream wants real ones + let (indices, distances): (Vec>, Vec>) = (0..n_samples) .into_par_iter() - .chunks(chunk_size) - .map(|chunk| { - let mut local_triplets = Vec::with_capacity(chunk.len() * k as usize * 2); - - for i in chunk { - for (neighbor_idx, &j) in knn_indices[i].iter().enumerate().skip(1) { - if i <= j { - let dist_sq = knn_distances_sq[i][neighbor_idx]; - - let sigma_i = sigmas[i]; - let sigma_j = sigmas[j]; - let sigma_i_sq = sigma_i * sigma_i; - let sigma_j_sq = sigma_j * sigma_j; - - let den = sigma_i_sq + sigma_j_sq; - - if den > T::zero() { - let num = T::from(2).unwrap() * sigma_i * sigma_j; - let normalization = (num / den).sqrt(); - let exponential = (-dist_sq / den).exp(); - let weight = normalization * exponential; - - if weight > min_weight { - local_triplets.push((i, j, weight)); - if i != j { - local_triplets.push((j, i, weight)); - } - } - } - } - } - } - - local_triplets + .map(|i| { + kdtree + .nearest_n::(&point_at::(&data, i), (k + 1) as usize) + .into_iter() + .map(|h| (h.item as usize, h.distance.sqrt())) + .unzip() }) - .collect(); - - let mut connectivity_triplets = Vec::new(); - for chunk in connectivity_chunks { - connectivity_triplets.extend(chunk); - } - println!( - "Connectivity computation: {:?}", - connectivity_start.elapsed() - ); - - let matrix_creation_start = Instant::now(); - let distances = create_csr_from_triplets(n_samples, distance_triplets)?; - let connectivities = create_csr_from_triplets(n_samples, connectivity_triplets)?; - println!("CSR matrix creation: {:?}", matrix_creation_start.elapsed()); - - println!("Total KNN computation time: {:?}", start_time.elapsed()); - println!( - "Created distance matrix: {} x {}, nnz: {}", - distances.nrows(), - distances.ncols(), - distances.nnz() - ); - println!( - "Created connectivity matrix: {} x {}, nnz: {}", - connectivities.nrows(), - connectivities.ncols(), - connectivities.nnz() - ); + .unzip(); - Ok(NeighborResult { - distances, - connectivities, - }) + gaussian_result(n_samples, k, &indices, &distances) } -/// Creates a CSR matrix from coordinate triplets. -/// -/// Converts a list of (row, col, value) triplets into an efficient CSR sparse matrix -/// representation for subsequent matrix operations. -fn create_csr_from_triplets( - n: usize, - triplets: Vec<(usize, usize, T)>, -) -> anyhow::Result> +/// Approximate kNN via HNSW. Used past ~250k points, where the kd-tree stops being viable. +pub fn knn_arrayd_hnswlib_gaussian( + data: ArrayViewD, + k: u64, +) -> anyhow::Result> where - T: FloatOpsTS + 'static, + T: FloatOpsTS + Send + Sync + 'static, + hnsw_rs::prelude::DistL2: hnsw_rs::prelude::Distance, { - if triplets.is_empty() { - return Ok(CsrMatrix::zeros(n, n)); - } + let n_samples = check_shape::(&data)?; + let n_features = data.shape()[1]; + let (max_nb_connection, nb_layer, ef_construction, ef_search) = + get_optimal_hnsw_params(n_samples, k as usize); - let row_indices: Vec = triplets.iter().map(|(r, _, _)| *r).collect(); - let col_indices: Vec = triplets.iter().map(|(_, c, _)| *c).collect(); - let values: Vec = triplets.into_iter().map(|(_, _, v)| v).collect(); + let mut hnsw = Hnsw::::new( + max_nb_connection, + n_samples, + nb_layer, + ef_construction, + DistL2, + ); + hnsw.set_extend_candidates(false); + hnsw.modify_level_scale(0.5); - let coo = CooMatrix::try_from_triplets(n, n, row_indices, col_indices, values) - .map_err(|e| anyhow::anyhow!("Failed to create COO matrix: {}", e))?; + let rows: Vec> = (0..n_samples) + .into_par_iter() + .map(|i| (0..n_features).map(|j| data[[i, j]]).collect()) + .collect(); + let slices: Vec<(&[T], usize)> = rows + .iter() + .enumerate() + .map(|(i, r)| (r.as_slice(), i)) + .collect(); + hnsw.parallel_insert_slice(&slices); + hnsw.set_searching_mode(true); - Ok(CsrMatrix::from(&coo)) + let hits: Vec> = hnsw.parallel_search(&rows, (k + 1) as usize, ef_search); + let (indices, distances): (Vec>, Vec>) = hits + .into_iter() + .map(|row| { + row.into_iter() + .map(|h| (h.d_id, T::from(h.distance).unwrap())) + .unzip() + }) + .unzip(); + + gaussian_result(n_samples, k, &indices, &distances) } -/// Performs KNN search in large batches to optimize memory usage. -/// -/// This function processes KNN queries in batches with controlled parallelism -/// to reduce memory bandwidth contention and improve performance on large datasets. -pub fn knn_search_large_batches( - kdtree: &kiddo::KdTree, +/// Picks the kd-tree below 250k points and HNSW above it. +pub fn knn_arrayd_adaptive( data: ArrayViewD, - n_samples: usize, k: u64, -) -> (Vec>, Vec>) +) -> anyhow::Result> where T: FloatOpsTS + Send + Sync + 'static, D: DistanceMetric, + hnsw_rs::prelude::DistL2: hnsw_rs::prelude::Distance, { - // Use fewer threads to reduce memory bandwidth contention - // Rule of thumb: Use ~1 thread per memory channel (typically 2-8 for modern CPUs) - let memory_threads = std::cmp::min(64, rayon::current_num_threads()); - let chunk_size = n_samples.div_ceil(memory_threads); - - println!( - "Using {} threads with chunk size {} to reduce memory contention", - memory_threads, chunk_size - ); - - // Process with controlled parallelism - let results: Vec, Vec)>> = rayon::ThreadPoolBuilder::new() - .num_threads(memory_threads) - .build() - .unwrap() - .install(|| { - (0..n_samples) - .collect::>() - .par_chunks(chunk_size) - .enumerate() - .map(|(batch_idx, chunk)| { - let batch_start = Instant::now(); - let mut batch_results = Vec::with_capacity(chunk.len()); - - for &i in chunk { - // Build query - let mut query = [T::zero(); K]; - for (j, slot) in query.iter_mut().enumerate() { - *slot = *data.get([i, j]).unwrap_or(&T::zero()); - } - - // Search - let neighbors = kdtree.nearest_n::(&query, (k + 1) as usize); - - // Collect results - let mut indices = Vec::with_capacity(neighbors.len()); - let mut distances = Vec::with_capacity(neighbors.len()); - - for neighbor in neighbors { - indices.push(neighbor.item as usize); - distances.push(neighbor.distance); - } - - batch_results.push((indices, distances)); - } - - let batch_time = batch_start.elapsed(); - println!( - "Batch {} took {:?} ({:.2} µs per query)", - batch_idx, - batch_time, - batch_time.as_micros() as f64 / chunk.len() as f64 - ); - - batch_results - }) - .collect() - }); - - // Flatten results - let mut knn_indices = Vec::with_capacity(n_samples); - let mut knn_distances = Vec::with_capacity(n_samples); + const HNSW_THRESHOLD: usize = 250_000; + let n_samples = check_shape::(&data)?; - for batch in results { - for (indices, distances) in batch { - knn_indices.push(indices); - knn_distances.push(distances); - } + if n_samples > HNSW_THRESHOLD { + knn_arrayd_hnswlib_gaussian::(data, k) + } else { + knn_arrayd_kiddo_gaussian::(data, k) } - - (knn_indices, knn_distances) } -/// Calculates optimal HNSW parameters based on dataset size and k value. -/// -/// Returns tuned parameters for HNSW construction that balance search quality -/// and performance based on the number of samples and desired neighbors. -/// -/// # Returns -/// Tuple of (max_nb_connection, nb_layer, ef_construction, ef_search) +/// HNSW parameters by dataset size, tuned to land near PyNNDescent's recall. pub fn get_optimal_hnsw_params(n_samples: usize, k: usize) -> (usize, usize, usize, usize) { let max_nb_connection = match n_samples { n if n < 10_000 => 16, @@ -327,299 +133,125 @@ pub fn get_optimal_hnsw_params(n_samples: usize, k: usize) -> (usize, usize, usi n if n < 1_000_000 => 32, _ => 48, }; - let nb_layer = 16.min((n_samples as f32).ln().trunc() as usize); - let ef_construction = match n_samples { n if n < 10_000 => 100, - n if n < 100_000 => 200, n if n < 1_000_000 => 200, n if n < 2_500_000 => 300, _ => 400, }; - - // ef_search: based on k - let ef_search = (k * 2).clamp(30, 200); - - (max_nb_connection, nb_layer, ef_construction, ef_search) + ( + max_nb_connection, + nb_layer, + ef_construction, + (k * 2).clamp(30, 200), + ) } -/// Computes K-nearest neighbors using HNSW with Gaussian connectivity weighting. -/// -/// This function is optimized for larger datasets (>= 250k samples) and uses the -/// HNSW (Hierarchical Navigable Small World) algorithm for approximate nearest -/// neighbor search with high performance and good recall. -/// -/// # Arguments -/// * `data` - 2D array view containing the input data points -/// * `k` - Number of nearest neighbors to find -/// -/// # Returns -/// `NeighborResult` containing distance and connectivity CSR matrices -pub fn knn_arrayd_hnswlib_gaussian( - data: ArrayViewD, - k: u64, -) -> anyhow::Result> -where - T: FloatOpsTS + Send + Sync + 'static, - hnsw_rs::prelude::DistL2: hnsw_rs::prelude::Distance, -{ +fn check_shape(data: &ArrayViewD) -> anyhow::Result { if data.ndim() != 2 { return Err(anyhow::anyhow!("The input array must have two dimensions.")); } - - let shape = data.shape(); - let n_samples = shape[0]; - let n_features = shape[1]; - - if n_features < K { + if data.shape()[1] < K { return Err(anyhow::anyhow!( "The data must have at least K features for KNN calculation" )); } + Ok(data.shape()[0]) +} - let start_time = Instant::now(); - - // Calculate HNSW parameters to match PyNNDescent behavior - // PyNNDescent: n_trees = min(64, 5 + round(sqrt(n_obs) / 20.0)) - // PyNNDescent: n_iters = max(5, round(log2(n_obs))) - - // Based on the example, they use max_nb_connection = 48 for 1M points - // and nb_layer = 16.min((nb_elem as f32).ln().trunc() as usize) - let (max_nb_connection, nb_layer, ef_construction, ef_search) = - get_optimal_hnsw_params(n_samples, k as usize); - - println!( - "HNSW params: max_nb_connection={}, nb_layer={}, ef_construction={}, ef_search={}", - max_nb_connection, nb_layer, ef_construction, ef_search - ); - - let hnsw_start = Instant::now(); - - let mut hnsw = Hnsw::::new( - max_nb_connection, - n_samples, - nb_layer, - ef_construction, - DistL2, - ); - - hnsw.set_extend_candidates(false); - hnsw.modify_level_scale(0.5); - - if let Some(slice) = data.as_slice() { - let data_slices: Vec<(&[T], usize)> = (0..n_samples) - .map(|i| { - let start = i * n_features; - let end = start + n_features; - (&slice[start..end], i) - }) - .collect(); - - hnsw.parallel_insert_slice(&data_slices); - } else { - let data_vecs: Vec<(Vec, usize)> = (0..n_samples) - .into_par_iter() - .map(|i| { - let point: Vec = (0..n_features).map(|j| data[[i, j]]).collect(); - (point, i) - }) - .collect(); - - let data_slices: Vec<(&[T], usize)> = data_vecs - .iter() - .map(|(vec, idx)| (vec.as_slice(), *idx)) - .collect(); - - hnsw.parallel_insert_slice(&data_slices); +fn point_at(data: &ArrayViewD, i: usize) -> [T; K] { + let mut p = [T::zero(); K]; + for (j, slot) in p.iter_mut().enumerate() { + *slot = *data.get([i, j]).unwrap_or(&T::zero()); } + p +} - println!("HNSW construction: {:?}", hnsw_start.elapsed()); - - hnsw.set_searching_mode(true); - - let knn_search_start = Instant::now(); - - let queries: Vec> = (0..n_samples) - .map(|i| (0..n_features).map(|j| data[[i, j]]).collect()) - .collect(); - - let knn_results: Vec> = - hnsw.parallel_search(&queries, (k + 1) as usize, ef_search); - - let (knn_indices, knn_distances): (Vec>, Vec>) = knn_results - .into_iter() - .map(|neighbors| { - let mut indices = Vec::with_capacity(neighbors.len()); - let mut distances = Vec::with_capacity(neighbors.len()); - - for neighbor in neighbors { - indices.push(neighbor.d_id); - distances.push(T::from(neighbor.distance).unwrap()); - } - - (indices, distances) - }) - .unzip(); - - println!("KNN search: {:?}", knn_search_start.elapsed()); - - let distance_matrix_start = Instant::now(); +/// Turns kNN hits into the two output matrices. +/// +/// The connectivity kernel is scanpy's: each node gets a bandwidth `sigma` from the median +/// distance to its neighbours, and an edge is weighted +/// `sqrt(2·σi·σj / (σi² + σj²)) · exp(-d² / (σi² + σj²))`. +fn gaussian_result( + n_samples: usize, + k: u64, + indices: &[Vec], + distances: &[Vec], +) -> anyhow::Result> +where + T: FloatOpsTS + Send + Sync + 'static, +{ let mut distance_triplets = Vec::with_capacity(n_samples * (k as usize + 1)); for i in 0..n_samples { - for (idx, &j) in knn_indices[i].iter().enumerate() { - distance_triplets.push((i, j, knn_distances[i][idx])); + for (slot, &j) in indices[i].iter().enumerate() { + distance_triplets.push((i, j, distances[i][slot])); } } - println!( - "Distance matrix triplets: {:?}", - distance_matrix_start.elapsed() - ); - let sigma_start = Instant::now(); - let sigmas: Vec = knn_distances + let sigmas: Vec = distances .par_iter() - .map(|distances| { - let mut dist_wo_self: Vec = distances - .iter() - .filter(|&&d| d > T::zero()) - .copied() - .collect(); - - if dist_wo_self.is_empty() { - T::one() - } else { - let mid = dist_wo_self.len() / 2; - dist_wo_self.select_nth_unstable_by(mid, |a, b| { - a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal) - }); - dist_wo_self[mid] + .map(|row| { + let mut nonzero: Vec = row.iter().filter(|&&d| d > T::zero()).copied().collect(); + if nonzero.is_empty() { + return T::one(); } + let mid = nonzero.len() / 2; + nonzero.select_nth_unstable_by(mid, |a, b| { + a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal) + }); + nonzero[mid] }) .collect(); - println!("Sigma computation: {:?}", sigma_start.elapsed()); - let connectivity_start = Instant::now(); let min_weight = T::from_f64(1e-14).unwrap(); - let chunk_size = n_samples.div_ceil(rayon::current_num_threads()); - - let connectivity_chunks: Vec> = (0..n_samples) + let two = T::from(2).unwrap(); + let connectivity_triplets: Vec<(usize, usize, T)> = (0..n_samples) .into_par_iter() - .chunks(chunk_size) - .map(|chunk| { - let mut local_triplets = Vec::with_capacity(chunk.len() * k as usize * 2); - - for i in chunk { - for (neighbor_idx, &j) in knn_indices[i].iter().enumerate().skip(1) { - if i <= j { - let dist = knn_distances[i][neighbor_idx]; - let dist_sq = dist * dist; - - let sigma_i = sigmas[i]; - let sigma_j = sigmas[j]; - let sigma_i_sq = sigma_i * sigma_i; - let sigma_j_sq = sigma_j * sigma_j; - - let den = sigma_i_sq + sigma_j_sq; - - if den > T::zero() { - let num = T::from(2).unwrap() * sigma_i * sigma_j; - let normalization = (num / den).sqrt(); - let exponential = (-dist_sq / den).exp(); - let weight = normalization * exponential; - - if weight > min_weight { - local_triplets.push((i, j, weight)); - if i != j { - local_triplets.push((j, i, weight)); - } - } - } + .fold(Vec::new, |mut acc, i| { + // skip(1) drops the self hit; `i <= j` keeps each pair once + for (slot, &j) in indices[i].iter().enumerate().skip(1) { + if i > j { + continue; + } + let d = distances[i][slot]; + let den = sigmas[i] * sigmas[i] + sigmas[j] * sigmas[j]; + if den <= T::zero() { + continue; + } + let weight = (two * sigmas[i] * sigmas[j] / den).sqrt() * (-(d * d) / den).exp(); + if weight > min_weight { + acc.push((i, j, weight)); + if i != j { + acc.push((j, i, weight)); } } } - - local_triplets + acc }) - .collect(); - - let mut connectivity_triplets = Vec::new(); - for chunk in connectivity_chunks { - connectivity_triplets.extend(chunk); - } - println!( - "Connectivity computation: {:?}", - connectivity_start.elapsed() - ); - - let matrix_creation_start = Instant::now(); - let distances = create_csr_from_triplets(n_samples, distance_triplets)?; - let connectivities = create_csr_from_triplets(n_samples, connectivity_triplets)?; - println!("CSR matrix creation: {:?}", matrix_creation_start.elapsed()); - - println!("Total KNN computation time: {:?}", start_time.elapsed()); - println!( - "Created distance matrix: {} x {}, nnz: {}", - distances.nrows(), - distances.ncols(), - distances.nnz() - ); - println!( - "Created connectivity matrix: {} x {}, nnz: {}", - connectivities.nrows(), - connectivities.ncols(), - connectivities.nnz() - ); + .reduce(Vec::new, |mut a, b| { + a.extend(b); + a + }); Ok(NeighborResult { - distances, - connectivities, + distances: csr_from_triplets(n_samples, distance_triplets)?, + connectivities: csr_from_triplets(n_samples, connectivity_triplets)?, }) } -/// Adaptive KNN algorithm that automatically selects the best approach. -/// -/// This function automatically chooses between KD-tree (for smaller datasets) -/// and HNSW (for larger datasets) based on a predefined threshold to optimize -/// performance across different dataset sizes. -/// -/// # Arguments -/// * `data` - 2D array view containing the input data points -/// * `k` - Number of nearest neighbors to find -/// -/// # Returns -/// `NeighborResult` containing distance and connectivity CSR matrices -pub fn knn_arrayd_adaptive( - data: ArrayViewD, - k: u64, -) -> anyhow::Result> +fn csr_from_triplets(n: usize, triplets: Vec<(usize, usize, T)>) -> anyhow::Result> where - T: FloatOpsTS + Send + Sync + 'static, - D: DistanceMetric, - hnsw_rs::prelude::DistL2: hnsw_rs::prelude::Distance, + T: FloatOpsTS + 'static, { - if data.ndim() != 2 { - return Err(anyhow::anyhow!("The input array must have two dimensions.")); + if triplets.is_empty() { + return Ok(CsrMatrix::zeros(n, n)); } + let rows: Vec = triplets.iter().map(|(r, _, _)| *r).collect(); + let cols: Vec = triplets.iter().map(|(_, c, _)| *c).collect(); + let values: Vec = triplets.into_iter().map(|(_, _, v)| v).collect(); - let shape = data.shape(); - let n_samples = shape[0]; - - const HNSW_THRESHOLD: usize = 250_000; - - println!( - "Dataset has {} samples. Using {} for KNN search.", - n_samples, - if n_samples > HNSW_THRESHOLD { - "HNSW" - } else { - "KD-tree" - } - ); - - if n_samples > HNSW_THRESHOLD { - knn_arrayd_hnswlib_gaussian::(data, k) - } else { - knn_arrayd_kiddo_gaussian::(data, k) - } + let coo = CooMatrix::try_from_triplets(n, n, rows, cols, values) + .map_err(|e| anyhow::anyhow!("Failed to create COO matrix: {}", e))?; + Ok(CsrMatrix::from(&coo)) } diff --git a/src/network/csr_network.rs b/src/network/csr_network.rs index 4ee8292..60a32d2 100644 --- a/src/network/csr_network.rs +++ b/src/network/csr_network.rs @@ -30,7 +30,7 @@ use nalgebra_sparse::CsrMatrix; use single_utilities::traits::FloatOpsTS; use crate::error::{ClusteringError, Result}; -use crate::network::grouping::NetworkGrouping; +use crate::network::grouping::VectorGrouping; /// Largest addressable node id. `u32` adjacency caps the graph at ~4.29 billion nodes. pub const MAX_NODES: usize = u32::MAX as usize; @@ -513,7 +513,7 @@ impl CSRNetwork { /// between groups becomes an ordinary edge. `total_weight` and `Σ strength` are both /// preserved exactly, so quality doesn't change — which is what lets the multilevel scheme /// optimize one objective across levels. - pub fn aggregate(&self, grouping: &G) -> Self { + pub fn aggregate(&self, grouping: &VectorGrouping) -> Self { let n = self.node_count(); let n_groups = grouping.group_count(); @@ -738,7 +738,7 @@ impl std::fmt::Display for CSRNetwork { #[cfg(test)] mod tests { use super::*; - use crate::network::grouping::{NetworkGrouping, VectorGrouping}; + use crate::network::grouping::VectorGrouping; fn triangle_with_loop() -> CSRNetwork { // triangle 0-1-2 (unit weights) plus a self-loop of weight 3 on node 0 diff --git a/src/network/grouping.rs b/src/network/grouping.rs index 28d38fc..0bb4b1a 100644 --- a/src/network/grouping.rs +++ b/src/network/grouping.rs @@ -1,255 +1,58 @@ -//! # Network Grouping Module -//! -//! This module provides abstractions for representing and manipulating node groupings -//! in networks. It's essential for clustering algorithms where nodes need to be -//! assigned to communities or clusters. -//! -//! ## Key Components -//! - `NetworkGrouping` trait - Interface for node-to-group assignments -//! - `VectorGrouping` - Efficient vector-based implementation -//! - Group operations: merge, normalize, bulk updates +//! Node-to-group assignments, as produced by clustering and consumed by +//! [`CSRNetwork::aggregate`](crate::network::CSRNetwork::aggregate). -use std::fmt::Debug; - -/// Trait for representing node-to-group assignments in networks. -/// -/// This trait provides a common interface for different grouping implementations -/// used in clustering algorithms. It supports operations like group assignment, -/// merging, and normalization essential for community detection. -pub trait NetworkGrouping: Debug + Send + Sync { - /// Creates a grouping where each node is in its own isolated group. - fn create_isolated(node_count: usize) -> Self; - - /// Creates a grouping where all nodes are in a single unified group. - fn create_unified(node_count: usize) -> Self; - - /// Creates a grouping from an array of group assignments. - fn from_assignments(assignments: &[usize]) -> Self; - - /// Returns a vector of vectors, where each inner vector contains the nodes in that group. - fn get_group_members(&self) -> Vec>; - - /// Gets the group ID for a given node. - fn get_group(&self, node: usize) -> usize; - - /// Gets the group IDs for a range of nodes. - fn get_groups_range(&self, range: std::ops::Range) -> &[usize]; - - /// Sets the group for a given node. - fn set_group(&mut self, node: usize, group: usize); - - /// Sets groups for multiple nodes at once. - fn set_groups_bulk(&mut self, nodes: &[usize], group: usize); - - /// Gets the total number of nodes. - fn node_count(&self) -> usize; - - /// Gets the total number of groups. - fn group_count(&self) -> usize; - - /// Renumbers groups to eliminate gaps in group IDs. - fn normalize_groups(&mut self); - - /// Merges groups based on a higher-level grouping scheme. - /// - /// This is used in multilevel clustering where groups themselves are - /// further grouped into larger communities. - fn merge(&mut self, arrangement: &G) { - for node in 0..self.node_count() { - let current_group = self.get_group(node); - let new_group = arrangement.get_group(current_group); - self.set_group(node, new_group); - } - self.normalize_groups(); - } - - /// Resets all nodes to group 0, effectively creating a single unified group. - fn clear(&mut self) { - for i in 0..self.node_count() { - self.set_group(i, 0); - } - - self.normalize_groups(); - } -} - -/// Vector-based implementation of NetworkGrouping. -/// -/// This implementation uses a simple vector to store node-to-group assignments, -/// providing efficient access and updates. It includes caching for group sizes -/// to optimize frequent size queries in clustering algorithms. -/// -/// # Performance Features -/// - O(1) group assignment and lookup -/// - Cached group sizes with lazy updates -/// - Bulk operations for efficiency -#[derive(Debug, Clone, Default)] +/// A labelling of nodes into groups, with ids renumbered consecutively from 0. +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct VectorGrouping { - /// Vector storing the group assignment for each node assignments: Vec, - /// Total number of distinct groups group_count: usize, - /// Cache for frequently accessed group sizes - group_sizes: Vec, - /// Flag indicating if group_sizes cache needs updating - needs_size_update: bool, } impl VectorGrouping { - /// Updates the cached group sizes if needed. - /// - /// This method is called automatically when group sizes are accessed - /// to ensure the cache is current. - #[inline] - fn update_group_sizes(&mut self) { - if !self.needs_size_update { - return; - } - - self.group_sizes = vec![0; self.group_count]; - for &group in &self.assignments { - self.group_sizes[group] += 1; - } - self.needs_size_update = false; - } - - /// Gets the size of a specific group. - /// - /// Updates the size cache if necessary before returning the result. - #[inline] - pub fn get_group_size(&mut self, group: usize) -> usize { - self.update_group_sizes(); - self.group_sizes[group] - } - - /// Returns an iterator over groups with their sizes. - /// - /// Yields (group_id, group_size) pairs for all groups. - pub fn iter_group_sizes(&mut self) -> impl Iterator + '_ { - self.update_group_sizes(); - self.group_sizes.iter().copied().enumerate() - } -} - -impl NetworkGrouping for VectorGrouping { - fn create_isolated(node_count: usize) -> Self { - let assignments = (0..node_count).collect(); - Self { - assignments, - group_count: node_count, - group_sizes: vec![1; node_count], - needs_size_update: false, + /// Builds a grouping from raw assignments, renumbering to close any gaps. + pub fn from_assignments(assignments: &[usize]) -> Self { + let slots = assignments.iter().copied().max().map_or(0, |g| g + 1); + let mut seen = vec![false; slots]; + for &g in assignments { + seen[g] = true; + } + + let mut new_id = vec![usize::MAX; slots]; + let mut next = 0; + for (id, &used) in new_id.iter_mut().zip(&seen) { + if used { + *id = next; + next += 1; + } } - } - fn create_unified(node_count: usize) -> Self { Self { - assignments: vec![0; node_count], - group_count: usize::from(node_count > 0), - group_sizes: vec![node_count], - needs_size_update: false, - } - } - - fn from_assignments(input: &[usize]) -> Self { - let mut max_group = 0; - let assignments = input - .iter() - .map(|&group| { - max_group = max_group.max(group); - group - }) - .collect(); - - let mut grouping = Self { - assignments, - group_count: max_group + 1, - group_sizes: Vec::new(), - needs_size_update: true, - }; - grouping.normalize_groups(); - grouping - } - - fn get_group_members(&self) -> Vec> { - let mut groups = vec![Vec::new(); self.group_count]; - - // Pre-allocate space based on average group size - let avg_size = self.assignments.len() / self.group_count; - for group in groups.iter_mut() { - group.reserve(avg_size); - } - - for (node, &group) in self.assignments.iter().enumerate() { - groups[group].push(node); + assignments: assignments.iter().map(|&g| new_id[g]).collect(), + group_count: next, } - groups } + /// The group a node belongs to. #[inline] - fn get_group(&self, node: usize) -> usize { + pub fn get_group(&self, node: usize) -> usize { self.assignments[node] } + /// Number of groups, all of them non-empty. #[inline] - fn get_groups_range(&self, range: std::ops::Range) -> &[usize] { - &self.assignments[range] - } - - #[inline] - fn set_group(&mut self, node: usize, group: usize) { - if self.assignments[node] != group { - self.assignments[node] = group; - self.group_count = self.group_count.max(group + 1); - self.needs_size_update = true; - } - } - - fn set_groups_bulk(&mut self, nodes: &[usize], group: usize) { - for &node in nodes { - self.assignments[node] = group; - } - self.group_count = self.group_count.max(group + 1); - self.needs_size_update = true; + pub fn group_count(&self) -> usize { + self.group_count } + /// Number of nodes. #[inline] - fn node_count(&self) -> usize { + pub fn node_count(&self) -> usize { self.assignments.len() } + /// The assignments, consecutive from 0. #[inline] - fn group_count(&self) -> usize { - self.group_count - } - - fn normalize_groups(&mut self) { - // Use original sequential approach for small datasets - let mut sizes = vec![0; self.group_count]; - for &group in &self.assignments { - sizes[group] += 1; - } - - let mut new_ids = Vec::with_capacity(self.group_count); - let mut next_id = 0; - - for size in sizes { - if size == 0 { - new_ids.push(usize::MAX); - } else { - new_ids.push(next_id); - next_id += 1; - } - } - - for group in self.assignments.iter_mut() { - let new_id = new_ids[*group]; - debug_assert!(new_id != usize::MAX, "Invalid group assignment"); - *group = new_id; - } - - self.group_count = next_id; - - self.needs_size_update = true; + pub fn assignments(&self) -> &[usize] { + &self.assignments } } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4bce6bf..889d7f6 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,57 +1,13 @@ -//! Graph fixtures and metrics shared by the integration tests. -//! -//! Included by several test binaries, each of which uses a different subset. -#![allow(dead_code)] +//! Test fixtures shared by the integration tests. Each binary uses a different subset. +#![allow(dead_code, unused_imports)] use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use single_clustering::network::CSRNetwork; -/// Edges of Zachary's karate club. -pub fn karate_edges() -> Vec<(usize, usize, f64)> { - // dense on purpose — one tuple per line is unreadable - #[rustfmt::skip] - const E: &[(usize, usize)] = &[ - (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 10), (0, 11), - (0, 12), (0, 13), (0, 17), (0, 19), (0, 21), (0, 31), (1, 2), (1, 3), (1, 7), (1, 13), - (1, 17), (1, 19), (1, 21), (1, 30), (2, 3), (2, 7), (2, 8), (2, 9), (2, 13), (2, 27), - (2, 28), (2, 32), (3, 7), (3, 12), (3, 13), (4, 6), (4, 10), (5, 6), (5, 10), (5, 16), - (6, 16), (8, 30), (8, 32), (8, 33), (9, 33), (13, 33), (14, 32), (14, 33), (15, 32), - (15, 33), (18, 32), (18, 33), (19, 33), (20, 32), (20, 33), (22, 32), (22, 33), - (23, 25), (23, 27), (23, 29), (23, 32), (23, 33), (24, 25), (24, 27), (24, 31), - (25, 31), (26, 29), (26, 33), (27, 33), (28, 31), (28, 33), (29, 32), (29, 33), - (30, 32), (30, 33), (31, 32), (31, 33), (32, 33), - ]; - E.iter().map(|&(a, b)| (a, b, 1.0)).collect() -} - -/// The karate club as a graph. -pub fn karate() -> CSRNetwork { - CSRNetwork::from_edges(34, &karate_edges()).unwrap() -} - -/// A stochastic block model with the given within/between edge probabilities. -pub fn sbm( - n_per: usize, - blocks: usize, - p_in: f64, - p_out: f64, - seed: u64, -) -> (Vec<(usize, usize, f64)>, Vec) { - let mut rng = ChaCha8Rng::seed_from_u64(seed); - let n = n_per * blocks; - let truth: Vec = (0..n).map(|i| i / n_per).collect(); - let mut edges = Vec::new(); - for i in 0..n { - for j in (i + 1)..n { - let p = if truth[i] == truth[j] { p_in } else { p_out }; - if rng.random::() < p { - edges.push((i, j, 1.0)); - } - } - } - (edges, truth) -} +pub use single_clustering::testdata::{ + disconnected_community_count, karate, karate_edges, nmi, sbm, +}; /// A varied set of graphs, including the degenerate shapes that tend to break assumptions. pub fn test_graphs() -> Vec<(String, CSRNetwork)> { @@ -158,67 +114,3 @@ pub fn adjusted_rand_index(a: &[usize], b: &[usize]) -> f64 { } (sum_ij - expected) / (max - expected) } - -/// Normalized mutual information between two labellings, in `[0, 1]`. -pub fn nmi(a: &[usize], b: &[usize]) -> f64 { - let n = a.len() as f64; - if n == 0.0 { - return 1.0; - } - let ka = a.iter().max().map_or(0, |m| m + 1); - let kb = b.iter().max().map_or(0, |m| m + 1); - let mut joint = vec![0.0f64; ka * kb]; - let (mut pa, mut pb) = (vec![0.0f64; ka], vec![0.0f64; kb]); - for i in 0..a.len() { - joint[a[i] * kb + b[i]] += 1.0; - pa[a[i]] += 1.0; - pb[b[i]] += 1.0; - } - let mut mi = 0.0; - for i in 0..ka { - for j in 0..kb { - let p = joint[i * kb + j] / n; - if p > 0.0 { - mi += p * (p / ((pa[i] / n) * (pb[j] / n))).ln(); - } - } - } - let h = |p: &[f64]| -> f64 { - -p.iter() - .filter(|&&x| x > 0.0) - .map(|&x| (x / n) * (x / n).ln()) - .sum::() - }; - let (ha, hb) = (h(&pa), h(&pb)); - if ha + hb == 0.0 { - 1.0 - } else { - 2.0 * mi / (ha + hb) - } -} - -/// Number of communities that are not internally connected. -pub fn disconnected_community_count(graph: &CSRNetwork, labels: &[usize]) -> usize { - let n = graph.node_count(); - let n_comms = labels.iter().max().map_or(0, |m| m + 1); - let mut seen = vec![false; n]; - let mut components = vec![0usize; n_comms]; - - for v in 0..n { - if seen[v] { - continue; - } - components[labels[v]] += 1; - let mut stack = vec![v]; - seen[v] = true; - while let Some(u) = stack.pop() { - for (w, _) in graph.neighbors(u) { - if !seen[w] && labels[w] == labels[u] { - seen[w] = true; - stack.push(w); - } - } - } - } - components.iter().filter(|&&c| c > 1).count() -} From f69c7da8b66cb2051cd59beef990120357d9d16b Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 24 Aug 2026 01:54:00 +0200 Subject: [PATCH 19/20] docs: cut the comments back to the facts Long doc blocks nobody reads, gone. Kept the one line that carries the finding, dropped the essay around it. src comments 1226 -> ~900 with nothing factual lost. The Delaunay research - Zahn's factor, squidpy/Giotto defaults, why Gabriel and RNG don't help, the Visium loader gotchas - moved to docs/spatial-graphs.md, where it can be read once rather than sat in a header. Also: README says 1.0 now, matching Cargo.toml. --- .github/workflows/ci.yml | 6 +- Cargo.toml | 13 +- README.md | 13 +- docs/spatial-graphs.md | 70 +++++++++ examples/evaluate.rs | 5 +- examples/phases.rs | 4 +- examples/real_data.rs | 16 +- examples/reorder.rs | 29 +--- examples/scaling_ceiling.rs | 9 +- examples/vs_igraph.rs | 6 +- src/clustering.rs | 6 +- src/community_search/leiden/local_move.rs | 35 ++--- src/community_search/leiden/mod.rs | 84 ++++------ src/community_search/leiden/objective.rs | 91 +++++------ src/community_search/leiden/partition.rs | 146 ++++++++---------- src/community_search/leiden/refine.rs | 79 ++++------ src/community_search/mod.rs | 5 +- src/error.rs | 23 +-- src/network/csr_network.rs | 179 ++++++++-------------- src/network/mod.rs | 9 +- src/spatial/banksy.rs | 108 +++++-------- src/spatial/combine.rs | 69 ++++----- src/spatial/delaunay.rs | 141 +++++------------ src/spatial/grid.rs | 33 ++-- src/spatial/lattice.rs | 123 ++++++--------- src/spatial/mod.rs | 26 +--- src/spatial/points.rs | 140 ++++++++--------- tests/banksy_reference.rs | 29 ++-- tests/invariants.rs | 17 +- tests/optimality.rs | 41 ++--- tests/properties.rs | 8 +- tests/reference.rs | 72 ++++----- tests/spatial_stability.rs | 61 +++----- tests/thread_invariance.rs | 12 +- 34 files changed, 696 insertions(+), 1012 deletions(-) create mode 100644 docs/spatial-graphs.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d17cb36..ed73d7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,14 +36,14 @@ jobs: - name: Test (release) run: cargo test --no-default-features --release - # the parallel path must give byte-identical results, so it needs its own run + # must give byte-identical results, so it needs its own run - name: Clippy (parallel) run: cargo clippy --no-default-features --features parallel --all-targets -- -D warnings - name: Test (parallel) run: cargo test --no-default-features --features parallel --release - # the #[ignore]d tests: scale runs and the exhaustive optimality sweep. ~11s total, and - # without this the HD-scale path and the Bell(12) optimality check never execute anywhere. + # the #[ignore]d tests: scale runs and the exhaustive optimality sweep, ~11s. Without this + # the HD-scale path and the Bell(12) check never run anywhere. scale: name: Scale and exhaustive runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 4f84b8b..163998e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,17 +11,14 @@ description = "A high-performance network clustering library implementing commun [features] default = ["knn"] -# k-nearest-neighbour graph construction from high-dimensional data. Split out so the -# clustering core can be built and tested without the HNSW/kd-tree stack, which does not -# compile on every target. +# kNN graph construction. Split out so the clustering core builds without the HNSW/kd-tree +# stack. Spatial graphs need no feature - the uniform-grid index has no dependencies. knn = ["dep:hnsw_rs", "dep:kiddo", "dep:ndarray"] -# Multi-threaded refinement. Off by default until local moving is parallel too, since -# refinement alone is worth about 1.25x. +# Multi-threaded refinement. Off until local moving is parallel too, since refinement alone is +# worth about 1.25x. parallel = [] -# Shared test fixtures, so unit tests and integration tests use one copy. Not public API. +# Shared test fixtures, so unit and integration tests use one copy. Not public API. testdata = [] -# Spatial neighbour graphs are always available: the uniform-grid index they use has no -# dependencies, so there is no build to opt out of. [dependencies] anyhow = "1.0.100" diff --git a/README.md b/README.md index eb756c4..f6d43c3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # single-clustering -⚠️ **Development Status**: This library is under active development. APIs may change between -versions; see the changelog for 0.7.0, which is a breaking rewrite of the Leiden core. +⚠️ **Development Status**: Under active development, APIs may change between versions. 1.0 +drops the `NetworkGrouping` trait and trims `VectorGrouping` to what `aggregate` actually +uses. A Rust library for community detection and graph clustering, focused on being correct, reproducible, and fast enough for single-cell-scale graphs. @@ -195,14 +196,14 @@ graphs. ```toml [dependencies] -single-clustering = "0.7" +single-clustering = "1.0" ``` The k-NN graph construction is behind the default-on `knn` feature. To build just the -clustering core — useful in CI, or on targets where the HNSW stack does not compile: +clustering core: ```toml -single-clustering = { version = "0.7", default-features = false } +single-clustering = { version = "1.0", default-features = false } ``` Multi-threaded refinement is behind an off-by-default `parallel` feature. It is off because @@ -210,7 +211,7 @@ local moving — the larger half of the work — is still sequential, so the gai rather than the several-x a fully parallel implementation would give: ```toml -single-clustering = { version = "0.7", features = ["parallel"] } +single-clustering = { version = "1.0", features = ["parallel"] } ``` Results are byte-identical regardless of thread count; `tests/thread_invariance.rs` asserts it diff --git a/docs/spatial-graphs.md b/docs/spatial-graphs.md new file mode 100644 index 0000000..b606106 --- /dev/null +++ b/docs/spatial-graphs.md @@ -0,0 +1,70 @@ +# Notes on spatial neighbour graphs + +Background for choices in `src/spatial/` that aren't obvious from the code. + +## Delaunay: why prune at all + +A triangulation covers the *convex hull*, so it invents edges wherever tissue isn't convex: +across ventricles and vessels, around concave boundaries, and between separate fragments on +the same section. Those edges are long, and joining two sides of a hole produces a +plausible-looking but meaningless domain. + +The parameter-free subgraphs don't fix it. Gabriel and relative-neighbourhood tests ask +whether other points lie near the edge, and the whole point of a hole is that nothing does, +so a hole-spanning edge passes. Measured on two detached fragments: Gabriel leaves 19 of 42 +bridges standing and drops 21% of genuine edges elsewhere; RNG drops 52%. Removing an +artefact edge needs a rule about length. + +They may still be worth adding as an option — MST ⊆ RNG ⊆ GG ⊆ Delaunay, both are always +connected, and Lingas (1994) extracts either from an existing triangulation in O(n). Two +things to get right: use the **open** exclusion region, since the closed variant disconnects +on ties and gridded coordinates are made of ties; and expect mean degree ~4 for Gabriel and +~2.56 for RNG against Delaunay's 6. + +## What other tools do + +- **squidpy** applies no pruning at all. `delaunay=True` returns the raw triangulation, hull + included. `radius` and `percentile` both default to off, and in 1.6.x a scalar `radius` is + silently ignored on the Delaunay path. +- **Giotto** is the only one that derives a cutoff automatically, using a global Tukey whisker + over all edge lengths. Being global, it fails where density varies: on a dense block beside + 24x sparser stroma it shatters the sparse side into ~570 components while barely touching + the dense one. + +That's the case for a local rule, and why `HullPruning::Adaptive` is the default. + +## Where the default factor of 2.0 comes from + +`calibrate_adaptive_factor` in `src/spatial/delaunay.rs` measures it: 2.0 is the largest +factor that fully separates two detached tissue fragments, which is the one unambiguous +requirement. It costs ~5% of edges on uniform-random points and less on real tissue, whose +cells pack more regularly than a Poisson process. + +It's also the canonical value. Zahn's 1971 inconsistent-edge criterion is the same shape — an +edge significantly larger than nearby edge weights on **both sides** — and he reports a factor +of 2 usually makes the separation apparent, with worked examples from 1.3 to 2.6. + +Two things it won't do. It can't clear a hole two or three cells across: that needs a factor +near 1.5, which drops ~16% of genuine edges everywhere, and at that width it's arguable +whether the cells either side are neighbours at all. And, as Zahn notes, it doesn't detect +one-way gradients however steep — density ramping smoothly across a section has no local +discontinuity to find. + +## Local scale is the 25th percentile, not the median + +A rim node's incident edges are mostly the spurious long ones, so its median is inflated by +exactly the artefact the rule is meant to catch. A low quantile reads the real local spacing. + +## Reading Visium data + +Two things to know before wiring up a loader, both checked against upstream: + +- Space Ranger ≥ 2.0 renamed `tissue_positions_list.csv` to `tissue_positions.csv` **and** + added a header row. Parse the header rather than assuming column positions — scanpy + branches on the filename to decide. +- `scanpy.read_visium` labels the two pixel columns the wrong way round, then selects them in + the wrong order. The errors cancel, so `obsm["spatial"]` really is `(x, y)`, but the names + in `obs` are swapped. Don't trust `pxl_row_in_fullres` / `pxl_col_in_fullres` if you read + those columns directly. + +Neither affects `array_row` / `array_col`, which is what `lattice_graph` wants. diff --git a/examples/evaluate.rs b/examples/evaluate.rs index 1750e71..bad43d5 100644 --- a/examples/evaluate.rs +++ b/examples/evaluate.rs @@ -1,8 +1,7 @@ //! Head-to-head evaluation against `leidenalg` on LFR benchmarks and large kNN graphs. //! -//! Reads graphs and reference results produced by the generator in `tools/`, runs our -//! algorithm on the same inputs, and reports NMI against ground truth, modularity, and wall -//! time for both. +//! Reads graphs and reference results from `tools/`, runs ours on the same inputs, and reports +//! NMI against ground truth, modularity and wall time for both. //! //! ```text //! cargo run --release --no-default-features --example evaluate -- diff --git a/examples/phases.rs b/examples/phases.rs index 7dc5f9a..7dcdb94 100644 --- a/examples/phases.rs +++ b/examples/phases.rs @@ -4,8 +4,8 @@ //! cargo run --release --no-default-features --example phases -- 1000000 //! ``` //! -//! Replicates the driver in `leiden::run_once` using the public API, so the phase split is -//! measured on exactly the work the real driver does. Answers "what is worth parallelising". +//! Replicates `leiden::run_once` through the public API, so the split is measured on exactly +//! the work the real driver does. Answers what's worth parallelising. use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/examples/real_data.rs b/examples/real_data.rs index aa072f3..7b540f1 100644 --- a/examples/real_data.rs +++ b/examples/real_data.rs @@ -5,14 +5,9 @@ //! cargo run --release --no-default-features --example real_data -- /tmp/pbmc3k //! ``` //! -//! Clusters the *same* connectivity matrix scanpy did, so any difference is the algorithm, -//! not graph construction. Reports: -//! -//! * cluster count vs resolution, ours against scanpy's -//! * agreement with scanpy's partition (ARI / NMI) -//! * agreement with the author cell-type annotation — the only number here that's about -//! biology rather than matching another implementation -//! * modularity and wall time +//! Clusters the *same* connectivity matrix scanpy did, so any difference is the algorithm +//! rather than graph construction. Reports cluster count vs resolution, agreement with +//! scanpy's partition and with the author annotations, modularity, and wall time. use single_clustering::community_search::leiden::{LeidenConfig, leiden, modularity}; use single_clustering::network::CSRNetwork; @@ -43,10 +38,7 @@ fn read_f32(path: &Path) -> Vec { .collect() } -/// Adjusted Rand Index: agreement between two partitions, corrected for chance. -/// -/// The standard measure for comparing clusterings against a reference labelling. 1.0 is exact -/// agreement, 0.0 is what random labelling would score. +/// Adjusted Rand Index. 1.0 is exact agreement, 0.0 is what random labelling scores. fn adjusted_rand_index(a: &[usize], b: &[usize]) -> f64 { let n = a.len() as f64; if n == 0.0 { diff --git a/examples/reorder.rs b/examples/reorder.rs index 26a09f0..7467c0f 100644 --- a/examples/reorder.rs +++ b/examples/reorder.rs @@ -4,20 +4,10 @@ //! cargo run --release --no-default-features --example reorder -- 1000000 //! ``` //! -//! The inner loop is a scatter-gather over CSR: every visited node reads `membership` and the -//! community aggregates at its neighbours' indices. If those indices are scattered, each is a -//! cache miss. Relabelling nodes so that neighbours sit near each other in memory changes no -//! arithmetic at all — the clustering must come out identical up to the permutation — so any -//! difference in wall time is pure locality. -//! -//! Two orderings are compared against whatever order the data arrived in: -//! -//! * **Morton (Z-order)** on coordinates — needs positions, so spatial data only, but nearly -//! free to compute. -//! * **BFS** over the graph — works for any graph, including expression k-NN where there are -//! no coordinates. -//! -//! # What it measured +//! The inner loop is a scatter-gather over CSR, so scattered neighbour indices are cache +//! misses. Relabelling so neighbours sit near each other changes no arithmetic — the +//! clustering must come out identical up to the permutation — so the wall-time difference is +//! pure locality. Morton needs coordinates, BFS works on any graph. //! //! ```text //! n morton bfs edge span (orig -> morton) @@ -25,14 +15,9 @@ //! 1M 1.13x 1.09x 27778 -> 701 //! ``` //! -//! Locality improves by a factor of ~40 and buys 13%. The gain grows with size — at 200k the -//! membership array is under a megabyte and still fits in L3, so there is nothing to fix — -//! but slowly, and extrapolates to only ~1.2x at 8M. -//! -//! So reordering is real but small, and it was ranked below parallelism on the strength of -//! these numbers rather than on a guess: parallel refinement alone is worth ~1.4x for -//! comparable effort. Kept here because the conclusion is scale-dependent and someone should -//! re-measure before believing it at 75M. +//! ~40x better locality buys 13%, and extrapolates to only ~1.2x at 8M. Real but small, which +//! is why parallelism was ranked above it. Scale-dependent, so re-measure before believing +//! this at 75M. use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/examples/scaling_ceiling.rs b/examples/scaling_ceiling.rs index abbee55..d3f242a 100644 --- a/examples/scaling_ceiling.rs +++ b/examples/scaling_ceiling.rs @@ -4,12 +4,9 @@ //! cargo run --release --no-default-features --example scaling_ceiling -- 500000 //! ``` //! -//! Runs N *independent* clusterings concurrently, each on its own graph, and measures -//! aggregate throughput against one thread. Nothing is shared, so there is no contention and -//! no coordination — the only thing that can stop this scaling linearly is the memory system. -//! -//! That makes it a ceiling: a real parallel local-move, which does share state, cannot beat -//! it. If throughput flattens at 4x on 8 cores, no amount of clever lock-free work gets 8x. +//! Runs N *independent* clusterings concurrently and measures aggregate throughput against +//! one thread. Nothing is shared, so only the memory system can stop it scaling linearly — +//! which makes it a ceiling. A real parallel local-move shares state and can't beat it. use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/examples/vs_igraph.rs b/examples/vs_igraph.rs index e52eccf..1f4cd0e 100644 --- a/examples/vs_igraph.rs +++ b/examples/vs_igraph.rs @@ -5,9 +5,9 @@ //! uv run tools/igraph_bench.py /tmp/bench //! ``` //! -//! Writes the graph to `/edges.tsv` so both sides cluster the identical input, and -//! times only `leiden()` — graph construction is excluded on both sides, because including -//! it measures the pipeline rather than the algorithm. +//! Writes the graph to `/edges.tsv` so both sides cluster the identical input, and times +//! only `leiden()`. Construction is excluded on both sides — including it would measure the +//! pipeline, not the algorithm. use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/src/clustering.rs b/src/clustering.rs index 419d2fa..572acbe 100644 --- a/src/clustering.rs +++ b/src/clustering.rs @@ -1,9 +1,7 @@ //! The result type shared by every clustering algorithm in this crate. -/// Label assigned to points that an algorithm considers noise. -/// -/// Leiden never produces it — every node lands somewhere — but density-based methods will, so -/// it's here from the start rather than as a breaking change later. +/// Label for points an algorithm considers noise. Leiden never produces it; density-based +/// methods will. pub const NOISE: usize = usize::MAX; /// An assignment of items to clusters. diff --git a/src/community_search/leiden/local_move.rs b/src/community_search/leiden/local_move.rs index b91a204..16d862d 100644 --- a/src/community_search/leiden/local_move.rs +++ b/src/community_search/leiden/local_move.rs @@ -1,10 +1,8 @@ //! Local moving: the inner loop of Leiden. //! -//! Take a node out of its community, put it wherever it scores best, repeat until nothing -//! wants to move. Nodes come off a queue seeded with a shuffled order; a node that moves -//! re-queues its neighbours, so only the affected part gets revisited. -//! -//! O(degree) per node, and nothing allocates per node or per candidate. +//! Take a node out, put it wherever it scores best, repeat until nothing moves. Nodes come off +//! a queue seeded with a shuffled order, and a node that moves re-queues its neighbours, so +//! only the affected part gets revisited. O(degree) per node, no allocation per node. use rand_chacha::ChaCha8Rng; @@ -12,28 +10,25 @@ use crate::community_search::leiden::objective::{InsertContext, Objective}; use crate::community_search::leiden::partition::{MoveScratch, Partition}; use crate::network::CSRNetwork; -/// Improvement floor, as a fraction of total edge weight. -/// -/// Relative, not absolute: otherwise scaling every weight by a constant could change the -/// clustering, even though the objective itself is scale-invariant. Low enough to sit under -/// any real gain, high enough that float dust doesn't cause no-op move cycles. +/// Improvement floor as a fraction of total edge weight. Relative, so rescaling weights +/// can't change the clustering; low enough to sit under any real gain, high enough that float +/// dust doesn't cause no-op move cycles. pub(crate) const MIN_GAIN_RELATIVE: f64 = 1e-12; -/// The absolute improvement threshold for a given graph. +/// Absolute threshold for a given graph. #[inline] pub(crate) fn min_gain(partition: &Partition) -> f64 { MIN_GAIN_RELATIVE * partition.total_weight().abs().max(1.0) } -/// Move cap, as a multiple of node count. Only a safety valve — this terminates on its own, -/// since every accepted move strictly increases a bounded objective. +/// Move cap per node. A safety valve only — every accepted move strictly increases a bounded +/// objective, so this terminates anyway. const MAX_MOVES_PER_NODE: usize = 100; -/// Moves nodes between communities until no single move improves the objective. +/// Moves nodes until no single move improves the objective, returning the total gain. /// -/// Returns the total quality improvement. `max_community_weight` caps a community's summed -/// node weight; node weights add up when communities collapse, so it means the same thing at -/// every level. +/// `max_community_weight` caps a community's summed node weight. Node weights add up on +/// collapse, so it means the same thing at every level. pub fn local_move( graph: &CSRNetwork, partition: &mut Partition, @@ -55,7 +50,7 @@ pub fn local_move( while let Some(v) = scratch.pop() { let ctx = InsertContext::for_node(graph, v); - // hoisted out of the neighbour loop, ~15x fewer calls + // hoisted out of the neighbour loop: ~15x fewer calls scratch.weights.ensure_capacity(partition.slots() + 1); scratch .weights @@ -65,7 +60,7 @@ pub fn local_move( let weight_to_old = scratch.weights.weight_to(old); partition.remove_node(v, graph, weight_to_old); - // staying put is just another candidate — keeps the empty case uniform + // staying put is just another candidate, which keeps the empty case uniform let base_gain = objective.delta_insert(partition, &ctx, old, weight_to_old); let mut best = old; let mut best_gain = base_gain; @@ -86,7 +81,7 @@ pub fn local_move( } } - // one per node, claimed below, so no two get the same + // one per node, claimed below, so no two nodes get the same let empty = partition.empty_community(); if empty != old && fits(partition, empty) { let gain = objective.delta_insert(partition, &ctx, empty, 0.0); diff --git a/src/community_search/leiden/mod.rs b/src/community_search/leiden/mod.rs index 0fe9508..ffe9c32 100644 --- a/src/community_search/leiden/mod.rs +++ b/src/community_search/leiden/mod.rs @@ -17,16 +17,13 @@ //! # } //! ``` //! -//! # How it works +//! Each level: [`local_move()`] settles nodes, [`refine()`] re-derives a finer partition +//! inside each community, and [`CSRNetwork::aggregate`] collapses the **refined** communities. +//! The next level starts from the coarse partition the working communities induce, so the same +//! partition keeps improving until collapsing stops shrinking the graph. //! -//! Each level: [`local_move()`] settles nodes into communities, [`refine()`] re-derives a -//! finer partition inside each one, and [`CSRNetwork::aggregate`] collapses the **refined** -//! communities into super-nodes. The next level starts from the coarse partition the working -//! communities induce, so the same partition keeps improving at coarser granularity until -//! collapsing stops shrinking the graph. -//! -//! Collapsing the refined partition instead of the working one is the whole difference from -//! Louvain — it's why badly connected communities don't get locked in. +//! Collapsing the refined partition rather than the working one is the whole difference from +//! Louvain. pub mod local_move; pub mod objective; @@ -48,44 +45,35 @@ use crate::network::CSRNetwork; /// Configuration for [`leiden`]. #[derive(Debug, Clone, PartialEq)] pub struct LeidenConfig { - /// Quality function to optimize, carrying the resolution parameter. - /// - /// [`ObjectiveKind::Rb`] at `resolution = 1.0` is modularity, matching `scanpy`'s default. + /// Quality function and its resolution. [`ObjectiveKind::Rb`] at `1.0` is modularity, + /// matching scanpy's default. pub objective: ObjectiveKind, - /// Seed for the random node orderings. `Some(_)` makes runs bit-for-bit reproducible; - /// `None` draws from the OS. + /// Seed for the node orderings. `Some(_)` is bit-for-bit reproducible, `None` draws from + /// the OS. pub seed: Option, - /// Number of passes, each continuing from the previous result. - /// - /// Matches `leidenalg` — passes keep improving the same partition rather than restarting - /// from singletons, which is how it escapes local optima a single pass falls into. Stops - /// early once a pass finds nothing. + /// Passes, each continuing from the previous result rather than restarting from + /// singletons — same as `leidenalg`. Stops early once a pass finds nothing. pub n_iterations: usize, - /// Cap on aggregation levels within one pass. Reaching it is unusual — a pass normally - /// stops earlier, when collapsing no longer shrinks the graph. + /// Cap on aggregation levels per pass. Rarely reached; a pass normally stops when + /// collapsing no longer shrinks the graph. pub max_levels: usize, - /// Minimum improvement for a pass to count as progress, relative to total edge weight. - /// - /// Relative, so the stopping rule doesn't depend on what units the weights are in. + /// Minimum improvement for a pass to count as progress, relative to total edge weight so + /// the rule doesn't depend on units. /// - /// Between passes only, never between levels — a level finding nothing says nothing about - /// the coarser level above it, which is exactly where aggregation earns its keep. + /// Between passes only. A level finding nothing says nothing about the coarser level + /// above it, which is where aggregation earns its keep. pub tolerance: f64, /// Whether to run the refinement phase. Disabling it turns the algorithm into Louvain. pub refine: bool, - /// Randomness of community selection during refinement, as in the Leiden paper. - /// - /// Higher explores more. `0.0` is a deterministic argmax, which gets stuck in local optima - /// no number of passes can escape. Deterministic for a fixed [`seed`](Self::seed) either - /// way. + /// Randomness of refinement's community selection, as in the Leiden paper. Higher + /// explores more; `0.0` is argmax, which gets stuck no matter how many passes run. Still + /// deterministic for a fixed [`seed`](Self::seed). pub refine_randomness: f64, - /// How many consecutive passes may find nothing before stopping. - /// - /// Refinement is randomised, so one fruitless pass isn't proof of convergence. `1` gives - /// `leidenalg`'s stop-on-first-stall behaviour. + /// Consecutive fruitless passes before stopping. Refinement is randomised, so one proves + /// nothing. `1` gives `leidenalg`'s stop-on-first-stall. pub patience: usize, - /// Optional cap on a community's total node weight. Node weights add up on aggregation, so - /// this means the same thing at every level — a limit on original nodes. + /// Cap on a community's total node weight. Node weights add up on aggregation, so this is + /// a limit on original nodes at every level. pub max_community_weight: Option, } @@ -106,7 +94,7 @@ impl Default for LeidenConfig { } impl LeidenConfig { - /// Convenience constructor for RB (modularity-style) clustering at a given resolution. + /// RB at a given resolution. pub fn with_resolution(resolution: f64) -> Self { Self { objective: ObjectiveKind::Rb { resolution }, @@ -162,9 +150,8 @@ fn build_objective(kind: ObjectiveKind) -> Box { /// Detects communities in `graph`. /// -/// Runs the algorithm [`LeidenConfig::n_iterations`] times, each pass continuing from the -/// previous result, and stops early once a pass finds no improvement. With a fixed -/// [`seed`](LeidenConfig::seed) the result is deterministic. +/// Runs [`LeidenConfig::n_iterations`] passes, each continuing from the last, stopping early +/// once one finds nothing. Deterministic for a fixed [`seed`](LeidenConfig::seed). pub fn leiden(graph: &CSRNetwork, config: &LeidenConfig) -> Result { config.validate()?; @@ -203,14 +190,11 @@ pub fn leiden(graph: &CSRNetwork, config: &LeidenConfig) -> Result { Ok(Clustering::from_normalized(labels, n_clusters)) } -/// One pass: local move, refine, aggregate, repeat until the graph stops shrinking. -/// -/// Starts from `initial`, not singletons — that's what makes successive passes build on each -/// other. Returns consecutive labels over the original nodes, the community count, and the -/// total improvement. +/// One pass: local move, refine, aggregate, until the graph stops shrinking. /// -/// The improvement is just the sum of per-level local-moving gains, which is exact: -/// aggregation doesn't change quality, and the coarse partition is the same partition. +/// Starts from `initial` rather than singletons, which is what lets passes build on each +/// other. Returns labels over the original nodes, the community count, and the improvement — +/// the sum of per-level gains, which is exact since aggregation doesn't change quality. fn run_once( graph: &CSRNetwork, objective: &dyn Objective, @@ -264,8 +248,8 @@ fn run_once( break; } - // several coarse nodes can share a working community — that's what lets the next - // level pull them apart again + // several coarse nodes can share a working community, which is what lets the next + // level pull them apart let mut coarse_membership = vec![0usize; coarse_graph.node_count()]; for v in 0..level_graph.node_count() { coarse_membership[collapse_by.membership(v)] = partition.membership(v); diff --git a/src/community_search/leiden/objective.rs b/src/community_search/leiden/objective.rs index 6fb0754..aa616f1 100644 --- a/src/community_search/leiden/objective.rs +++ b/src/community_search/leiden/objective.rs @@ -1,35 +1,29 @@ //! Quality functions. //! //! An [`Objective`] scores a [`Partition`], and more usefully scores *inserting* a removed -//! node into a candidate community. Both read only the aggregates the partition already -//! maintains, so neither touches the graph. +//! node into a candidate community. Both read only maintained aggregates, never the graph. //! -//! # Scaling -//! -//! Everything here is `Σ_c [ internal_c − null_c ]` with each internal edge counted once. For -//! [`Rb`] the null term is `γ·K_c²/(4m)`. That `4m` is load-bearing — with `2m` you get `Rb` -//! at resolution `2γ`, which is why this crate used to return about twice as many communities -//! as `leidenalg` at the same nominal resolution. [`modularity`] reports a value directly -//! comparable with `scanpy`/`leidenalg`. +//! Everything is `Σ_c [ internal_c − null_c ]`, each internal edge once. [`Rb`]'s null term is +//! `γ·K_c²/(4m)` — that `4m` is load-bearing, since `2m` gives `Rb` at resolution `2γ`, which +//! is the 0.6.x bug. [`modularity`] reports a value directly comparable with `scanpy`. use crate::community_search::leiden::partition::Partition; use crate::network::CSRNetwork; -/// The node-level quantities an objective needs to score an insertion. -/// -/// Built once per node by the local-moving loop and reused across every candidate community. +/// What an objective needs about the node being moved. Built once per node, reused across +/// every candidate. #[derive(Debug, Clone, Copy)] pub struct InsertContext { - /// Sum of the node's incident edge weights, self-loop counted twice. + /// Incident edge weight, self-loop counted twice. pub node_strength: f64, - /// The node's own weight ("size"), summed across members after aggregation. + /// The node's own weight, summed across members after aggregation. pub node_weight: f64, /// Weight of the node's self-loop, or `0.0`. pub self_loop: f64, } impl InsertContext { - /// Reads the quantities for `node` out of `graph`. + /// Reads them for `node` out of `graph`. #[inline] pub fn for_node(graph: &CSRNetwork, node: usize) -> Self { Self { @@ -40,10 +34,10 @@ impl InsertContext { } } -/// The community aggregates a move actually depends on. +/// The community aggregates a move depends on. /// -/// Only three numbers, which is what lets refinement work on per-community local state -/// instead of the whole partition — the basis of running it in parallel. +/// Three numbers, which is what lets refinement work on local state instead of the whole +/// partition — and so run in parallel. #[derive(Debug, Clone, Copy, Default)] pub struct CommunityView { /// Total edge weight of the graph, each edge once. Global, not per community. @@ -56,14 +50,12 @@ pub struct CommunityView { /// A quality function to maximize. pub trait Objective: Send + Sync { - /// Change in quality from inserting a currently-removed node into a community. + /// Quality change from inserting a removed node into a community. /// - /// The one place each objective's formula lives. [`delta_insert`](Self::delta_insert) - /// reads the view out of a [`Partition`] and calls this, so the partition-backed and - /// local-state paths can never drift apart. + /// The one place each formula lives — [`delta_insert`](Self::delta_insert) reads the view + /// out of a [`Partition`] and calls this, so the two paths can't drift. /// - /// `weight_to_comm` excludes the node's self-loop; that gets added here, since it becomes - /// internal to whichever community the node lands in. + /// `weight_to_comm` excludes the self-loop, which gets added here. fn delta_insert_view( &self, view: CommunityView, @@ -71,9 +63,8 @@ pub trait Objective: Send + Sync { weight_to_comm: f64, ) -> f64; - /// Change in quality from inserting a currently-removed node into `community`. - /// - /// `community` may name an unallocated slot, which reads as empty. + /// Quality change from inserting a removed node into `community`, which may be an + /// unallocated slot — that reads as empty. #[inline] fn delta_insert( &self, @@ -93,25 +84,24 @@ pub trait Objective: Send + Sync { ) } - /// Total quality of the partition, in the same units as [`delta_insert`](Self::delta_insert). + /// Total quality, in the same units as [`delta_insert`](Self::delta_insert). fn quality(&self, partition: &Partition) -> f64; - /// The resolution parameter. Higher values favour smaller communities. + /// Higher values favour smaller communities. fn resolution(&self) -> f64; } -/// Reichardt–Bornholdt configuration-model objective. +/// Reichardt–Bornholdt configuration model. /// -/// `Q = Σ_c [ internal_c − γ · K_c² / (4m) ]`, with `K_c` the summed node strength of `c` and -/// `m` the total edge weight. At `γ = 1` this is modularity, matching `leidenalg`'s -/// `RBConfigurationVertexPartition` and so `scanpy`'s default. +/// `Q = Σ_c [ internal_c − γ · K_c² / (4m) ]`. At `γ = 1` this is modularity, matching +/// `leidenalg`'s `RBConfigurationVertexPartition` and so scanpy's default. #[derive(Debug, Clone, Copy)] pub struct Rb { resolution: f64, } impl Rb { - /// Creates an RB objective with the given resolution. + /// RB at the given resolution. pub fn new(resolution: f64) -> Self { Self { resolution } } @@ -160,24 +150,21 @@ impl Objective for Rb { } } -/// Constant Potts Model objective. +/// Constant Potts Model. /// -/// `Q = Σ_c [ internal_c − γ · n_c(n_c − 1) / 2 ]`, where `n_c` is the summed node weight of -/// community `c` — that is, the internal weight minus `γ` times the number of node *pairs* -/// inside the community. Unlike RB, CPM has no resolution limit: `γ` is directly the internal -/// edge density below which a community will not form, so it behaves predictably as you turn -/// the knob on large graphs. +/// `Q = Σ_c [ internal_c − γ · n_c(n_c − 1) / 2 ]` over summed node weight `n_c`. No +/// resolution limit: `γ` is directly the internal edge density below which a community won't +/// form, so it behaves predictably on large graphs. /// -/// The pair count matches `leidenalg`'s `CPMVertexPartition`, whose reported quality is -/// exactly twice this one's. Because node weights are summed on aggregation, `n_c` counts -/// original nodes at every level, so the objective is unchanged by collapsing. +/// The pair count matches `leidenalg`'s `CPMVertexPartition`, which reports exactly twice +/// this. Node weights sum on aggregation, so `n_c` counts original nodes at every level. #[derive(Debug, Clone, Copy)] pub struct Cpm { resolution: f64, } impl Cpm { - /// Creates a CPM objective with the given resolution. + /// CPM at the given resolution. pub fn new(resolution: f64) -> Self { Self { resolution } } @@ -240,7 +227,7 @@ impl Default for ObjectiveKind { } impl ObjectiveKind { - /// The resolution parameter carried by this objective. + /// The resolution this carries. pub fn resolution(&self) -> f64 { match *self { Self::Rb { resolution } | Self::Cpm { resolution } => resolution, @@ -248,11 +235,11 @@ impl ObjectiveKind { } } -/// Standard Newman–Girvan modularity of a labelling, computed directly from the graph. +/// Newman–Girvan modularity of a labelling, straight from the graph. /// -/// Deliberately independent of [`Partition`] and [`Objective`]: it is what users should report -/// and compare against `scanpy`, and it doubles as an outside check on the optimizer's own -/// arithmetic. At `resolution = 1.0` this is textbook modularity in `[-1, 1]`. +/// Independent of [`Partition`] and [`Objective`] on purpose: it's what to report and compare +/// against scanpy, and it doubles as an outside check on the optimizer's arithmetic. At +/// `resolution = 1.0` it's textbook modularity in `[-1, 1]`. pub fn modularity(graph: &CSRNetwork, labels: &[usize], resolution: f64) -> f64 { let m = graph.total_weight(); if m == 0.0 { @@ -292,7 +279,7 @@ mod tests { let q_scaled = Rb::new(1.0).quality(&p); let q_standard = modularity(&g, &labels, 1.0); - // Rb::quality is m * Q — the scaling the old code got wrong by 2x + // Rb::quality is m * Q, the scaling the old code got wrong by 2x assert!( (q_scaled / g.total_weight() - q_standard).abs() < 1e-12, "Rb::quality/m = {}, modularity = {q_standard}", @@ -309,7 +296,7 @@ mod tests { let g = karate(); let labels = karate_optimum(); let p = Partition::from_membership(&g, &labels); - // Rb(gamma) == textbook Q(gamma), not Q(2*gamma) like the old code + // Rb(gamma) == textbook Q(gamma), not Q(2*gamma) as before for gamma in [0.5, 1.0, 2.0, 4.0] { let got = Rb::new(gamma).quality(&p) / g.total_weight(); let want = modularity(&g, &labels, gamma); @@ -317,7 +304,7 @@ mod tests { } } - /// The invariant that catches any drift between the delta and the objective. + /// Catches any drift between the delta and the objective. fn delta_matches_quality_change(obj: &O, graph: &CSRNetwork, labels: &[usize]) { use crate::community_search::leiden::partition::NeighborWeights; let mut p = Partition::from_membership(graph, labels); diff --git a/src/community_search/leiden/partition.rs b/src/community_search/leiden/partition.rs index 1f4cf6c..b7c0b06 100644 --- a/src/community_search/leiden/partition.rs +++ b/src/community_search/leiden/partition.rs @@ -1,13 +1,13 @@ //! Partition state. //! -//! [`Partition`] holds every aggregate the quality functions need — sizes, node weights, -//! strengths, internal edge weights — updated in O(1) per move. Nothing here walks the graph -//! or allocates per call, which is what keeps local moving at O(degree) rather than O(n). +//! [`Partition`] holds every aggregate the quality functions need, updated in O(1) per move. +//! Nothing here walks the graph or allocates per call, which is what keeps local moving at +//! O(degree). //! //! A move is [`remove_node`](Partition::remove_node) then -//! [`insert_node`](Partition::insert_node), not one operation. The node sits in no community -//! in between, so scoring every candidate — its old community, an empty one, anything else — -//! is the same calculation. +//! [`insert_node`](Partition::insert_node), never one operation. The node sits in no community +//! in between, so every candidate — old community, empty one, anything else — scores the same +//! way. use rand::seq::SliceRandom; use rand_chacha::ChaCha8Rng; @@ -15,20 +15,17 @@ use rand_chacha::ChaCha8Rng; use crate::network::CSRNetwork; use crate::network::grouping::VectorGrouping; -/// Membership value for a node that has been removed from its community. -/// -/// Visible in [`Partition::membership_raw`] while a move is in progress; never in a -/// partition handed back to a caller. +/// Membership value for a removed node. Visible via [`Partition::membership_raw`] mid-move, +/// never in a partition handed back. pub const UNASSIGNED: u32 = u32::MAX; /// A partition of a graph's nodes into communities, with incrementally maintained aggregates. #[derive(Debug, Clone)] pub struct Partition { - /// Community of each node, or [`UNASSIGNED`] while a node is removed. + /// Community of each node, or [`UNASSIGNED`] mid-move. /// - /// `u32`, not `usize`: this is the hottest random access in the algorithm — every - /// neighbour of every visited node reads it — so halving the array halves that cache - /// footprint. Ids are bounded by the node count, which `CSRNetwork` caps at `u32::MAX`. + /// `u32` because this is the hottest random access in the algorithm — every neighbour of + /// every visited node reads it — and halving the array halves that cache footprint. membership: Vec, /// Number of nodes in each community. size: Vec, @@ -36,13 +33,12 @@ pub struct Partition { weight: Vec, /// Sum of node strengths in each community. This is `K_c` in the RB null model. strength: Vec, - /// Internal edge weight of each community: edges with both endpoints inside, each - /// undirected edge counted once, self-loops counted once at full weight. + /// Internal edge weight per community, each undirected edge once, self-loops at full + /// weight. internal: Vec, /// Community slots that currently hold no nodes, available for reuse. free: Vec, - /// Total edge weight, each edge once. Kept here so quality functions don't need the graph, - /// and so it stays consistent across levels. + /// Total edge weight, each edge once. Here so quality functions don't need the graph. total_weight: f64, /// Sum of all node weights. total_node_weight: f64, @@ -57,7 +53,7 @@ impl Partition { size: vec![1; n], weight: (0..n).map(|v| graph.node_weight(v)).collect(), strength: (0..n).map(|v| graph.strength(v)).collect(), - // only internal edge is its own self-loop + // its only internal edge is its own self-loop internal: (0..n).map(|v| graph.self_loop_weight(v)).collect(), free: Vec::new(), total_weight: graph.total_weight(), @@ -67,8 +63,7 @@ impl Partition { /// Creates a partition from an explicit membership vector. /// - /// Ids need not be consecutive — empty slots below the maximum are recorded as free and - /// reused before anything new is allocated. + /// Ids needn't be consecutive; gaps become free slots and get reused first. pub fn from_membership(graph: &CSRNetwork, membership: &[usize]) -> Self { debug_assert_eq!(membership.len(), graph.node_count()); let slots = membership.iter().copied().max().map_or(0, |m| m + 1); @@ -94,7 +89,7 @@ impl Partition { if membership[u] != c { continue; } - // each edge once: loops here, regular ones from the lower id + // each edge once: loops here, the rest from the lower id if u == v || v < u { p.internal[c] += w; } @@ -126,20 +121,20 @@ impl Partition { self.membership.len() } - /// Community of a node. Panics in debug builds if the node is currently removed. + /// Community of a node. Debug-panics if it's currently removed. #[inline] pub fn membership(&self, node: usize) -> usize { debug_assert_ne!(self.membership[node], UNASSIGNED, "node {node} is removed"); self.membership[node] as usize } - /// The raw membership slice, which may contain [`UNASSIGNED`] mid-move. + /// Raw membership, which may hold [`UNASSIGNED`] mid-move. #[inline] pub fn membership_raw(&self) -> &[u32] { &self.membership } - /// The membership as `usize` values, allocated fresh. + /// Membership as `usize`, allocated fresh. pub fn membership_vec(&self) -> Vec { self.membership.iter().map(|&c| c as usize).collect() } @@ -180,21 +175,19 @@ impl Partition { self.total_node_weight } - /// Returns a community id that is currently empty, without allocating. + /// An empty community id, without allocating. /// - /// Reuses a free slot if there is one, otherwise the next index, which - /// [`insert_node`](Self::insert_node) allocates on demand. Each caller takes exactly one - /// and fills it immediately, so two nodes can't get the same empty community. + /// A free slot if there is one, otherwise the next index, allocated on insert. Each caller + /// takes one and fills it immediately, so two nodes can't get the same one. #[inline] pub fn empty_community(&self) -> usize { self.free.last().copied().unwrap_or(self.size.len()) } - /// Removes a node from its community, updating all aggregates in O(1). + /// Removes a node from its community, updating aggregates in O(1). Returns the community + /// it was in. /// - /// `weight_to_own` is the total weight of edges from `node` to other members of its - /// community, **excluding** the node's self-loop — exactly what - /// [`NeighborWeights`] accumulates. Returns the community the node was in. + /// `weight_to_own` excludes the self-loop — exactly what [`NeighborWeights`] accumulates. pub fn remove_node(&mut self, node: usize, graph: &CSRNetwork, weight_to_own: f64) -> usize { let c = self.membership[node] as usize; debug_assert_ne!( @@ -205,11 +198,11 @@ impl Partition { self.size[c] -= 1; self.weight[c] -= graph.node_weight(node); self.strength[c] -= graph.strength(node); - // its edges in, plus its self-loop, stop being internal + // its edges in, plus its self-loop, stop counting as internal self.internal[c] -= weight_to_own + graph.self_loop_weight(node); if self.size[c] == 0 { - // clamp drift so empty is exactly empty + // clamp float drift so empty is exactly empty self.weight[c] = 0.0; self.strength[c] = 0.0; self.internal[c] = 0.0; @@ -220,10 +213,10 @@ impl Partition { c } - /// Inserts a removed node into a community, updating all aggregates in O(1). + /// Inserts a removed node into a community, updating aggregates in O(1). /// - /// `community` may be [`empty_community`](Self::empty_community), in which case a new - /// slot is allocated. `weight_to_comm` excludes the node's self-loop. + /// `community` may be [`empty_community`](Self::empty_community), which allocates a slot. + /// `weight_to_comm` excludes the self-loop. pub fn insert_node( &mut self, node: usize, @@ -256,9 +249,8 @@ impl Partition { self.membership[node] = community as u32; } - /// Renumbers communities consecutively from 0, keeping their relative order. - /// - /// Ascending order, so the output never depends on iteration order upstream. + /// Renumbers communities consecutively from 0, ascending, so the output never depends on + /// iteration order upstream. pub fn renumber(&mut self) { let slots = self.size.len(); let mut new_id = vec![usize::MAX; slots]; @@ -294,17 +286,14 @@ impl Partition { /// Renumbers this partition and returns its membership as a [`VectorGrouping`]. /// - /// `&mut self` on purpose: the grouping's ids and this partition's must be the same - /// numbers, since callers use `membership(v)` to index the graph - /// [`CSRNetwork::aggregate`] produces. Renumbering a copy would let them drift silently. + /// `&mut self` on purpose: callers use `membership(v)` to index the graph + /// [`CSRNetwork::aggregate`] produces, so the two sets of ids have to stay the same. pub fn renumber_into_grouping(&mut self) -> VectorGrouping { self.renumber(); VectorGrouping::from_assignments(&self.membership_vec()) } - /// Recomputes every aggregate from scratch and checks it against the maintained value. - /// - /// Used by tests to prove the incremental updates never drift. + /// Recomputes every aggregate and checks it against the maintained one. Tests only. pub fn verify_against(&self, graph: &CSRNetwork) -> std::result::Result<(), String> { let rebuilt = Self::from_membership(graph, &self.membership_vec()); for c in 0..self.size.len() { @@ -329,38 +318,32 @@ impl Partition { } } -/// Accumulates edge weight from one node to each neighbouring community. -/// -/// Replaces the per-call `HashSet` and `get_group_members()` allocation that made the old -/// implementation O(n) per candidate. One pass over a node's neighbours gives every candidate -/// and its weight, so scoring all of them is O(degree), not O(n · degree). -/// -/// Candidates come back in first-touch order, i.e. ascending neighbour id — deterministic, -/// unlike hash-set iteration. #[derive(Debug, Clone, Copy, Default)] struct Slot { - /// Generation this slot was last written in, avoiding an O(slots) clear between nodes. + /// Generation last written, which is what avoids an O(slots) clear between nodes. stamp: u64, - /// Accumulated edge weight to this community, valid only when `stamp == generation`. + /// Edge weight to this community, valid only when `stamp == generation`. weight: f64, } +/// Edge weight from one node to each neighbouring community. +/// +/// One pass over a node's neighbours gives every candidate and its weight, so scoring all of +/// them is O(degree). Candidates come back in first-touch order, i.e. ascending neighbour id. #[derive(Debug, Clone, Default)] pub struct NeighborWeights { - /// Stamp and weight packed together — the inner loop touches both for the same community, - /// and at scale this array is way past cache, so adjacency turns two random misses per - /// neighbour into one. + /// Stamp and weight packed together: the inner loop touches both for the same community, + /// and past cache that's one random miss per neighbour instead of two. /// - /// Tried and reverted: a linear-scan path for low-degree nodes. 19% worse at 100k (the - /// indexed array still fits in cache there) and only break-even at 3M, since the scan - /// trades a miss for a branch-mispredicting loop. + /// Tried and reverted: a linear scan for low-degree nodes. 19% worse at 100k, break-even + /// at 3M — it trades a miss for a branch-mispredicting loop. slots: Vec, generation: u64, touched: Vec, } impl NeighborWeights { - /// Creates an accumulator sized for `slots` communities. + /// Sized for `slots` communities. pub fn with_capacity(slots: usize) -> Self { Self { slots: vec![Slot::default(); slots], @@ -369,9 +352,7 @@ impl NeighborWeights { } } - /// Grows the accumulator so community ids up to `slots - 1` are addressable. - /// - /// Call this once per node, before [`collect`](Self::collect) - not once per neighbour. + /// Grows so ids up to `slots - 1` are addressable. Once per node, not per neighbour. #[inline] pub fn ensure_capacity(&mut self, slots: usize) { if self.slots.len() < slots { @@ -379,10 +360,8 @@ impl NeighborWeights { } } - /// Starts a new accumulation round. - /// - /// A generation counter is what makes clearing free. `u64` won't wrap in any realistic - /// run, but the reset keeps that from being a silent correctness cliff. + /// Starts a new round. The generation counter makes clearing free; `u64` won't wrap in + /// any realistic run, but the reset keeps that from being a silent correctness cliff. #[inline] fn begin(&mut self) { self.touched.clear(); @@ -415,11 +394,9 @@ impl NeighborWeights { } } - /// Accumulates the weight from `node` to each community containing one of its neighbours. - /// - /// Self-loops are excluded, matching the convention of - /// [`Partition::remove_node`]/[`Partition::insert_node`], which add the self-loop - /// themselves. Returns the touched community ids. + /// Weight from `node` to each community holding one of its neighbours, self-loop + /// excluded — [`Partition::remove_node`]/[`insert_node`](Partition::insert_node) add that + /// themselves. Returns the touched ids. pub fn collect(&mut self, graph: &CSRNetwork, membership: &[u32], node: usize) -> &[usize] { self.begin(); @@ -436,7 +413,7 @@ impl NeighborWeights { &self.touched } - /// Weight from the last collected node to `community`, or `0.0` if untouched. + /// Weight from the last collected node to `community`, or `0.0`. #[inline] pub fn weight_to(&self, community: usize) -> f64 { match self.slots.get(community) { @@ -445,18 +422,17 @@ impl NeighborWeights { } } - /// The communities touched by the last [`collect`](Self::collect). + /// Communities touched by the last [`collect`](Self::collect). #[inline] pub fn touched(&self) -> &[usize] { &self.touched } } -/// Reusable working buffers for local moving and refinement. +/// Reusable buffers for local moving and refinement. /// -/// Both phases want a shuffled order, a work queue, and a queued-flag array, all sized to the -/// node count. Per-call allocation is ~1.3 GB of churn per level at 75M nodes, so the driver -/// owns one and hands it down. +/// Both want a shuffled order, a queue, and a queued flag per node. Allocating per call is +/// ~1.3 GB of churn per level at 75M nodes, so the driver owns one and hands it down. #[derive(Debug, Clone, Default)] pub struct MoveScratch { /// Per-node accumulator of edge weight to each neighbouring community. @@ -467,7 +443,7 @@ pub struct MoveScratch { } impl MoveScratch { - /// Creates scratch sized for `n` nodes and `slots` communities. + /// Sized for `n` nodes and `slots` communities. pub fn with_capacity(n: usize, slots: usize) -> Self { Self { weights: NeighborWeights::with_capacity(slots), @@ -477,7 +453,7 @@ impl MoveScratch { } } - /// Fills the queue with all `n` nodes in a freshly shuffled order and marks them queued. + /// Queues all `n` nodes in a fresh shuffled order. pub(crate) fn seed_queue(&mut self, n: usize, rng: &mut ChaCha8Rng) { self.order.clear(); self.order.extend(0..n); @@ -490,7 +466,7 @@ impl MoveScratch { self.queued.resize(n, true); } - /// Produces a freshly shuffled node order without touching the queue. + /// A fresh shuffled node order, leaving the queue alone. pub(crate) fn shuffled_order(&mut self, n: usize, rng: &mut ChaCha8Rng) -> &[usize] { self.order.clear(); self.order.extend(0..n); diff --git a/src/community_search/leiden/refine.rs b/src/community_search/leiden/refine.rs index 1a7feb9..c449453 100644 --- a/src/community_search/leiden/refine.rs +++ b/src/community_search/leiden/refine.rs @@ -1,18 +1,18 @@ //! Refinement — what makes this Leiden and not Louvain. //! -//! Re-derives a finer partition inside each community local moving found, from singletons, -//! merging only within a community. Aggregation then collapses the *refined* communities, so -//! Louvain's badly-connected (sometimes disconnected) communities don't get locked in. +//! Re-derives a finer partition inside each community local moving found, starting from +//! singletons. Aggregation then collapses the *refined* communities, so Louvain's +//! badly-connected ones don't get locked in. //! -//! Two rules, both of which the previous implementation got wrong: +//! Two rules, both of which the pre-0.7 implementation got wrong: //! -//! 1. Only singletons may merge — once absorbed, a node is never moved again. Otherwise -//! refined communities stop being bottom-up unions and the guarantee is gone. +//! 1. Only singletons may merge. Once absorbed a node never moves again, otherwise refined +//! communities stop being bottom-up unions and the guarantee is gone. //! 2. Moves stay inside the constraining community. //! //! Candidate selection is randomised (Leiden paper, Algorithm 3): draw with probability -//! proportional to `exp(gain / randomness)`. Greedy argmax gets stuck somewhere repeated -//! passes can't escape; this is how it explores past that. `randomness = 0.0` is greedy. +//! proportional to `exp(gain / randomness)`. Greedy argmax gets stuck where repeated passes +//! can't help. `randomness = 0.0` is greedy. use rand::Rng; use rand_chacha::ChaCha8Rng; @@ -23,9 +23,8 @@ use crate::network::CSRNetwork; /// Builds a refined partition inside the communities of `constraint`. /// -/// Every refined community sits inside exactly one community of `constraint`. One pass over a -/// shuffled order is enough — only singletons merge and each node is seen once, so it can't -/// cycle. That's why zero-gain merges are safe to accept here; they help escape plateaus. +/// One pass over a shuffled order is enough: only singletons merge and each node is seen once, +/// so it can't cycle. That's why zero-gain merges are safe here — they escape plateaus. pub fn refine( graph: &CSRNetwork, constraint: &[u32], @@ -40,7 +39,7 @@ pub fn refine( return Partition::singleton(graph); } - // relative to a typical edge, so rescaling weights doesn't change behaviour + // relative to a typical edge, so rescaling weights changes nothing let mean_edge_weight = if graph.edge_count() > 0 { graph.total_weight() / graph.edge_count() as f64 } else { @@ -48,18 +47,14 @@ pub fn refine( }; let randomness = randomness * mean_edge_weight; - // One draw per node, taken up front in node order. Previously each `select` pulled from a - // shared stream, so a node's randomness depended on how many nodes before it happened to - // need one — which couples communities that are otherwise independent, and would make the - // result depend on how the work was divided. Drawing per node decouples them. + // one draw per node, up front. A shared stream would make a node's randomness depend on + // how many before it needed one, coupling communities that are otherwise independent. let draws: Vec = (0..n).map(|_| rng.random::()).collect(); - // Visit order stays globally shuffled; bucketing preserves each community's relative - // order within it, so the sequence a community sees is what it would have seen anyway. + // bucketing keeps each community's relative order, so it sees the same sequence either way let order = scratch.shuffled_order(n, rng); - // Sized by the largest constraint id, not by the node count: these ids are inherited from - // the previous level's working partition, so at level 1 and above they routinely exceed - // the number of nodes in the current graph. + // sized by the largest constraint id, not the node count — these are inherited from the + // previous level and routinely exceed it let slots = constraint .iter() .copied() @@ -112,17 +107,15 @@ pub fn refine( } } - // Rebuild a full partition from the labels, so every aggregate is exactly right rather - // than incrementally maintained across a parallel split. + // rebuild from the labels, so aggregates are exact rather than maintained across a split let as_usize: Vec = labels.iter().map(|&c| c as usize).collect(); Partition::from_membership(graph, &as_usize) } /// Draws a candidate with probability proportional to `exp(gain / randomness)`. /// -/// Subtracting `best_rel` before exponentiating keeps weights in `(0, 1]`, so a large -/// gain/randomness ratio can't overflow. `randomness <= 0` is a deterministic argmax, ties -/// going to the lowest id so traversal order never shows through. +/// Subtracting `best_rel` first keeps weights in `(0, 1]` so a large ratio can't overflow. +/// `randomness <= 0` is argmax, ties to the lowest id. fn select( candidates: &[(usize, f64)], best_rel: f64, @@ -170,15 +163,13 @@ fn select( /// Refines one constraining community, independently of every other. /// -/// This is the whole basis for running refinement in parallel: a node may only merge with -/// refined communities inside its own constraining community, so two constraining communities -/// share no state at all. Working on local ids rather than the global partition is what makes -/// that disjointness visible to the compiler instead of merely true. +/// A node can only merge inside its own constraining community, so two of them share no state. +/// Local ids rather than the global partition is what makes that disjointness visible to the +/// compiler instead of merely true. /// -/// `members` are the community's global node ids in the order they should be visited; -/// `sorted` is the same set ascending, for global-to-local lookup. Writes each member's -/// refined label into `out`, as a global node id — the id of the member that community formed -/// around, so labels from different communities can never collide. +/// `members` is the community's global node ids in visit order, `sorted` the same set +/// ascending for global-to-local lookup. Each member's label goes into `out` as the global id +/// its refined community formed around, so labels can't collide across communities. #[allow(clippy::too_many_arguments)] fn refine_into( graph: &CSRNetwork, @@ -198,9 +189,8 @@ fn refine_into( let local_of = |g: u32| -> usize { sorted.binary_search(&g).expect("member of this community") }; - // Local singleton partition: community i starts as node i. Only the three aggregates - // `delta_insert_view` reads are tracked; `internal` is never consulted during refinement, - // and the caller rebuilds a full partition from the labels afterwards. + // local singleton partition. Only the three aggregates `delta_insert_view` reads are + // tracked; `internal` is never consulted here, and the caller rebuilds anyway. let mut membership: Vec = (0..k as u32).collect(); let mut size = vec![1u32; k]; let mut strength = vec![0.0f64; k]; @@ -210,7 +200,7 @@ fn refine_into( weight[local] = graph.node_weight(g as usize); } - // Weight from the current node to each local community, cleared via `touched`. + // weight to each local community, cleared via `touched` let mut to_comm = vec![0.0f64; k]; let mut touched: Vec = Vec::new(); let mut candidates: Vec<(usize, f64)> = Vec::new(); @@ -229,8 +219,8 @@ fn refine_into( } touched.clear(); - // rule 2: stay inside the constraint — neighbours outside it are simply not in - // `sorted`, so the binary search filters them out. + // rule 2: neighbours outside the constraint aren't in `sorted`, so the search + // filters them out for (u, w) in graph.neighbors(g as usize) { if u == g as usize { continue; @@ -247,7 +237,7 @@ fn refine_into( let ctx = InsertContext::for_node(graph, g as usize); let weight_to_own = to_comm[own]; - // Take the node out. Its own community is a singleton, so it empties. + // take it out; its community is a singleton, so it empties size[own] -= 1; strength[own] -= ctx.node_strength; weight[own] -= ctx.node_weight; @@ -294,9 +284,8 @@ fn refine_into( membership[v] = target as u32; } - // Label each member by the global id its refined community formed around, so labels are - // unique across communities without any coordination between them. - // `out` is indexed locally, matching `sorted`; the caller scatters it to global ids. + // label by the global id the refined community formed around, so labels are unique + // without coordination. `out` is local, matching `sorted`; the caller scatters it. for local in 0..k { out[local] = sorted[membership[local] as usize]; } @@ -350,7 +339,7 @@ mod tests { #[test] fn a_single_constraint_community_can_still_split() { - // one constraint community, should still split the barbell rather than merge it + // one constraint community; must still split the barbell let g = barbell(); let constraint: Vec = vec![0; 10]; let mut scratch = MoveScratch::with_capacity(g.node_count(), g.node_count()); diff --git a/src/community_search/mod.rs b/src/community_search/mod.rs index ef32d08..b4b8aa3 100644 --- a/src/community_search/mod.rs +++ b/src/community_search/mod.rs @@ -1,6 +1,3 @@ -//! Community detection algorithms for network analysis. -//! -//! Provides implementations of state-of-the-art community detection algorithms -//! for identifying modular structures in networks. +//! Community detection. pub mod leiden; diff --git a/src/error.rs b/src/error.rs index 1dc995b..2884802 100644 --- a/src/error.rs +++ b/src/error.rs @@ -63,11 +63,9 @@ pub enum ClusteringError { /// The two node indices sharing it. nodes: (usize, usize), }, - /// Visium hex positions did not all share the same `(row + col)` parity. - /// - /// In doubled coordinates every spot has the same parity, so mixed parity means the - /// coordinates are not doubled — most often offset coordinates (`col / 2`), which would - /// silently produce a wrong graph rather than an empty one. + /// Visium hex positions didn't all share the same `(row + col)` parity, so they aren't + /// doubled coordinates. Usually offset coordinates (`col / 2`), which would give a wrong + /// graph rather than an empty one. InconsistentHexParity { /// A node with the majority parity. expected_node: usize, @@ -76,11 +74,9 @@ pub enum ClusteringError { /// The offending position. position: (u32, u32), }, - /// No triangulation exists for the given points — they are collinear, or fewer than - /// three distinct positions. - /// - /// Reported rather than returning an edgeless graph, which would cluster into singletons - /// and look like a result. + /// No triangulation exists: collinear, or fewer than three distinct positions. An error + /// rather than an edgeless graph, which would cluster into singletons and look like a + /// result. DegenerateTriangulation { /// How many points were supplied. n_points: usize, @@ -92,11 +88,8 @@ pub enum ClusteringError { /// Expected length, from the first array supplied. expected: usize, }, - /// The adjacency is not symmetric, so `Σ strength != 2 · total_weight`. - /// - /// Most often means an un-symmetrised k-NN graph was passed to - /// `CSRNetwork::from_csr_parts`: if `j` is among `i`'s nearest neighbours but `i` is not - /// among `j`'s, the matrix has an entry in one direction only. + /// Adjacency isn't symmetric, so `Σ strength != 2 · total_weight`. Usually an + /// un-symmetrised kNN graph handed to `CSRNetwork::from_csr_parts`. AsymmetricGraph { /// The observed sum of node strengths. degree_sum: f64, diff --git a/src/network/csr_network.rs b/src/network/csr_network.rs index 60a32d2..90595cb 100644 --- a/src/network/csr_network.rs +++ b/src/network/csr_network.rs @@ -1,28 +1,17 @@ //! CSR storage for a weighted, undirected graph. //! -//! ## Weight conventions +//! igraph/leidenalg weight conventions, which every quality function here depends on: //! -//! igraph/leidenalg conventions. Every quality function here depends on them: -//! -//! - edge `{u, v}` of weight `w` → `w` to `strength(u)`, `w` to `strength(v)`, `w` to -//! [`total_weight`](CSRNetwork::total_weight) +//! - edge `{u, v}` of weight `w` → `w` to each endpoint's strength, `w` to `total_weight` //! - **self-loop** on `v` of weight `w` → **`2w`** to `strength(v)`, `w` to `total_weight` //! -//! Which gives the invariant `Σ strength(v) == 2 · total_weight`. This matters because -//! [`aggregate`](CSRNetwork::aggregate) packs a community's whole internal weight into one -//! self-loop — get the degree contribution wrong and the null model silently dies above -//! level 0. -//! -//! ## Memory layout +//! So `Σ strength(v) == 2 · total_weight`. [`aggregate`](CSRNetwork::aggregate) packs a +//! community's internal weight into one self-loop, so getting that wrong kills the null model +//! above level 0. //! -//! `u32` ids and `f32` weights, so 8 bytes per stored entry / 16 per undirected edge. Per-node -//! data and all arithmetic stay `f64` — weights are read at `f32`, never accumulated at it. -//! Node weights especially, since after aggregation they count original nodes and would lose -//! integer precision past 2^24. -//! -//! ~12 GB of adjacency at 75M nodes rather than ~24. [`from_csr_parts`](CSRNetwork::from_csr_parts) -//! takes buffers you already have without copying; [`from_edges`](CSRNetwork::from_edges) also -//! needs the caller's edge list resident, but builds in place rather than doubling. +//! `u32` ids and `f32` weights: 16 bytes per undirected edge, ~12 GB of adjacency at 75M +//! nodes rather than ~24. Per-node data and all arithmetic stay `f64` — node weights count +//! original nodes after aggregation and would lose integer precision past 2^24. use std::sync::Arc; @@ -37,8 +26,8 @@ pub const MAX_NODES: usize = u32::MAX as usize; #[derive(Debug, Clone)] struct CSRNetworkData { - /// Offsets into `neighbors`/`weights`; length `n_nodes + 1`. Stays `usize`, since it - /// indexes an array with up to `2m` entries. + /// Offsets into `neighbors`/`weights`, length `n_nodes + 1`. `usize`, since it indexes + /// up to `2m` entries. node_ptrs: Vec, /// Neighbour ids, strictly increasing within each node's slice. neighbors: Vec, @@ -52,26 +41,23 @@ struct CSRNetworkData { total_weight: f64, /// Number of distinct undirected edges, self-loops included. edge_count: usize, - /// Whether any node carries a self-loop. - /// - /// Lets `self_loop_weight` skip its binary search on graphs without any — which the level-0 - /// graph, where most node visits happen, normally is. That search was ~4% of runtime. + /// Lets `self_loop_weight` skip its binary search, which the level-0 graph normally can. + /// That search was ~4% of runtime. any_self_loops: bool, } /// A weighted, undirected graph in compressed-sparse-row form. /// -/// Cloning is cheap: the underlying data is shared behind an [`Arc`]. See the module-level -/// documentation for the weight conventions and memory layout this type guarantees. +/// Cloning is cheap — the data is shared behind an [`Arc`]. #[derive(Debug, Clone)] pub struct CSRNetwork { data: Arc, } -/// Iterator over `(neighbor, weight)` pairs for one node. +/// Iterator over one node's `(neighbor, weight)` pairs. /// -/// Yields `usize`/`f64` regardless of the narrower storage types, so callers can index -/// directly and do arithmetic at full precision. +/// Yields `usize`/`f64` whatever the storage types, so callers can index and do arithmetic +/// directly. pub struct CSRNeighborIterator<'a> { neighbors: std::slice::Iter<'a, u32>, weights: std::slice::Iter<'a, f32>, @@ -96,11 +82,10 @@ impl Iterator for CSRNeighborIterator<'_> { impl ExactSizeIterator for CSRNeighborIterator<'_> {} impl CSRNetwork { - /// Builds a graph from an edge list, giving every node unit weight. + /// Builds a graph from an edge list, every node at unit weight. /// - /// Each undirected edge should be supplied **once**; `(u, v, w)` and `(v, u, w)` are two - /// parallel edges, not one. Parallel edges between the same pair are merged by summing - /// their weights. A `(v, v, w)` entry is a self-loop of weight `w`. + /// Give each undirected edge **once** — `(u, v, w)` and `(v, u, w)` are two parallel + /// edges, not one. Parallel edges are merged by summing. `(v, v, w)` is a self-loop. pub fn from_edges(n_nodes: usize, edges: &[(usize, usize, W)]) -> Result where W: FloatOpsTS + 'static, @@ -110,13 +95,12 @@ impl CSRNetwork { /// Builds a graph from an edge list with explicit node weights. /// - /// Node weight is a node's "size", and what CPM measures communities in. Usually all - /// `1.0` straight from data; it starts mattering after [`aggregate`](Self::aggregate), - /// where a super-node's weight is the sum of its members'. + /// Node weight is a node's "size" and what CPM measures. Usually all `1.0`; it starts + /// mattering after [`aggregate`](Self::aggregate), where a super-node's weight is the sum + /// of its members'. /// - /// Allocates the adjacency arrays once and sorts in place, so peak memory is the graph - /// plus the caller's edge list, not double. For very large inputs - /// [`from_csr_parts`](Self::from_csr_parts) needs no edge list at all. + /// Allocates once and sorts in place, so peak memory is the graph plus the caller's edge + /// list, not double. [`from_csr_parts`](Self::from_csr_parts) needs no edge list at all. pub fn from_edges_with_node_weights( edges: &[(usize, usize, W)], node_weights: Vec, @@ -166,22 +150,13 @@ impl CSRNetwork { Self::finish(node_ptrs, neighbors, weights, node_weights, true) } - /// Builds a graph directly from CSR arrays, taking ownership of them. + /// Builds a graph directly from CSR arrays, taking ownership. /// /// The low-memory entry point: nothing proportional to the edge count is allocated, so a - /// connectivity matrix you already hold — scanpy's `connectivities`, say — becomes a graph - /// with no copy. + /// connectivity matrix you already hold — scanpy's `connectivities`, say — costs no copy. /// /// Must be the **full symmetric** adjacency: if `j` is in row `i`, `i` must be in row `j` - /// with the same weight. Rows need not be sorted (they're sorted in place); duplicates - /// within a row are summed, and anything summing to zero is dropped. - /// - /// # Arguments - /// * `node_ptrs` - row offsets, length `n_nodes + 1`, non-decreasing, last equals - /// `neighbors.len()` - /// * `neighbors` - column indices - /// * `weights` - values, parallel to `neighbors` - /// * `node_weights` - per-node weights, or `None` for unit weights + /// at the same weight. Rows are sorted in place, duplicates summed, zero sums dropped. pub fn from_csr_parts( node_ptrs: Vec, neighbors: Vec, @@ -255,10 +230,9 @@ impl CSRNetwork { Self::finish(node_ptrs, neighbors, weights, node_weights, false) } - /// Sorts each row, merges duplicates, compacts, and derives the cached aggregates. + /// Sorts each row, merges duplicates, compacts, derives the cached aggregates. /// - /// `may_have_gaps` says whether compaction can shrink the arrays. Sorting borrows one - /// scratch buffer sized to the largest row, so the temporary is O(max degree), not O(m). + /// One scratch buffer sized to the largest row, so the temporary is O(max degree). fn finish( mut node_ptrs: Vec, mut neighbors: Vec, @@ -350,13 +324,11 @@ impl CSRNetwork { }) } - /// Builds a graph from a sparse adjacency matrix, giving every node unit weight. - /// - /// The matrix is treated as symmetric: only entries with `row <= col` are read, and a - /// diagonal entry `(v, v, w)` becomes a self-loop of weight `w`. Zero entries are skipped. + /// Builds a graph from a sparse adjacency matrix, every node at unit weight. /// - /// Allocates an intermediate edge list. For large inputs prefer - /// [`from_csr_parts`](Self::from_csr_parts). + /// Treated as symmetric: only `row <= col` is read, and a diagonal entry is a self-loop. + /// Allocates an intermediate edge list — prefer + /// [`from_csr_parts`](Self::from_csr_parts) for large inputs. pub fn from_csr_matrix(matrix: &CsrMatrix) -> Result where W: FloatOpsTS + 'static, @@ -390,10 +362,8 @@ impl CSRNetwork { Self::from_edges_with_node_weights(&edges, node_weights) } - /// Returns an iterator over the `(neighbor, weight)` pairs of a node. - /// - /// Neighbours are yielded in ascending id order, which is what makes candidate-community - /// enumeration deterministic. + /// A node's `(neighbor, weight)` pairs, in ascending id order — which is what makes + /// candidate enumeration deterministic. #[inline] pub fn neighbors(&self, node: usize) -> CSRNeighborIterator<'_> { let start = self.data.node_ptrs[node]; @@ -404,50 +374,49 @@ impl CSRNetwork { } } - /// Returns the number of nodes in the network. + /// Number of nodes. #[inline] pub fn node_count(&self) -> usize { self.data.node_weights.len() } - /// Returns the number of distinct undirected edges, self-loops included. + /// Distinct undirected edges, self-loops included. #[inline] pub fn edge_count(&self) -> usize { self.data.edge_count } - /// Returns the degree (number of distinct neighbours) of a node. + /// Number of distinct neighbours. #[inline] pub fn degree(&self, node: usize) -> usize { self.data.node_ptrs[node + 1] - self.data.node_ptrs[node] } - /// Returns the strength of a node: the sum of incident edge weights, with self-loops - /// counted twice. + /// Sum of incident edge weights, self-loops counted twice. #[inline] pub fn strength(&self, node: usize) -> f64 { self.data.strengths[node] } - /// Returns the weight ("size") of a node. + /// A node's weight, i.e. its "size". #[inline] pub fn node_weight(&self, node: usize) -> f64 { self.data.node_weights[node] } - /// Returns the total weight of all edges, each undirected edge counted once. + /// Total edge weight, each undirected edge once. #[inline] pub fn total_weight(&self) -> f64 { self.data.total_weight } - /// Returns the sum of all node weights. + /// Sum of all node weights. #[inline] pub fn total_node_weight(&self) -> f64 { self.data.node_weights.iter().sum() } - /// Returns the weight of a node's self-loop, or `0.0` if it has none. + /// A node's self-loop weight, or `0.0`. #[inline] pub fn self_loop_weight(&self, node: usize) -> f64 { if !self.data.any_self_loops { @@ -461,7 +430,7 @@ impl CSRNetwork { } } - /// Returns the weight of the edge between two nodes, or `None` if there is none. + /// Weight of the edge between two nodes, if there is one. pub fn edge_weight(&self, from: usize, to: usize) -> Option { // search the shorter row let (search_node, target) = if self.degree(from) <= self.degree(to) { @@ -477,10 +446,8 @@ impl CSRNetwork { } } - /// Returns copies of the underlying CSR arrays, as accepted by - /// [`from_csr_parts`](Self::from_csr_parts). - /// - /// Round-tripping through these is lossless. + /// Copies of the CSR arrays, as [`from_csr_parts`](Self::from_csr_parts) takes them. + /// Round-tripping is lossless. pub fn to_csr_parts(&self) -> (Vec, Vec, Vec) { ( self.data.node_ptrs.clone(), @@ -489,15 +456,12 @@ impl CSRNetwork { ) } - /// The per-node weights, as accepted by [`from_csr_parts`](Self::from_csr_parts). + /// Per-node weights, as [`from_csr_parts`](Self::from_csr_parts) takes them. pub fn node_weights(&self) -> &[f64] { &self.data.node_weights } - /// Approximate resident size of the graph in bytes. - /// - /// Useful for sizing a machine before running: at 75M nodes and 750M edges this is - /// roughly 14 GB. + /// Rough resident size in bytes — ~14 GB at 75M nodes and 750M edges. pub fn memory_bytes(&self) -> usize { let d = &self.data; d.node_ptrs.len() * size_of::() @@ -507,12 +471,11 @@ impl CSRNetwork { + d.strengths.len() * size_of::() } - /// Collapses each group into a single super-node. + /// Collapses each group into a super-node. /// - /// Node weights are summed, a group's internal weight becomes a self-loop, and weight - /// between groups becomes an ordinary edge. `total_weight` and `Σ strength` are both - /// preserved exactly, so quality doesn't change — which is what lets the multilevel scheme - /// optimize one objective across levels. + /// Node weights sum, a group's internal weight becomes a self-loop, weight between groups + /// becomes an edge. `total_weight` and `Σ strength` are preserved exactly, so quality + /// doesn't change across levels. pub fn aggregate(&self, grouping: &VectorGrouping) -> Self { let n = self.node_count(); let n_groups = grouping.group_count(); @@ -607,7 +570,7 @@ impl CSRNetwork { .expect("aggregate produces a structurally valid graph") } - /// Converts the network back to a symmetric sparse matrix. + /// Back to a symmetric sparse matrix. pub fn to_csr_matrix(&self) -> CsrMatrix { let n = self.node_count(); let row_ptrs = self.data.node_ptrs.clone(); @@ -617,13 +580,11 @@ impl CSRNetwork { .expect("CSR invariants are maintained by construction") } - /// Verifies that the adjacency is exactly symmetric. + /// Checks every stored `(v, u, w)` has its `(u, v, w)`. /// /// Constructors already enforce `Σ strength == 2 · total_weight`, which catches the - /// realistic mistakes (a k-NN graph nobody symmetrised). This is the exhaustive version: - /// for every stored `(v, u, w)`, check `(u, v, w)` is there too. - /// - /// O(m log d) — worth running once when wiring up a new input source, not every call. + /// realistic mistakes. This is the exhaustive version, O(m log d) — worth running once + /// when wiring up a new input source, not every call. pub fn validate_symmetry(&self) -> Result<()> { for v in 0..self.node_count() { for (u, w) in self.neighbors(v) { @@ -645,13 +606,13 @@ impl CSRNetwork { Ok(()) } - /// Returns `true` if any node carries a self-loop. + /// Whether any node carries a self-loop. #[inline] pub fn has_self_loops(&self) -> bool { self.data.any_self_loops } - /// Returns the fraction of possible edges that are present. + /// Fraction of possible edges present. pub fn density(&self) -> f64 { let n = self.node_count() as f64; let max_edges = n * (n - 1.0) / 2.0; @@ -697,18 +658,12 @@ fn check_edge(from: usize, to: usize, w: f64, n_nodes: usize) -> Result<()> { /// Checks `Σ strength == 2 · total_weight`. /// -/// This is the invariant the self-loop convention exists to maintain, and it is the cheapest -/// guard against the failure mode that motivated the 0.7 rewrite: a null model silently -/// switched off, producing plausible-looking but wrong clusters. -/// -/// Checked in **release builds too**, not just debug. It costs one O(n) pass against minutes -/// of clustering, and it is the only thing standing between an asymmetric input to -/// [`CSRNetwork::from_csr_parts`] and quietly corrupt results. It is a necessary condition for -/// symmetry, not a sufficient one — [`CSRNetwork::validate_symmetry`] is the exhaustive check. +/// Runs in release too: one O(n) pass against minutes of clustering, and it's the only thing +/// between an asymmetric input to [`CSRNetwork::from_csr_parts`] and quietly wrong clusters. +/// Necessary but not sufficient — [`CSRNetwork::validate_symmetry`] is exhaustive. /// -/// The tolerance is loose (`1e-6` relative) because both sides are naive f64 sums over -/// possibly hundreds of millions of terms, accumulated in different orders. Any real asymmetry -/// is off by whole edge weights, many orders of magnitude above that. +/// The `1e-6` relative tolerance is loose because both sides are naive f64 sums in different +/// orders. Real asymmetry is off by whole edge weights. fn check_degree_sum(data: &CSRNetworkData) -> Result<()> { let sum: f64 = data.strengths.iter().sum(); let expected = 2.0 * data.total_weight; @@ -851,7 +806,7 @@ mod tests { )); } - /// The zero-copy path must produce exactly the same graph as the edge-list path. + /// Zero-copy and edge-list paths must give exactly the same graph. #[test] fn from_csr_parts_matches_from_edges() { let edges = [ @@ -921,8 +876,7 @@ mod tests { )); } - /// The realistic catastrophic mistake: handing over a k-NN graph that was never - /// symmetrised. Node 0 lists node 1, but node 1 does not list node 0. + /// The realistic mistake: a kNN graph nobody symmetrised. #[test] fn asymmetric_input_is_rejected() { use crate::error::ClusteringError; @@ -962,8 +916,7 @@ mod tests { } } - /// A "balanced" asymmetry that the degree-sum check cannot see: two errors that cancel in - /// the totals. This is what `validate_symmetry` is for. + /// Asymmetry that cancels in the totals, so only `validate_symmetry` sees it. #[test] fn validate_symmetry_catches_what_the_degree_sum_cannot() { // strengths and total both balance, but neither edge agrees with its reverse diff --git a/src/network/mod.rs b/src/network/mod.rs index 4885538..caf70a1 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -1,11 +1,4 @@ -//! # Network Module -//! -//! This module provides the network/graph representation used by the clustering -//! algorithms, plus the grouping abstraction used to express partitions. -//! -//! ## Key Components -//! - [`CSRNetwork`] - compressed-sparse-row weighted undirected graph -//! - [`grouping`] - node-to-group assignments (partitions/clusterings) +//! Graph representation: [`CSRNetwork`] plus the [`grouping`] type partitions come back as. pub mod grouping; diff --git a/src/spatial/banksy.rs b/src/spatial/banksy.rs index 71bae20..d2a49d2 100644 --- a/src/spatial/banksy.rs +++ b/src/spatial/banksy.rs @@ -1,23 +1,14 @@ //! BANKSY-style feature augmentation. //! -//! Turns spatial domain detection into ordinary clustering: augment each cell's expression -//! with a summary of its neighbourhood, then run Leiden on the result exactly as you would -//! without coordinates. Nothing here knows about clustering. +//! Augments each cell's expression with a summary of its neighbourhood, so ordinary Leiden +//! finds spatial domains. Nothing here knows about clustering. //! -//! Every formula below was read from the reference implementation (`banksy-py`, -//! `banksy/main.py` and `banksy/embed_banksy.py`), not from the paper, and is pinned by -//! differential fixtures in `tests/fixtures/banksy_reference.json`. Two details are easy to -//! get wrong from the paper alone: +//! Formulas come from `banksy-py` (`main.py`, `embed_banksy.py`) rather than the paper, and +//! are pinned by fixtures in `tests/fixtures/banksy_reference.json`. Two things the paper +//! doesn't make obvious: the λ budget halves with each harmonic rather than splitting evenly +//! ([`scale_factors`]), and every block is z-scored per column before scaling. //! -//! * The λ budget is **not** split evenly across harmonics. Each successive harmonic gets -//! half the weight of the previous one, so at `max_m = 1` the mean takes ⅔ of λ and the -//! gradient ⅓ — see [`scale_factors`]. -//! * Every block is **z-scored per column before scaling**, so λ mixes standardised blocks -//! rather than raw ones. Without that, a block with larger variance dominates regardless -//! of λ. -//! -//! The weight matrix is row-normalised, hence asymmetric, so it is a -//! [`NeighbourhoodOperator`] rather than a [`CSRNetwork`](crate::network::CSRNetwork). +//! The weight matrix is row-normalised and so asymmetric — an operator, not a graph. use rayon::prelude::*; @@ -33,19 +24,16 @@ pub enum Decay { Reciprocal, /// `1 / r²`. ReciprocalSquared, - /// `exp(-(r / median_r)²)`, where `median_r` is the median neighbour distance **for that - /// cell**. Scale-free per cell, which is why it is the reference default. + /// `exp(-(r / median_r)²)`, `median_r` per cell. Scale-free, and the reference default. #[default] ScaledGaussian, - /// `exp(-((rank + 1) · 1.5 / k)²)`, assigned in order of distance. Ignores the distances - /// themselves, so it is unaffected by local density. + /// `exp(-((rank + 1) · 1.5 / k)²)` by distance rank. Ignores distances, so density-free. Ranked, } /// Row-normalised directed neighbour weights. /// -/// Not a graph: row normalisation makes it asymmetric, so `w[i][j] != w[j][i]`. It is an -/// operator applied to a feature matrix. +/// Not a graph — normalisation makes it asymmetric. An operator applied to a feature matrix. pub struct NeighbourhoodOperator { node_ptrs: Vec, neighbours: Vec, @@ -61,19 +49,15 @@ pub struct NeighbourhoodOperator { impl NeighbourhoodOperator { /// Builds the operator for harmonic `m` over `k` nearest neighbours. /// - /// `k` is explicit per harmonic rather than derived from `m`, because the two references - /// disagree: R takes a `k_geom` vector and uses `k_geom[m]` (both 18 for DLPFC), while - /// Python silently multiplies, `num_neighbours * (m + 1)`, so the same nominal settings - /// give the gradient twice the neighbourhood. R produced the published DLPFC numbers, so - /// its convention is the one exposed here — pass `k * (m + 1)` yourself to reproduce - /// Python. + /// `k` is explicit per harmonic because the references disagree: R uses `k_geom[m]`, + /// Python silently uses `k * (m + 1)`. R produced the published DLPFC numbers, so that's + /// the convention here — pass `k * (m + 1)` yourself to match Python. /// - /// Excludes the cell itself — its own expression enters the augmented matrix as its own - /// block, not through the neighbourhood. + /// Excludes the cell itself; its own expression is a separate block. /// /// # Errors /// - /// If `k` is zero or a coordinate is not finite. + /// If `k` is zero or a coordinate isn't finite. pub fn for_harmonic(coords: &[[f64; 2]], k: usize, m: usize, decay: Decay) -> Result { Self::knn(coords, k, decay, m) } @@ -106,8 +90,7 @@ impl NeighbourhoodOperator { let want = k.min(n.saturating_sub(1)); let grid = Grid::new(coords, typical_spacing(coords, want.max(1))); - // Nearest `want` neighbours per cell, with distances, sorted by (distance, id) so - // ties never depend on visit order. + // sorted by (distance, id) so ties don't depend on visit order let found: Vec> = coords .par_iter() .enumerate() @@ -153,8 +136,8 @@ impl NeighbourhoodOperator { let distances: Vec = row.iter().map(|&(_, d2)| d2.sqrt()).collect(); let mut w = decay_weights(&distances, decay); - // Row-normalise. Done *before* any phase factor, matching the reference: the - // magnitudes sum to 1, the complex weights do not. + // before any phase factor, like the reference: magnitudes sum to 1, the + // complex weights don't let sum: f64 = w.iter().sum(); if sum > 0.0 { for x in &mut w { @@ -193,18 +176,15 @@ impl NeighbourhoodOperator { self.m } - /// Applies this operator's harmonic to a feature matrix. - /// - /// `m = 0` is the plain weighted neighbourhood mean. For `m >= 1` the weights carry a - /// phase `exp(i·m·θ)`, and the result is the **magnitude** of the complex sum — large - /// where a gene varies systematically with direction, near zero where the neighbourhood - /// looks the same all round. That is the "gradient" term. + /// Applies this operator's harmonic to a row-major `n_cells × n_features` matrix. /// - /// `features` is row-major, `n_cells × n_features`. + /// `m = 0` is the weighted neighbourhood mean. For `m >= 1` weights carry a phase + /// `exp(i·m·θ)` and the result is the magnitude of the complex sum — large where a gene + /// varies with direction, near zero where the neighbourhood looks the same all round. /// /// # Errors /// - /// If `features` does not match the cell count. + /// If `features` doesn't match the cell count. pub fn apply(&self, features: &[f64], n_features: usize) -> Result> { let m = self.m; if n_features == 0 { @@ -233,12 +213,9 @@ impl NeighbourhoodOperator { } } } else { - // Centre on this cell's neighbourhood before taking the phase sum. - // Without it the result measures the neighbourhood's overall level as - // well as its directional variation, because the phase sum - // `sum_j w_ij e^{i m phi}` is generally non-zero, so subtracting a - // constant is not a no-op. Easy to miss: it lives in the reference's - // matrix builder, not in its weight construction. + // centre on this cell's neighbourhood first. The phase sum is generally + // non-zero, so skipping this mixes in the overall level. Lives in the + // reference's matrix builder, not its weight construction. let mut centre = vec![0.0f64; n_features]; for e in span.clone() { let (w, j) = (self.weights[e], self.neighbours[e] as usize); @@ -273,7 +250,7 @@ impl NeighbourhoodOperator { } } -/// Unnormalised weights for one cell's neighbour distances. +/// Unnormalised weights for one cell's neighbours. fn decay_weights(distances: &[f64], decay: Decay) -> Vec { match decay { Decay::Uniform => vec![1.0; distances.len()], @@ -282,7 +259,7 @@ fn decay_weights(distances: &[f64], decay: Decay) -> Vec { Decay::ScaledGaussian => { let mut sorted = distances.to_vec(); sorted.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); - // numpy's median: mean of the middle two on even counts. + // numpy's median: mean of the middle two on even counts let n = sorted.len(); let median = if n == 0 { 0.0 @@ -298,7 +275,7 @@ fn decay_weights(distances: &[f64], decay: Decay) -> Vec { } Decay::Ranked => { let k = distances.len(); - // Rank by distance, then assign a fixed decreasing profile in that order. + // rank by distance, then a fixed decreasing profile in that order let mut order: Vec = (0..k).collect(); order.sort_unstable_by(|&a, &b| { distances[a] @@ -316,10 +293,9 @@ fn decay_weights(distances: &[f64], decay: Decay) -> Vec { } } -/// Column z-scores, using the **population** variance `E[x²] − E[x]²`. +/// Column z-scores on the population variance `E[x²] − E[x]²`. /// -/// Not the sample variance — the reference divides by `n`, not `n − 1`, and a column with -/// zero variance becomes zero rather than NaN. +/// The reference divides by `n`, not `n − 1`. Zero-variance columns come out zero, not NaN. fn zscore_columns(matrix: &mut [f64], n_rows: usize, n_cols: usize) { if n_rows == 0 || n_cols == 0 { return; @@ -344,11 +320,8 @@ fn zscore_columns(matrix: &mut [f64], n_rows: usize, n_cols: usize) { /// Block scale factors for `max_m` harmonics at neighbourhood contribution `lambda`. /// -/// Returns `max_m + 2` factors: own expression first, then one per harmonic. -/// -/// **Each harmonic gets half the weight of the one before it**, not an equal share. With -/// `max_m = 1` that makes the mean ⅔ of λ and the gradient ⅓ — assuming an even split would -/// over-weight the gradient by a factor of two. +/// `max_m + 2` factors: own expression first, then one per harmonic. Each harmonic gets half +/// the weight of the one before, so at `max_m = 1` the mean takes ⅔ of λ and the gradient ⅓. pub fn scale_factors(max_m: usize, lambda: f64) -> Vec { let n_blocks = max_m + 1; let mut squared = vec![0.0f64; n_blocks + 1]; @@ -361,10 +334,10 @@ pub fn scale_factors(max_m: usize, lambda: f64) -> Vec { squared.iter().map(|&s| s.max(0.0).sqrt()).collect() } -/// Assembles the augmented matrix from the own-expression block and the harmonic blocks. +/// Assembles the augmented matrix from the own-expression and harmonic blocks. /// -/// Each block is z-scored per column and then scaled, so λ mixes standardised blocks. The -/// result is `n_cells × (n_features · (max_m + 2))`, row-major, ready to PCA and cluster. +/// Blocks are z-scored per column then scaled, so λ mixes standardised blocks. Result is +/// `n_cells × (n_features · (max_m + 2))`, row-major, ready to PCA and cluster. /// /// # Errors /// @@ -421,13 +394,12 @@ pub fn banksy_matrix( /// One-call BANKSY augmentation. /// -/// Builds the neighbourhood operator, applies harmonics `0..=max_m`, and assembles the -/// augmented matrix. `lambda = 0.2` and `k = 18` are the reference's Visium settings for -/// domain segmentation; `max_m = 1` includes the gradient term. +/// `lambda = 0.2`, `k = 18` are the reference's Visium domain settings; `max_m = 1` adds the +/// gradient term. /// /// # Errors /// -/// If any argument is out of range or the feature matrix does not match the cell count. +/// If an argument is out of range or the feature matrix doesn't match the cell count. pub fn banksy_augment( coords: &[[f64; 2]], features: &[f64], @@ -445,7 +417,7 @@ pub fn banksy_augment( banksy_matrix(features, &harmonics, coords.len(), n_features, lambda) } -/// A cell size that puts roughly `k` points in each grid cell. +/// Cell size putting roughly `k` points per grid cell. fn typical_spacing(points: &[[f64; 2]], k: usize) -> f64 { let (mut min, mut max) = ([f64::INFINITY; 2], [f64::NEG_INFINITY; 2]); for p in points { diff --git a/src/spatial/combine.rs b/src/spatial/combine.rs index a4ee9c7..f7f4d4a 100644 --- a/src/spatial/combine.rs +++ b/src/spatial/combine.rs @@ -1,8 +1,7 @@ //! Combining graphs, and building them per sample. //! -//! Two operations that both exist because real experiments are not one clean tissue section: -//! you usually have an expression graph *and* a spatial graph over the same cells, and you -//! usually have several slices rather than one. +//! Real experiments give you an expression graph *and* a spatial graph over the same cells, +//! and several slices rather than one. use crate::error::{ClusteringError, Result}; use crate::network::CSRNetwork; @@ -10,11 +9,8 @@ use crate::network::CSRNetwork; /// How to put two graphs on comparable footing before mixing them. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum Normalization { - /// Mix the weights as they are. - /// - /// Almost never what you want across an expression and a spatial graph: their weights - /// live on unrelated scales, so whichever is larger dominates at every `alpha` and the - /// parameter stops meaning anything. + /// Mix the weights as they are. Rarely right across expression and spatial graphs — + /// their scales are unrelated, so the larger one dominates at every `alpha`. None, /// Scale each graph so its total edge weight is 1, so `alpha` divides a fixed budget. #[default] @@ -23,16 +19,13 @@ pub enum Normalization { /// Blends two graphs over the same nodes: `alpha · a + (1 − alpha) · b`. /// -/// An edge present in only one contributes only its own side, so the result is the union of -/// the two edge sets. Both graphs must cover the same nodes. -/// -/// With [`Normalization::TotalWeight`] each graph is first scaled to unit total weight, which -/// is what makes `alpha` behave like a proportion rather than an arbitrary knob. It is the -/// same problem the BANKSY blocks solve by z-scoring, and the same fix. +/// The result is the union of the two edge sets. [`Normalization::TotalWeight`] scales each +/// graph to unit total weight first, which is what makes `alpha` a proportion rather than an +/// arbitrary knob — same problem the BANKSY blocks solve by z-scoring. /// /// # Errors /// -/// If the graphs have different node counts, or `alpha` is outside `[0, 1]`. +/// If the node counts differ, or `alpha` is outside `[0, 1]`. pub fn fuse( a: &CSRNetwork, b: &CSRNetwork, @@ -65,8 +58,7 @@ pub fn fuse( }; let (wa, wb) = (alpha * sa, (1.0 - alpha) * sb); - // Merge each node's two neighbour lists. Both are sorted ascending, so this is a linear - // two-pointer walk and the output stays sorted. + // both lists are sorted, so a two-pointer merge keeps the output sorted let mut node_ptrs = Vec::with_capacity(n + 1); node_ptrs.push(0usize); let mut neighbors: Vec = Vec::new(); @@ -105,7 +97,7 @@ pub fn fuse( CSRNetwork::from_csr_parts(node_ptrs, neighbors, weights, None) } -/// Reciprocal of a total weight, or 1.0 when there is nothing to scale. +/// Reciprocal of a total weight, or 1.0 if there's nothing to scale. fn scale_to_unit(total: f64) -> f64 { if total > 0.0 && total.is_finite() { 1.0 / total @@ -116,18 +108,16 @@ fn scale_to_unit(total: f64) -> f64 { /// Runs a graph builder separately within each sample and reassembles one graph. /// -/// Spatial neighbours are only meaningful within a slice: two cells on different sections are -/// not adjacent however close their stored coordinates happen to be, and sections are often -/// laid out overlapping in the same coordinate space. Building globally and deleting -/// cross-sample edges afterwards is **not** equivalent for k-nearest builders — a cell at a -/// section's edge would lose neighbours rather than take k from its own section. So the -/// builder runs per sample. +/// Cells on different sections aren't adjacent however close their stored coordinates are, +/// and sections often overlap in the same frame. Building globally and deleting cross-sample +/// edges afterwards isn't equivalent for kNN — a cell at a section's edge would lose +/// neighbours rather than take k from its own section. /// -/// `samples` labels each point. Node indices in the result are the caller's original ones. +/// `samples` labels each point; result indices are the caller's originals. /// /// # Errors /// -/// If `samples` does not match the point count, or the builder fails on a sample. +/// If `samples` doesn't match the point count, or the builder fails on a sample. pub fn per_sample(points: &[[f64; 2]], samples: &[u32], build: F) -> Result where F: Fn(&[[f64; 2]]) -> Result, @@ -143,8 +133,7 @@ where return CSRNetwork::from_csr_parts(vec![0], Vec::new(), Vec::new(), None); } - // Group point indices by sample, keeping each group in ascending original order so the - // result never depends on how the samples were labelled. + // ascending original order within each group, so labelling can't change the result let mut order: Vec = (0..n as u32).collect(); order.sort_by_key(|&v| (samples[v as usize], v)); @@ -216,7 +205,7 @@ mod tests { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); let mut pts = Vec::new(); let mut samples = Vec::new(); - // Deliberately overlapping coordinates: two sections stored in the same frame. + // overlapping on purpose: two sections in the same frame for s in 0..2u32 { for _ in 0..300 { pts.push([rng.random::() * 50.0, rng.random::() * 50.0]); @@ -256,8 +245,7 @@ mod tests { f.validate_symmetry().unwrap(); } - /// The point of normalising: without it, the graph with heavier weights wins whatever - /// alpha says. + /// Without normalising, the heavier graph wins whatever alpha says. #[test] fn normalisation_stops_one_graph_dominating() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(3); @@ -265,14 +253,14 @@ mod tests { .map(|_| [rng.random::() * 30.0, rng.random::() * 30.0]) .collect(); let light = radius_graph(&pts, 3.0, SpatialWeight::Uniform, None).unwrap(); - // Same shape, weights a thousand times larger. + // same shape, weights a thousand times larger let heavy = { let (ptrs, nbrs, w) = light.to_csr_parts(); CSRNetwork::from_csr_parts(ptrs, nbrs, w.iter().map(|x| x * 1000.0).collect(), None) .unwrap() }; - // Normalised, an even blend of a graph with itself is that graph, whatever the scale. + // normalised, an even blend of a graph with itself is that graph let fused = fuse(&light, &heavy, 0.5, Normalization::TotalWeight).unwrap(); let first = fused.neighbors(0).next().unwrap().1; for v in 0..fused.node_count() { @@ -284,7 +272,7 @@ mod tests { } } - // Unnormalised, the heavy graph contributes ~1000x as much. + // unnormalised, the heavy graph contributes ~1000x as much let raw = fuse(&light, &heavy, 0.5, Normalization::None).unwrap(); let w = raw.neighbors(0).next().unwrap().1; assert!(w > 400.0, "expected the heavy graph to dominate, got {w}"); @@ -305,8 +293,7 @@ mod tests { assert!(fuse(&a, &a, f64::NAN, Normalization::TotalWeight).is_err()); } - /// Cells in different sections must never be joined, even where their coordinates - /// coincide — which they do here by construction. + /// Different sections must never be joined, even where coordinates coincide. #[test] fn per_sample_never_joins_two_slices() { let (pts, samples) = two_slices(5); @@ -332,8 +319,8 @@ mod tests { } } - /// The reason it builds per sample rather than filtering afterwards: with kNN, a cell at - /// a section's edge must take k neighbours from its own section, not lose them. + /// Why it builds per sample: a cell at a section's edge must take k from its own + /// section, not lose them. #[test] fn per_sample_knn_keeps_every_cell_at_full_degree() { let (pts, samples) = two_slices(6); @@ -346,7 +333,7 @@ mod tests { assert!(g.degree(v) >= k, "node {v} has degree {}", g.degree(v)); } - // Build globally and delete cross-sample edges, and cells lose neighbours instead. + // build globally and delete afterwards, and cells lose neighbours instead let global = knn_graph(&pts, k, Symmetry::Union, SpatialWeight::Uniform).unwrap(); let starved = (0..global.node_count()) .filter(|&v| { @@ -367,7 +354,7 @@ mod tests { #[test] fn per_sample_handles_edge_cases() { let pts = vec![[0.0, 0.0], [1.0, 0.0], [50.0, 50.0]]; - // A sample of one has no neighbours, and must not break the reassembly. + // a sample of one has no neighbours, and must not break reassembly let samples = vec![0u32, 0, 1]; let g = per_sample(&pts, &samples, |sub| { radius_graph(sub, 5.0, SpatialWeight::Uniform, None) @@ -400,7 +387,7 @@ mod tests { ); } - /// Sample labels are arbitrary; only the grouping matters. + /// Labels are arbitrary, only the grouping matters. #[test] fn per_sample_is_independent_of_label_values() { let (pts, samples) = two_slices(7); diff --git a/src/spatial/delaunay.rs b/src/spatial/delaunay.rs index c6a6625..8e0c7c8 100644 --- a/src/spatial/delaunay.rs +++ b/src/spatial/delaunay.rs @@ -1,45 +1,11 @@ //! Delaunay neighbour graphs. //! -//! Parameter-free: no radius, no `k`. Each cell is joined to the ones it actually borders, -//! and the triangulation adapts to local density on its own — dense regions get short edges, -//! sparse regions long ones, with no threshold to tune. Average degree is just under 6, since -//! a triangulation of `n` points with `h` on the convex hull has exactly `3n - 3 - h` edges. +//! No radius, no `k` — each cell joins the ones it borders, and the triangulation adapts to +//! local density on its own. Mean degree is just under 6: a triangulation of `n` points with +//! `h` on the hull has exactly `3n - 3 - h` edges. //! -//! # Why pruning is still needed -//! -//! A triangulation covers the *convex hull* of the points, so it invents edges wherever the -//! tissue is not convex: across ventricles and vessels, around concave boundaries, and -//! between physically separate fragments on the same section. Those edges are long, and -//! joining two sides of a hole is exactly the kind of error that produces a plausible-looking -//! but meaningless domain. -//! -//! Note that the parameter-free subgraphs — Gabriel, relative-neighbourhood — do **not** fix -//! this. Their tests ask whether other points lie near the edge, and the whole point of a -//! hole is that nothing does, so a hole-spanning edge passes. Measured on two detached -//! fragments, Gabriel leaves 19 of 42 bridges standing and drops 21% of genuine edges -//! elsewhere; the relative-neighbourhood graph drops 52%. Removing an artefact edge needs a -//! rule about length. See [`HullPruning`]. -//! -//! They may still be worth adding as an option one day — MST ⊆ RNG ⊆ GG ⊆ Delaunay, both are -//! always connected, and Lingas (1994) extracts either from an existing triangulation in -//! O(n), so they are nearly free once the Delaunay exists. Two things to get right if so: -//! use the **open** exclusion region, since the closed variant disconnects on ties and -//! gridded coordinates are made of ties; and expect mean degree ~4 for Gabriel and ~2.56 for -//! RNG against Delaunay's 6. -//! -//! # What other tools do -//! -//! Worth knowing, because the defaults differ sharply: -//! -//! * **squidpy** applies no pruning at all — `delaunay=True` returns the raw triangulation, -//! convex hull included. Its `radius` and `percentile` filters both default to off, and in -//! 1.6.x a scalar `radius` is *silently ignored* on the Delaunay path. -//! * **Giotto** is the only one that derives a cutoff automatically, using a global Tukey -//! whisker over all edge lengths. Being global, it fails exactly where tissue density -//! varies: on a dense block beside 24x sparser stroma it shatters the sparse side into -//! ~570 components while barely touching the dense one. -//! -//! That is the case for a local rule, and why [`HullPruning::Adaptive`] is the default here. +//! Pruning is still needed, because a triangulation covers the convex hull and so invents +//! edges across holes and between separate fragments. See `docs/spatial-graphs.md`. use crate::error::{ClusteringError, Result}; use crate::network::{CSRNetwork, MAX_NODES}; @@ -48,45 +14,23 @@ use crate::spatial::points::SpatialWeight; /// How to drop the edges a triangulation invents across empty space. #[derive(Debug, Clone, Copy, PartialEq)] pub enum HullPruning { - /// Keep the whole triangulation. Correct only when the tissue really is convex and - /// gap-free, which is rare. + /// Keep everything. Only right when the tissue is convex and gap-free, which is rare. None, - /// Drop edges longer than this, in coordinate units. Use when the tissue has a known - /// scale and roughly uniform density. + /// Drop edges longer than this, in coordinate units. Wants a known scale and roughly + /// uniform density. MaxDistance(f64), - /// Drop the longest `fraction` of all edges. - /// - /// One global cutoff, so it over-prunes sparse regions and under-prunes dense ones - /// whenever density varies — which in tissue it always does. + /// Drop the longest `fraction` of all edges. One global cutoff, so it over-prunes sparse + /// regions and under-prunes dense ones wherever density varies. Percentile { /// Share of edges to drop, in `[0, 1)`. fraction: f64, }, - /// Drop an edge longer than `factor` times the local edge scale at **both** its - /// endpoints, where local scale is a low quantile of a node's incident edge lengths. - /// - /// Compares against `max` of the two scales rather than `min`, so an edge that is long - /// only because one end sits in sparse tissue survives — a real boundary between a dense - /// nest and loose stroma should stay connected. A hole-spanning edge is long relative to - /// both ends and goes. - /// - /// The default of 2.0 is measured, by `calibrate_adaptive_factor`: it is the largest - /// factor that fully separates two detached tissue fragments, which is the one - /// unambiguous requirement — separate pieces must never be joined. It costs about 5% of - /// edges on uniform-random points, and less on real tissue, whose cells pack more - /// regularly than a Poisson process. - /// - /// It also happens to be the canonical value. Zahn's 1971 inconsistent-edge criterion is - /// this same shape — an edge "significantly larger than the average of nearby edge - /// weights on **both sides** of the edge" — and he reports that "a factor of 2 usually - /// means the separation is quite apparent", with worked examples spanning 1.3 to 2.6. + /// Drop an edge longer than `factor` times the local edge scale at **both** endpoints. /// - /// Two things it will not do. It cannot clear a hole only two or three cells across: - /// that needs a factor near 1.5, which drops ~16% of genuine edges everywhere, and at - /// that width it is arguable whether the cells either side are neighbours at all. And, - /// as Zahn notes of the same criterion, it "doesn't detect one-way gradients however - /// steep" — a tissue whose density ramps smoothly across the section has no local - /// discontinuity for the rule to find. + /// Compares against the larger of the two scales, so an edge that's long only because one + /// end sits in sparse tissue survives. A hole-spanning edge is long at both ends and goes. + /// The default 2.0 is measured by `calibrate_adaptive_factor`; see + /// `docs/spatial-graphs.md`. Adaptive { /// Multiple of the local scale above which an edge is dropped. factor: f64, @@ -124,15 +68,13 @@ impl HullPruning { /// Builds a Delaunay neighbour graph from 2D coordinates. /// -/// 2D only — the 3D equivalent is a tetrahedralisation, which is a different algorithm and a -/// much heavier dependency. For 3D use [`radius_graph`](super::radius_graph) or -/// [`knn_graph`](super::knn_graph). +/// 2D only. For 3D use [`radius_graph`](super::radius_graph) or [`knn_graph`](super::knn_graph). /// /// # Errors /// -/// If the points are degenerate (all collinear, or fewer than three distinct positions), so -/// no triangulation exists. That is reported rather than returning an empty graph, since an -/// edgeless graph would cluster into singletons and look like a result. +/// Degenerate points (all collinear, or fewer than three distinct positions) have no +/// triangulation. That's an error rather than an empty graph, which would cluster into +/// singletons and look like a result. pub fn delaunay_graph( points: &[[f64; 2]], pruning: HullPruning, @@ -156,7 +98,7 @@ pub fn delaunay_graph( if n < 2 { return CSRNetwork::from_csr_parts(vec![0; n + 1], Vec::new(), Vec::new(), None); } - // Two points have no triangle but do border each other. + // two points make no triangle but do border each other if n == 2 { let d2 = distance_sq(points[0], points[1]); return build(n, &[(0, 1, d2)], weight); @@ -171,8 +113,7 @@ pub fn delaunay_graph( return Err(ClusteringError::DegenerateTriangulation { n_points: n }); } - // Each triangle contributes three edges; neighbouring triangles share them, so collect - // into a set keyed on the ordered pair. + // neighbouring triangles share edges, so dedup on the ordered pair let mut edges: Vec<(u32, u32, f64)> = Vec::with_capacity(tri.triangles.len()); for t in tri.triangles.chunks_exact(3) { for &(a, b) in &[(t[0], t[1]), (t[1], t[2]), (t[2], t[0])] { @@ -220,7 +161,7 @@ fn prune(edges: &[(u32, u32, f64)], n: usize, pruning: HullPruning) -> Vec<(u32, .iter() .copied() .filter(|&(a, b, d2)| { - // Squared throughout, so the factor is squared too. + // squared throughout, so the factor is too let s = scale[a as usize].max(scale[b as usize]); d2 <= f2 * s }) @@ -229,16 +170,13 @@ fn prune(edges: &[(u32, u32, f64)], n: usize, pruning: HullPruning) -> Vec<(u32, } } -/// Quantile of incident edge length used as a node's local spacing. +/// Quantile of incident edge length taken as a node's local spacing. /// -/// Deliberately below the median. A node on the rim of a hole has several long edges reaching -/// across it, and those drag its median up until the spurious edges look normal — the median -/// hides exactly what we are trying to find. A lower quantile reads the genuine local -/// spacing, since at least a quarter of any node's edges go to real neighbours. +/// Below the median on purpose: a rim node's long edges drag its median up until the spurious +/// ones look normal. A quarter of any node's edges go to real neighbours. const SCALE_QUANTILE: f64 = 0.25; -/// Squared local length scale per node. One small sort each, since Delaunay degree averages -/// just under 6. +/// Squared local length scale per node. One small sort each — degree averages under 6. fn local_scale(edges: &[(u32, u32, f64)], n: usize) -> Vec { let mut incident: Vec> = vec![Vec::new(); n]; for &(a, b, d2) in edges { @@ -258,7 +196,7 @@ fn local_scale(edges: &[(u32, u32, f64)], n: usize) -> Vec { .collect() } -/// Turns an undirected edge list into a symmetric graph. +/// Undirected edge list to symmetric CSR. fn build(n: usize, edges: &[(u32, u32, f64)], weight: SpatialWeight) -> Result { let mut degree = vec![0u32; n]; for &(a, b, _) in edges { @@ -302,7 +240,7 @@ mod tests { .collect() } - /// A square of tissue with a circular hole punched out of the middle. + /// Square of tissue with a hole punched in the middle. fn tissue_with_hole(seed: u64) -> (Vec<[f64; 2]>, [f64; 2], f64) { tissue_with_hole_radius(seed, 15.0) } @@ -319,7 +257,7 @@ mod tests { (pts, centre, hole) } - /// Tissue in two pieces with a gap between, as a torn or folded section gives. + /// Two pieces with a gap, as a torn or folded section gives. fn two_fragments(seed: u64) -> Vec<[f64; 2]> { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); (0..2000) @@ -330,7 +268,7 @@ mod tests { .collect() } - /// Does the segment a-b pass through the disc? + /// Does segment a-b pass through the disc? fn crosses(a: [f64; 2], b: [f64; 2], centre: [f64; 2], r: f64) -> bool { let (dx, dy) = (b[0] - a[0], b[1] - a[1]); let len2 = dx * dx + dy * dy; @@ -352,8 +290,7 @@ mod tests { out } - /// Euler's formula: a Delaunay triangulation of `n` points with `h` on the convex hull - /// has exactly `3n - 3 - h` edges. Nothing approximate about it. + /// Euler: `n` points with `h` on the hull give exactly `3n - 3 - h` edges. #[test] fn unpruned_edge_count_matches_eulers_formula() { for (n, seed) in [(50usize, 1u64), (500, 2), (2000, 3)] { @@ -367,13 +304,13 @@ mod tests { let h = delaunator::triangulate(&coords).hull.len(); assert_eq!(g.edge_count(), 3 * n - 3 - h, "n={n}, hull={h}"); - // Which puts average degree just under 6. + // average degree just under 6 let avg = 2.0 * g.edge_count() as f64 / n as f64; assert!(avg < 6.0 && avg > 5.0, "average degree {avg} at n={n}"); } } - /// The reason pruning exists: a triangulation spans holes, and the default must not. + /// Why pruning exists: a triangulation spans holes, the default must not. #[test] fn adaptive_pruning_clears_a_tissue_hole() { let (pts, centre, hole) = tissue_with_hole(7); @@ -395,9 +332,8 @@ mod tests { "the hole should be bridged before pruning: {before}" ); assert_eq!(after, 0, "{after} edges still cross the hole"); - // And it must not gut the rest of the graph. The default costs ~5% on uniform-random - // points, which are less regularly packed than real cells, so this is the pessimistic - // end of the range. + // and it must not gut the rest. ~5% on uniform-random points, which pack less + // regularly than real cells, so this is the pessimistic end. assert!( pruned.edge_count() as f64 > 0.92 * raw.edge_count() as f64, "pruning removed {} of {} edges", @@ -406,8 +342,8 @@ mod tests { ); } - /// Why the rule compares against `max` of the two local scales, not `min`: a genuine - /// boundary between dense and sparse tissue has to survive. + /// Why the rule uses `max` of the two scales, not `min`: a real dense/sparse boundary + /// has to survive. #[test] fn adaptive_pruning_keeps_a_dense_to_sparse_boundary() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(5); @@ -434,8 +370,7 @@ mod tests { ); } - /// Sweeps the one tuned constant across every artefact it has to remove and everything it - /// must not, over several seeds, so the default is a measurement rather than a guess. + /// Sweeps the one tuned constant over several seeds, so the default is measured. /// /// A large hole is easy and tells you little. The discriminating cases are a /// capillary-scale hole a few cell spacings across, and two separated fragments. diff --git a/src/spatial/grid.rs b/src/spatial/grid.rs index 4961618..b93796b 100644 --- a/src/spatial/grid.rs +++ b/src/spatial/grid.rs @@ -1,13 +1,11 @@ //! Uniform-grid spatial index. //! -//! Tissue is close to uniformly dense, so bucketing points into fixed cells beats a tree: -//! queries are O(points nearby) with no traversal, duplicates and collinear runs are ordinary -//! inputs rather than pathological ones, and there is nothing approximate anywhere. +//! Tissue is close to uniformly dense, so fixed cells beat a tree: queries are O(points +//! nearby), duplicates and collinear runs are ordinary inputs, and nothing is approximate. //! -//! It also replaces a dependency that turned out to be wrong. `kiddo` 5.2.2's `KdTree` panics -//! once more than 32 points share a coordinate on one axis — which every Visium row does — -//! and its `ImmutableKdTree` returns neighbour *ids* that do not match the coordinates it -//! measured, so a graph built from it joins each cell to someone else's neighbours. +//! It also replaces `kiddo` 5.2.2, which was wrong here. Its `KdTree` panics once more than +//! 32 points share an axis value — every Visium row does — and its `ImmutableKdTree` returns +//! ids that don't match the coordinates it measured. /// Points bucketed into cells of a fixed size, stored CSR-style. pub(crate) struct Grid { @@ -20,10 +18,8 @@ pub(crate) struct Grid { } impl Grid { - /// Buckets `points` into cells of roughly `target_cell`. - /// - /// The cell size is enlarged if it would need more cells than points, so a handful of - /// far-flung outliers cannot make the index enormous. + /// Buckets `points` into cells of roughly `target_cell`, enlarging if that would need + /// more cells than points. pub(crate) fn new(points: &[[f64; D]], target_cell: f64) -> Self { debug_assert!(!points.is_empty()); let mut min = [f64::INFINITY; D]; @@ -35,8 +31,7 @@ impl Grid { } } - // Cap total cells at ~2 per point: sparse data gets coarser cells rather than a - // gigantic mostly-empty index. + // ~2 cells per point max, so sparse data gets coarser cells not a huge empty index let mut cell = target_cell.max(f64::MIN_POSITIVE); let mut dims = [0usize; D]; loop { @@ -116,18 +111,18 @@ impl Grid { .fold(0usize, |r, (&c, &dim)| r.max(c).max(dim - 1 - c)) } - /// Calls `f` for every point in a cell at Chebyshev distance exactly `ring` from `centre`. + /// Calls `f` for every point at Chebyshev distance exactly `ring` from `centre`. /// - /// Walking one ring at a time is what lets a k-nearest search stop as soon as its current - /// k-th distance is provably better than anything left unvisited. + /// One ring at a time, so a kNN search can stop once its k-th distance beats everything + /// left unvisited. pub(crate) fn for_each_in_ring( &self, centre: &[usize; D], ring: usize, mut f: impl FnMut(u32), ) { - // Clamp each axis to the grid, then walk the box with an odometer, skipping the - // interior — those cells belong to a smaller ring and were visited already. + // clamp to the grid, then odometer over the box, skipping the interior (already + // visited as a smaller ring) let mut lo = [0usize; D]; let mut hi = [0usize; D]; for d in 0..D { @@ -152,7 +147,7 @@ impl Grid { } } - // Odometer step over the clamped box. + // odometer step let mut d = D; loop { if d == 0 { diff --git a/src/spatial/lattice.rs b/src/spatial/lattice.rs index 0e6eb6f..53b3af8 100644 --- a/src/spatial/lattice.rs +++ b/src/spatial/lattice.rs @@ -1,25 +1,16 @@ //! Neighbour graphs for observations on a regular lattice. //! -//! Visium spots and Visium HD bins sit on a known grid, so their neighbours follow from -//! integer arithmetic — no spatial index, no distance computation, nothing approximate. -//! At HD scale (millions of bins) that is the difference between seconds and minutes. +//! Visium spots and HD bins sit on a known grid, so neighbours are integer arithmetic — no +//! spatial index, nothing approximate. At HD scale that's seconds instead of minutes. //! -//! # Why not distance-based -//! -//! `squidpy.gr.spatial_neighbors` ignores the lattice and runs Euclidean kNN on the float -//! pixel coordinates, keeping edges under `median(dist) * 1.3`. On contiguous tissue that -//! reproduces the lattice exactly, but the cutoff is global, so on a sparse or fragmented -//! lattice it bridges the gaps: at 50% occupancy roughly half the edges it produces are not -//! lattice-adjacent, and at 20% it is three quarters. Working from the integers is exact -//! everywhere and needs no heuristic. -//! -//! # The anisotropy trap +//! `squidpy.gr.spatial_neighbors` instead runs Euclidean kNN on pixel coordinates with a +//! global cutoff, which bridges gaps on a sparse lattice: at 50% occupancy about half its +//! edges aren't lattice-adjacent, at 20% three quarters. //! //! Never run Euclidean kNN on raw doubled coordinates. In-row neighbours are 2 units apart -//! while diagonal ones are only √2, so a metric method silently drops the two in-row -//! neighbours and returns a diagonal-only graph — wrong, and wrong in a way that still looks -//! like a plausible clustering. [`visium_isometric_coords`] rescales to a space where all six -//! neighbours are equidistant; use it for anything distance-based. +//! and diagonal ones only √2, so a metric method drops the in-row pair and hands back a +//! diagonal-only graph that still clusters plausibly. [`visium_isometric_coords`] rescales so +//! all six are equidistant. use crate::error::{ClusteringError, Result}; use crate::network::{CSRNetwork, MAX_NODES}; @@ -38,8 +29,7 @@ pub enum Lattice { } impl Lattice { - /// Half the neighbour offsets — enough that each undirected edge is generated exactly - /// once, by its lower endpoint in (row, col) order. The other half are these negated. + /// Half the offsets, so each undirected edge is emitted once by its lower endpoint. const fn forward_offsets(self) -> &'static [(i64, i64)] { match self { Self::VisiumHex => &[(0, 2), (1, -1), (1, 1)], @@ -48,7 +38,7 @@ impl Lattice { } } - /// Neighbours an interior position has. Only used for documentation and tests. + /// Neighbours an interior position has. Docs and tests only. pub const fn degree(self) -> usize { match self { Self::VisiumHex => 6, @@ -77,12 +67,11 @@ impl RowIndex { /// Builds a neighbour graph from integer lattice coordinates. /// -/// `rows` and `cols` give each observation's position; every edge has weight 1.0. Positions -/// that are absent — tissue-masked spots, trimmed bins — simply have no edge there, so a -/// partial capture area needs no special handling. +/// Every edge has weight 1.0. Absent positions — masked spots, trimmed bins — just have no +/// edge, so a partial capture area needs no special handling. /// -/// Since the graph is exactly the lattice adjacency, Leiden's internal-connectivity guarantee -/// becomes spatial contiguity: no community can be split across disconnected regions. +/// The graph is exactly the lattice adjacency, so Leiden's internal-connectivity guarantee +/// becomes spatial contiguity. /// /// # Errors /// @@ -103,14 +92,12 @@ pub fn lattice_graph(rows: &[u32], cols: &[u32], lattice: Lattice) -> Result = (0..n as u32).collect(); order.sort_unstable_by_key(|&v| key(rows[v as usize], cols[v as usize])); - // Columns in sorted order, held separately so the binary search reads contiguous memory. - // Going through `cols[order[i]]` gathers randomly on every comparison instead: 1.21s vs - // 954ms on 10.5M bins. + // held separately so the search reads contiguous memory. `cols[order[i]]` gathers + // randomly instead: 1.21s vs 954ms on 10.5M bins. let sorted_cols: Vec = order.iter().map(|&v| cols[v as usize]).collect(); for (i, w) in order.windows(2).enumerate() { @@ -131,8 +118,8 @@ pub fn lattice_graph(rows: &[u32], cols: &[u32], lattice: Lattice) -> Result Result u64 { ((row as u64) << 32) | col as u64 } -/// Rejects coordinates that are not doubled. +/// Rejects coordinates that aren't doubled. /// -/// Real Visium data is always `(row + col)` even, but only *consistency* is required here — -/// a shifted origin is fine, offset coordinates are not. Without this, passing `col / 2` -/// produces a graph that is wrong rather than empty, since the offsets still find something. +/// Only consistency is required, so a shifted origin is fine. Without this, passing `col / 2` +/// gives a wrong graph rather than an empty one — the offsets still find something. fn check_hex_parity(rows: &[u32], cols: &[u32]) -> Result<()> { let parity = (rows[0] + cols[0]) % 2; for v in 1..rows.len() { @@ -189,10 +174,9 @@ fn check_hex_parity(rows: &[u32], cols: &[u32]) -> Result<()> { /// Rescales Visium doubled coordinates so all six neighbours sit at the same distance. /// -/// Doubled coordinates are anisotropic — in-row neighbours are 2 units apart, diagonal ones -/// √2 — so any distance-based method must be given these instead. `pitch` is the -/// centre-to-centre spot spacing, 100.0 µm on standard Visium; the output is in the same -/// units, and every one of the six neighbours lands exactly `pitch` away. +/// Hand these to anything distance-based. `pitch` is centre-to-centre spot spacing, 100.0 µm +/// on standard Visium; output is in the same units and every neighbour lands exactly `pitch` +/// away. /// /// # Errors /// @@ -208,7 +192,7 @@ pub fn visium_isometric_coords( expected: rows.len(), }); } - // col carries the doubling, so it scales by pitch/2; row spacing is the hex height. + // col carries the doubling, so pitch/2; row spacing is the hex height let (sx, sy) = (pitch / 2.0, pitch * f64::sqrt(3.0) / 2.0); Ok(( cols.iter().map(|&c| c as f64 * sx).collect(), @@ -232,8 +216,8 @@ fn build_row_index(order: &[u32], rows: &[u32]) -> RowIndex { index } -/// Calls `f(v, u)` once per undirected edge, with both node indices in the caller's -/// numbering. Runs identically in both passes, so degrees and fill can never disagree. +/// Calls `f(v, u)` once per undirected edge, in the caller's numbering. Identical in both +/// passes, so degrees and fill can't disagree. #[inline] fn visit_edges( order: &[u32], @@ -269,7 +253,7 @@ fn lookup( col: u32, ) -> Option { let range = index.range(row)?; - // The row is short — 128 columns on Visium, ~3250 on HD — so this stays in L1. + // rows are short (128 on Visium, ~3250 on HD), so this stays in L1 let i = sorted_cols[range.clone()].binary_search(&col).ok()?; Some(order[range.start + i] as usize) } @@ -309,7 +293,7 @@ mod tests { (rows, cols) } - /// Undirected edges as coordinate pairs, so results can be compared across node orderings. + /// Edges as coordinate pairs, so orderings can be compared. fn edge_set(g: &CSRNetwork, rows: &[u32], cols: &[u32]) -> HashSet<((u32, u32), (u32, u32))> { let mut out = HashSet::new(); for v in 0..g.node_count() { @@ -320,7 +304,7 @@ mod tests { out } - /// Orders an edge's endpoints so the two directions collapse to one entry. + /// Orders endpoints so both directions collapse to one entry. fn canon(a: (u32, u32), b: (u32, u32)) -> ((u32, u32), (u32, u32)) { if a <= b { (a, b) } else { (b, a) } } @@ -358,7 +342,7 @@ mod tests { assert_eq!(b.len() - a.len(), 8, "2x2 blocks x 2 diagonals each"); } - /// Closed form for a fully occupied grid, checked over a range of shapes. + /// Closed form for a full grid, over a range of shapes. #[test] fn square_edge_counts_match_the_closed_form() { for (r, c) in [(1, 1), (1, 7), (7, 1), (2, 2), (5, 9), (16, 16)] { @@ -378,8 +362,7 @@ mod tests { } } - /// The property that would break if a forward offset were double-counted: duplicate - /// entries are summed on construction, so a double emission shows up as weight 2.0. + /// Duplicates are summed on construction, so a double emission shows up as weight 2.0. #[test] fn every_edge_has_weight_exactly_one() { for lattice in [Lattice::Square4, Lattice::Square8, Lattice::VisiumHex] { @@ -406,7 +389,7 @@ mod tests { _ => full_square(r, c), }; let g = lattice_graph(&rows, &cols, lattice).unwrap(); - // Hex reaches two columns sideways, so its interior starts one further in. + // hex reaches two columns sideways, so interior starts one further in let margin = if lattice == Lattice::VisiumHex { 2 } else { 1 }; let mut checked = 0; for v in 0..g.node_count() { @@ -424,8 +407,7 @@ mod tests { } } - /// Visium's parity: neighbours of an even-parity spot are also even-parity, which is what - /// makes the doubled-coordinate scheme self-consistent. + /// Neighbours of an even-parity spot are also even-parity. #[test] fn hex_neighbours_preserve_parity_and_are_the_six_offsets() { let (rows, cols) = full_hex(9, 13); @@ -446,7 +428,7 @@ mod tests { } } - /// Boundary spots, worked out by hand on the layout in the module docs. + /// Boundary spots, worked out by hand. #[test] fn hex_boundary_degrees_are_exact() { let (rows, cols) = full_hex(5, 9); @@ -463,7 +445,7 @@ mod tests { assert_eq!(g.degree(at(4, 8)), 2, "opposite corner"); } - /// Tissue masking removes spots; the remaining ones must simply lose those edges. + /// Masking removes spots; the rest just lose those edges. #[test] fn missing_positions_leave_holes_rather_than_shifting_neighbours() { let (rows, cols) = full_square(5, 5); @@ -519,8 +501,7 @@ mod tests { } } - /// Real Visium geometry: 78 rows, `array_col` 0..126 even / 1..127 odd, 64 spots per row. - /// Verified against 10x's Space Ranger spatial-outputs documentation. + /// Real Visium geometry per Space Ranger docs: 78 rows, 64 spots each. #[test] fn matches_the_documented_visium_capture_area() { let mut rows = Vec::new(); @@ -535,7 +516,7 @@ mod tests { let g = lattice_graph(&rows, &cols, Lattice::VisiumHex).unwrap(); assert_eq!(g.node_count(), 4992); - // Interior spots: rows 1..77 with both in-row neighbours present. + // interior spots: rows 1..77 with both in-row neighbours let interior = (0..g.node_count()) .filter(|&v| rows[v] > 0 && rows[v] < 77 && cols[v] >= 2 && cols[v] <= 125) .count(); @@ -547,7 +528,7 @@ mod tests { } } - /// The trap: offset coordinates look like valid input but describe a different lattice. + /// Offset coordinates look valid but describe a different lattice. #[test] fn rejects_offset_coordinates_masquerading_as_doubled() { let (rows, doubled) = full_hex(9, 13); @@ -559,11 +540,11 @@ mod tests { ), "offset coordinates must not be silently accepted" ); - // Square lattices have no parity constraint, so they stay unaffected. + // square lattices have no parity constraint assert!(lattice_graph(&rows, &offset, Lattice::Square4).is_ok()); } - /// A shifted origin is still doubled, so it must be allowed. + /// A shifted origin is still doubled. #[test] fn accepts_a_shifted_hex_origin() { let (rows, cols) = full_hex(9, 13); @@ -573,8 +554,7 @@ mod tests { assert_eq!(g.edge_count(), reference.edge_count()); } - /// All six neighbours must land at exactly `pitch` in the rescaled space — the property - /// that makes distance-based methods safe on Visium. + /// All six neighbours land at exactly `pitch` once rescaled. #[test] fn isometric_coords_equalise_all_six_neighbours() { let (rows, cols) = full_hex(9, 13); @@ -591,8 +571,7 @@ mod tests { } } - // And nothing else is that close, so a radius query at 1.1x pitch is exactly the - // lattice — which is what makes the isometric form usable for kNN. + // and nothing else is that close, so radius at 1.1x pitch is exactly the lattice let v = (0..g.node_count()) .find(|&v| rows[v] == 4 && cols[v] == 6) .unwrap(); @@ -627,13 +606,12 @@ mod tests { assert_eq!(single.node_count(), 1); assert_eq!(single.edge_count(), 0); - // Far apart, so nothing is adjacent. + // far apart, nothing adjacent let scattered = lattice_graph(&[0, 100, 200], &[0, 100, 200], Lattice::Square8).unwrap(); assert_eq!(scattered.edge_count(), 0); } - /// Leiden guarantees internally-connected communities, so on a lattice every domain must - /// be a spatially contiguous region. This is the property the whole approach rests on. + /// Internally-connected communities on a lattice means spatially contiguous domains. #[test] fn leiden_domains_are_spatially_contiguous() { use crate::community_search::leiden::{LeidenConfig, ObjectiveKind, leiden}; @@ -661,7 +639,7 @@ mod tests { } } - /// Coordinates at the top of the `u32` range must not wrap when an offset goes negative. + /// Top of the `u32` range must not wrap on a negative offset. #[test] fn extreme_coordinates_do_not_wrap() { let rows = [0u32, 0, u32::MAX, u32::MAX]; @@ -670,9 +648,8 @@ mod tests { assert_eq!(g.edge_count(), 0, "corners of the space are not adjacent"); } - /// Visium HD at 2 µm. Sources disagree on the grid: 10x's row count implies 3350², while - /// spatialdata documents 3250². Only a size for the benchmark, so either does — but the - /// builder never assumes an extent, and callers shouldn't either. + /// Visium HD at 2 µm. Sources disagree on the extent (3350² vs 3250²); it's only a + /// benchmark size, and the builder never assumes one. /// /// ```text /// cargo test --release --no-default-features visium_hd_scale -- --ignored --nocapture diff --git a/src/spatial/mod.rs b/src/spatial/mod.rs index 6c284e9..c9fb921 100644 --- a/src/spatial/mod.rs +++ b/src/spatial/mod.rs @@ -1,27 +1,13 @@ //! Spatial neighbour graphs. //! -//! Spatial domain detection is mostly a graph-construction problem: build the right graph and -//! the clustering is the same Leiden used everywhere else. Because refinement guarantees -//! internally-connected communities, running it on a spatial graph gives spatially contiguous -//! domains for free. +//! Domain detection is mostly a graph-construction problem — build the right graph and the +//! clustering is the same Leiden as everywhere else. Refinement guarantees internally +//! connected communities, so domains come out spatially contiguous for free. //! -//! Use [`ObjectiveKind::Cpm`](crate::community_search::leiden::ObjectiveKind::Cpm) rather than -//! RB for spatial domains — modularity's resolution limit bites harder here, where domains -//! tend to be numerous and small. - -//! # Reading Visium data -//! -//! Two things to know before wiring up a loader, both verified against the upstream source: -//! -//! * Space Ranger ≥ 2.0 renamed `tissue_positions_list.csv` to `tissue_positions.csv` **and -//! added a header row**. Parse the header rather than assuming column positions — scanpy -//! branches on the filename to decide. -//! * `scanpy.read_visium` labels the two pixel columns the wrong way round, then selects them -//! in the wrong order. The errors cancel, so `obsm["spatial"]` really is `(x, y)`, but the -//! names in `obs` are swapped. Don't trust `pxl_row_in_fullres` / `pxl_col_in_fullres` if -//! you read those columns directly. +//! Prefer [`ObjectiveKind::Cpm`](crate::community_search::leiden::ObjectiveKind::Cpm) over RB +//! here: modularity's resolution limit bites harder when domains are many and small. //! -//! Neither affects `array_row` / `array_col`, which is what [`lattice_graph`] wants. +//! Gotchas around reading Visium data are in `docs/spatial-graphs.md`. pub mod banksy; pub mod combine; diff --git a/src/spatial/points.rs b/src/spatial/points.rs index 042e1dd..84bf309 100644 --- a/src/spatial/points.rs +++ b/src/spatial/points.rs @@ -1,12 +1,11 @@ -//! Neighbour graphs from point coordinates, for assays that are not on a lattice. +//! Neighbour graphs from point coordinates, for assays that aren't on a lattice. //! -//! Xenium, MERFISH, CosMx and Slide-seq give each cell a position rather than a grid slot, so -//! neighbours have to be searched for. Both builders here are exact, over the uniform grid in -//! [`grid`](super::grid) — no approximation, so no recall gaps to make a graph -//! irreproducible. Both are checked against brute force on degenerate inputs. +//! Xenium, MERFISH, CosMx and Slide-seq give positions rather than grid slots, so neighbours +//! have to be searched for. Both builders are exact over the uniform grid in +//! [`grid`](super::grid), and both are checked against brute force on degenerate inputs. //! -//! On Visium data, pass [`visium_isometric_coords`](super::visium_isometric_coords) rather -//! than raw lattice coordinates; see the module docs for why. +//! On Visium, pass [`visium_isometric_coords`](super::visium_isometric_coords) instead of raw +//! lattice coordinates. use rayon::prelude::*; @@ -14,19 +13,17 @@ use crate::error::{ClusteringError, Result}; use crate::network::{CSRNetwork, MAX_NODES}; use crate::spatial::grid::{Grid, distance_sq}; -/// How to reconcile the two directions of a k-nearest-neighbour relation. +/// How to reconcile the two directions of a kNN relation. /// -/// kNN is directed — `j` being among `i`'s nearest does not make `i` among `j`'s — but the -/// quality functions need a symmetric graph, so one of these has to be chosen. +/// kNN is directed, the quality functions need symmetry. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum Symmetry { - /// Keep an edge if either endpoint chose the other. Degrees come out at or above `k`. - /// This is what scanpy and squidpy do. + /// Keep an edge if either endpoint chose the other, so degree >= `k`. What scanpy and + /// squidpy do. #[default] Union, - /// Keep an edge only if both endpoints chose each other. Degrees come out at or below - /// `k`, and the graph is sparser and more conservative — hub cells stop dragging in - /// distant neighbours. + /// Keep an edge only if both chose each other, so degree <= `k`. Sparser, and hub cells + /// stop dragging in distant neighbours. Intersection, } @@ -35,8 +32,7 @@ pub enum Symmetry { pub enum SpatialWeight { /// Every edge weighs 1.0. Adjacency alone carries the signal. Uniform, - /// `exp(-d² / (2σ²))`, so nearby cells count for more. `sigma` is in the same units as - /// the coordinates. + /// `exp(-d² / (2σ²))`. `sigma` is in coordinate units. Gaussian { /// Kernel bandwidth. sigma: f64, @@ -70,7 +66,7 @@ impl SpatialWeight { } } -/// A neighbour and the square of its distance, kept squared to avoid a pointless `sqrt`. +/// A neighbour and its squared distance — squared to skip a pointless `sqrt`. type Candidate = (u32, f64); fn validate_points(points: &[[f64; D]]) -> Result<()> { @@ -91,19 +87,17 @@ fn validate_points(points: &[[f64; D]]) -> Result<()> { /// Joins every pair of points closer than `radius`. /// -/// The relation is symmetric by construction, so no reconciliation step is needed and the -/// result does not depend on any tie-breaking. `radius` is in coordinate units — for spatial -/// assays that means it is directly interpretable, e.g. 30 µm. +/// Symmetric by construction, so no reconciliation and no tie-breaking. `radius` is in +/// coordinate units, e.g. 30 µm. /// -/// Degree is unbounded: in dense tissue a generous radius can give a cell thousands of -/// neighbours, and cost downstream is linear in degree. `max_degree` caps it by keeping only -/// the nearest, but note the cap is applied **before** symmetrisation, so a node can still -/// finish slightly above it when a neighbour kept an edge it dropped. +/// Degree is unbounded — a generous radius in dense tissue gives thousands of neighbours, and +/// downstream cost is linear in degree. `max_degree` caps it, but before symmetrisation, so a +/// node can finish slightly over when a neighbour kept an edge it dropped. /// /// # Errors /// -/// If `radius` is not finite and positive, a coordinate is not finite, or there are more -/// points than `u32` adjacency can address. +/// If `radius` isn't finite and positive, a coordinate isn't finite, or there are more points +/// than `u32` adjacency can address. pub fn radius_graph( points: &[[f64; D]], radius: f64, @@ -121,8 +115,7 @@ pub fn radius_graph( return CSRNetwork::from_csr_parts(vec![0], Vec::new(), Vec::new(), None); } - // Cells the size of the radius, so everything in range sits in the 3^D block around a - // point and one ring is all that ever needs visiting. + // cells the size of the radius, so one ring covers everything in range let grid = Grid::new(points, radius); let r2 = radius * radius; @@ -143,8 +136,7 @@ pub fn radius_graph( } }); } - // Sorted by (distance, id) so a capped result never depends on visit order — - // points at equal distance are the norm on regular tissue. + // (distance, id) so a capped result doesn't depend on visit order found.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0))); if let Some(cap) = max_degree { found.truncate(cap); @@ -153,22 +145,21 @@ pub fn radius_graph( }) .collect(); - // Capping breaks symmetry, so restore it. Without a cap this is already a no-op. + // capping breaks symmetry; without a cap this is a no-op if max_degree.is_some() { symmetrise(&mut adjacency, Symmetry::Union); } assemble(adjacency, weight) } -/// Joins every point to its `k` nearest neighbours, then makes the relation symmetric. +/// Joins every point to its `k` nearest, then symmetrises. /// -/// Ties are broken on the lower node index, so a fixed input gives a fixed graph even where -/// many points sit at identical coordinates — which happens whenever coordinates have been -/// rounded to a pixel grid. +/// Ties break on the lower node index, so coordinates rounded to a pixel grid still give a +/// fixed graph. /// /// # Errors /// -/// If `k` is zero, a coordinate is not finite, or there are more points than `u32` adjacency +/// If `k` is zero, a coordinate isn't finite, or there are more points than `u32` adjacency /// can address. pub fn knn_graph( points: &[[f64; D]], @@ -187,7 +178,7 @@ pub fn knn_graph( return CSRNetwork::from_csr_parts(vec![0], Vec::new(), Vec::new(), None); } - // Aim for a handful of points per cell, so the first ring or two usually suffices. + // a handful of points per cell, so one or two rings usually suffice let grid = Grid::new(points, typical_spacing(points, k)); let mut adjacency: Vec> = points @@ -207,9 +198,9 @@ pub fn knn_graph( if found.len() < k { continue; } - // Anything still unvisited sits at Chebyshev distance >= ring + 1, so it is - // at least `ring * cell` away — a point can be anywhere inside its own cell, - // which costs one ring of slack. Once the k-th best beats that, stop. + // unvisited points are >= ring+1 cells out, so at least `ring * cell` away + // (one ring of slack, since a point sits anywhere in its cell). Stop once + // the k-th best beats that. found.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0))); found.truncate(k.max(1).min(found.len())); let safe = ring as f64 * grid.cell_size(); @@ -228,7 +219,7 @@ pub fn knn_graph( assemble(adjacency, weight) } -/// A cell size that puts roughly `k` points in each cell. +/// Cell size putting roughly `k` points per cell. fn typical_spacing(points: &[[f64; D]], k: usize) -> f64 { let mut min = [f64::INFINITY; D]; let mut max = [f64::NEG_INFINITY; D]; @@ -249,13 +240,12 @@ fn typical_spacing(points: &[[f64; D]], k: usize) -> f64 { /// Rewrites `adjacency` in place so `j ∈ adj[i]` exactly when `i ∈ adj[j]`. /// -/// Done explicitly rather than by emitting both directions and letting construction merge -/// them: duplicates are *summed* there, which would quietly give mutual pairs twice the -/// weight of one-sided ones. +/// Explicit rather than emitting both directions and letting construction merge them: +/// duplicates are summed there, so mutual pairs would end up at twice the weight. fn symmetrise(adjacency: &mut [Vec], symmetry: Symmetry) { let n = adjacency.len(); - // Reverse lists via counting sort — O(total edges), and no per-node allocation. + // counting sort, so O(edges) and no per-node allocation let mut counts = vec![0u32; n + 1]; for list in adjacency.iter() { for &(u, _) in list { @@ -337,14 +327,14 @@ mod tests { out } - /// On a unit grid the radius picks out a known connectivity, so this is exact. + /// On a unit grid the radius picks out a known connectivity. #[test] fn radius_on_a_unit_grid_is_exactly_the_expected_connectivity() { let pts = grid(6); let four = radius_graph(&pts, 1.01, SpatialWeight::Uniform, None).unwrap(); let eight = radius_graph(&pts, 1.5, SpatialWeight::Uniform, None).unwrap(); - // 6x6 grid: 4-connected has 2*6*5 = 60 edges, 8-connected adds 2*5*5 = 50 diagonals. + // 6x6: 4-connected is 2*6*5 = 60 edges, 8-connected adds 2*5*5 = 50 diagonals assert_eq!(four.edge_count(), 60); assert_eq!(eight.edge_count(), 110); assert!(edge_set(&four).is_subset(&edge_set(&eight))); @@ -357,8 +347,7 @@ mod tests { } } - /// A radius relation is symmetric before anything is done to it, so this must hold with - /// no reconciliation step at all. + /// A radius relation is symmetric with no reconciliation at all. #[test] fn radius_is_symmetric_without_reconciliation() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(4); @@ -370,7 +359,7 @@ mod tests { assert!(g.edge_count() > 0); } - /// The cross-check that matters: the two builders must agree on Visium. + /// The two builders must agree on Visium. #[test] fn isometric_radius_reproduces_the_exact_hex_lattice() { use crate::spatial::lattice::{Lattice, lattice_graph, visium_isometric_coords}; @@ -386,7 +375,7 @@ mod tests { let (x, y) = visium_isometric_coords(&rows, &cols, 100.0).unwrap(); let pts: Vec<[f64; 2]> = x.iter().zip(&y).map(|(&a, &b)| [a, b]).collect(); - // Anything past the pitch but short of the next shell at pitch*sqrt(3). + // past the pitch, short of the next shell at pitch*sqrt(3) let searched = radius_graph(&pts, 110.0, SpatialWeight::Uniform, None).unwrap(); assert_eq!(edge_set(&exact), edge_set(&searched)); @@ -416,13 +405,12 @@ mod tests { } } - /// Coordinates rounded to a pixel grid produce many exact ties; those must not make the - /// result depend on kd-tree traversal order. + /// Pixel-rounded coordinates make many exact ties, which must not decide the result. #[test] fn duplicate_points_still_give_a_deterministic_graph() { let mut pts = Vec::new(); for i in 0..40 { - // Four coincident points at each of ten sites. + // four coincident points at each of ten sites for _ in 0..4 { pts.push([(i % 10) as f64, 0.0]); } @@ -444,7 +432,7 @@ mod tests { let g = radius_graph(&pts, 2.5, SpatialWeight::Gaussian { sigma: 1.0 }, None).unwrap(); let w = |a: usize, b: usize| g.neighbors(a).find(|&(u, _)| u == b).unwrap().1; - // exp(-1/2) and exp(-4/2), to f32 precision. + // exp(-1/2) and exp(-4/2), to f32 precision assert!((w(0, 1) - (-0.5f64).exp()).abs() < 1e-6, "got {}", w(0, 1)); assert!((w(0, 2) - (-2.0f64).exp()).abs() < 1e-6, "got {}", w(0, 2)); assert!(w(0, 1) > w(0, 2)); @@ -453,7 +441,7 @@ mod tests { #[test] fn max_degree_bounds_the_hubs() { - // One dense clump: without a cap, every point sees every other. + // one dense clump: uncapped, every point sees every other let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(2); let pts: Vec<[f64; 2]> = (0..200) .map(|_| [rng.random::(), rng.random::()]) @@ -464,7 +452,7 @@ mod tests { assert_eq!(uncapped.degree(0), 199, "everything is within the radius"); capped.validate_symmetry().unwrap(); assert!(capped.edge_count() < uncapped.edge_count() / 5); - // Documented as a soft cap: symmetrisation can push a node back over it. + // soft cap: symmetrisation can push a node back over for v in 0..pts.len() { assert!(capped.degree(v) >= 10, "each node keeps its own 10"); } @@ -479,7 +467,7 @@ mod tests { .collect(); let g = radius_graph(&pts, 1.01, SpatialWeight::Uniform, None).unwrap(); g.validate_symmetry().unwrap(); - // 4x4x4 grid, 6-connected: 3 * 4 * 4 * 3 = 144 edges. + // 4x4x4, 6-connected: 3 * 4 * 4 * 3 = 144 edges assert_eq!(g.edge_count(), 144); let interior = (0..pts.len()) .find(|&v| pts[v].iter().all(|&c| c > 0.0 && c < 3.0)) @@ -507,7 +495,7 @@ mod tests { perm.shuffle(&mut rng); let shuffled: Vec<[f64; 2]> = perm.iter().map(|&i| pts[i]).collect(); let g = knn_graph(&shuffled, 5, Symmetry::Union, SpatialWeight::Uniform).unwrap(); - // Map back through the permutation and compare as sets. + // map back through the permutation, compare as sets let mapped: HashSet<(u64, u64)> = edge_set(&g) .into_iter() .map(|(a, b)| { @@ -519,11 +507,11 @@ mod tests { } } - /// `KdTree` panics past 32 items sharing a value on one axis. Spatial data does that as a - /// matter of course, so this covers the shapes that actually occur. + /// `KdTree` panics past 32 items sharing an axis value, which spatial data does + /// routinely. These are the shapes that actually occur. #[test] fn survives_heavy_axis_alignment() { - // A full Visium row is 64 spots at one y; a capture area is 78 of them. + // a full Visium row is 64 spots at one y, a capture area 78 of them let mut visium = Vec::new(); for r in 0..78 { for i in 0..64 { @@ -534,12 +522,12 @@ mod tests { g.validate_symmetry().unwrap(); assert_eq!(g.node_count(), 4992); - // A whole HD-sized row at a single y. + // a whole HD-sized row at a single y let row: Vec<[f64; 2]> = (0..3250).map(|i| [i as f64, 0.0]).collect(); let g = radius_graph(&row, 1.5, SpatialWeight::Uniform, None).unwrap(); assert_eq!(g.edge_count(), 3249, "a path along the row"); - // Every point identical — the worst case for any tree. + // every point identical, the worst case for any tree let same = vec![[7.0, 7.0]; 200]; for sym in [Symmetry::Union, Symmetry::Intersection] { let g = knn_graph(&same, 5, sym, SpatialWeight::Uniform).unwrap(); @@ -549,8 +537,7 @@ mod tests { } } - /// Point sets covering the shapes that break spatial indices: duplicates, collinear runs, - /// tight clumps, near-empty space. + /// Shapes that break spatial indices: duplicates, collinear runs, clumps, empty space. fn awkward_point_sets(seed: u64) -> Vec<(String, Vec<[f64; 2]>)> { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); let mut out: Vec<(String, Vec<[f64; 2]>)> = Vec::new(); @@ -600,7 +587,7 @@ mod tests { out } - /// The radius search must agree with O(n²) brute force exactly, on every shape. + /// Must agree with O(n²) brute force exactly, on every shape. #[test] fn radius_matches_brute_force() { for (name, pts) in awkward_point_sets(21) { @@ -623,13 +610,12 @@ mod tests { } } - /// The k-nearest search must pick exactly the same neighbours brute force would, - /// including how it breaks ties. + /// Must pick exactly what brute force does, ties included. #[test] fn knn_matches_brute_force() { for (name, pts) in awkward_point_sets(22) { for &k in &[1usize, 3, 8] { - // Compare pre-symmetrisation, which is where the search itself is decided. + // pre-symmetrisation, where the search itself is decided let mut want: Vec> = Vec::with_capacity(pts.len()); for i in 0..pts.len() { let mut all: Vec<(f64, u32)> = (0..pts.len()) @@ -647,8 +633,8 @@ mod tests { want.push(ids); } - // Intersection keeps only mutual pairs, so recover the directed lists by - // asking for the union and checking containment both ways instead. + // intersection keeps only mutual pairs, so recover the directed lists from + // the union plus a containment check both ways let g = knn_graph(&pts, k, Symmetry::Union, SpatialWeight::Uniform).unwrap(); for (i, truth) in want.iter().enumerate() { let neigh: HashSet = g.neighbors(i).map(|(u, _)| u).collect(); @@ -659,7 +645,7 @@ mod tests { ); } } - // And every union edge must be justified by one side's true k-nearest. + // every union edge must be justified by one side's true k-nearest for (i, truth) in want.iter().enumerate() { for (u, _) in g.neighbors(i) { assert!( @@ -672,7 +658,7 @@ mod tests { } } - /// Xenium-scale: a few hundred thousand cells over a tissue section. + /// Xenium scale: a few hundred thousand cells over a section. /// /// ```text /// cargo test --release --no-default-features xenium_scale -- --ignored --nocapture @@ -682,7 +668,7 @@ mod tests { fn xenium_scale() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); let n = 500_000; - // ~12 mm square at roughly Xenium cell density. + // ~12 mm square at roughly Xenium density let pts: Vec<[f64; 2]> = (0..n) .map(|_| { [ @@ -736,7 +722,7 @@ mod tests { assert_eq!(g.node_count(), 1); assert_eq!(g.edge_count(), 0); - // Nothing within the radius. + // nothing within the radius let far = vec![[0.0, 0.0], [1000.0, 0.0]]; let g = radius_graph(&far, 1.0, SpatialWeight::Uniform, None).unwrap(); assert_eq!(g.edge_count(), 0); diff --git a/tests/banksy_reference.rs b/tests/banksy_reference.rs index fd26e7c..b59b06e 100644 --- a/tests/banksy_reference.rs +++ b/tests/banksy_reference.rs @@ -1,17 +1,13 @@ //! Differential tests for the BANKSY feature augmentation. //! -//! Fixtures come from `banksy-py` itself via `tools/gen_banksy_fixtures.py` — the reference's -//! own `generate_spatial_weights_fixed_nbrs` and `concatenate_all`, not a reimplementation of -//! them. So this checks against what BANKSY computes rather than against a reading of the -//! paper. Fixtures are committed; the suite needs no Python. +//! Fixtures come from `banksy-py`'s own functions via `tools/gen_banksy_fixtures.py`, not a +//! reimplementation, so this checks what BANKSY computes rather than a reading of the paper. +//! Three things it pins that the paper alone would get wrong: the λ budget halves per +//! harmonic, blocks are z-scored before scaling, and the gradient is centred on its own +//! neighbourhood first. //! -//! Three things this pins that a formula transcribed from the paper would get wrong: the λ -//! budget halves with each harmonic rather than splitting evenly, every block is z-scored -//! before scaling, and the gradient term is centred on its own neighbourhood first. -//! -//! Tolerance is 1e-6, not tighter, because the reference stores azimuths as `float32` -//! (`theta_data = np.zeros_like(..., dtype=np.float32)`). We carry f64 throughout, so the -//! residual is the reference's precision, not ours. +//! Tolerance is 1e-6 because the reference stores azimuths as `float32`. We carry f64, so the +//! residual is theirs. use serde_json::Value; use single_clustering::spatial::banksy::{Decay, NeighbourhoodOperator, banksy_matrix}; @@ -71,9 +67,9 @@ fn max_abs_diff(a: &[f64], b: &[f64]) -> (f64, usize) { worst } -/// Points on a regular grid have many exactly-equidistant neighbours, and nothing specifies -/// which of them a k-nearest search returns. Our tie-break is (distance, index); sklearn's is -/// unspecified, so that case is compared structurally elsewhere rather than value-for-value. +/// A regular grid has many equidistant neighbours and nothing specifies which a kNN search +/// returns. Ours breaks on (distance, index); sklearn's is unspecified, so grids are compared +/// structurally elsewhere. fn has_distance_ties(name: &str) -> bool { name.starts_with("grid") } @@ -171,9 +167,8 @@ fn augmented_matrix_matches_the_reference() { assert!(checked >= 10, "only {checked} matrices compared"); } -/// On a regular grid the neighbour *set* is ambiguous, but the neighbourhood mean over a -/// symmetric lattice should still land close — a large gap would mean something worse than a -/// tie-break difference. +/// The neighbour set is ambiguous on a grid, but the mean over a symmetric lattice should +/// still land close. A large gap would mean worse than a tie-break difference. #[test] fn grid_case_agrees_up_to_tie_breaking() { let f = fixtures(); diff --git a/tests/invariants.rs b/tests/invariants.rs index ce1b908..a27bc04 100644 --- a/tests/invariants.rs +++ b/tests/invariants.rs @@ -1,7 +1,7 @@ -//! Properties that must hold for any input, exercised through the public API. +//! Properties that must hold for any input, through the public API. //! -//! Each of the four below maps to a bug that shipped in 0.6.x. Cheap, no fixtures needed, and -//! any one failing means the algorithm is wrong rather than unlucky. +//! Each maps to a bug that shipped in 0.6.x. No fixtures, and any one failing means the +//! algorithm is wrong rather than unlucky. use single_clustering::community_search::leiden::{ Cpm, LeidenConfig, Objective, ObjectiveKind, Partition, Rb, leiden, @@ -11,13 +11,12 @@ use single_clustering::network::CSRNetwork; mod common; use common::{disconnected_community_count, sbm, test_graphs}; -/// Invariant 1: collapsing communities must not change what a partition scores. Broken in -/// 0.6.x, where a self-loop added its weight once instead of twice to strength, switching the -/// null model off above level 0. +/// Collapsing communities must not change what a partition scores. Broken in 0.6.x, where a +/// self-loop added its weight once instead of twice and switched the null model off above +/// level 0. /// -/// Holds to stored-weight precision. Adjacency is `f32`, so a collapsed self-loop carrying a -/// whole community's internal weight rounds once per level — `1e-6` relative, about 10x f32 -/// epsilon. The bug this guards against was a factor of ~1.75, not 1e-8. +/// To `1e-6` relative: adjacency is `f32`, so a collapsed self-loop rounds once per level. The +/// bug this guards against was a factor of ~1.75. #[test] fn quality_is_invariant_under_aggregation() { for (name, graph) in test_graphs() { diff --git a/tests/optimality.rs b/tests/optimality.rs index 7e0e737..1b8f712 100644 --- a/tests/optimality.rs +++ b/tests/optimality.rs @@ -1,11 +1,8 @@ //! Exhaustive optimality checks on small graphs. //! -//! Small enough to enumerate every set partition, so the true optimum is computable. The only -//! test here that checks ground truth rather than another implementation — nothing in it can -//! be fooled by a shared misunderstanding of the objective. -//! -//! Kept small enough for the normal suite; `exhaustive_optimality_larger` does `n = 10..12` -//! and is `#[ignore]`d. +//! Small enough to enumerate every set partition, so this is ground truth rather than another +//! implementation — nothing here can be fooled by a shared misunderstanding of the objective. +//! `exhaustive_optimality_larger` does `n = 10..12` and is `#[ignore]`d. use single_clustering::community_search::leiden::{LeidenConfig, leiden, modularity}; use single_clustering::network::CSRNetwork; @@ -15,9 +12,8 @@ mod common; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; -/// Visits every set partition of `n` items via restricted growth strings, calling `f` with -/// each labelling. There are `Bell(n)` of them: 4140 for n=8, 115975 for n=10, 4213597 for -/// n=12. +/// Every set partition of `n` items, via restricted growth strings. `Bell(n)` of them: 4140 +/// at n=8, 4213597 at n=12. fn for_each_partition(n: usize, mut f: impl FnMut(&[usize])) { let mut a = vec![0usize; n]; let mut max_seen = vec![0usize; n]; @@ -49,7 +45,7 @@ fn for_each_partition(n: usize, mut f: impl FnMut(&[usize])) { } } -/// True modularity optimum of `graph` at the given resolution, by exhaustive enumeration. +/// True modularity optimum, by exhaustive enumeration. fn brute_force_optimum(graph: &CSRNetwork, resolution: f64) -> f64 { let n = graph.node_count(); let mut best = f64::NEG_INFINITY; @@ -62,7 +58,7 @@ fn brute_force_optimum(graph: &CSRNetwork, resolution: f64) -> f64 { best } -/// Random graphs spanning a range of densities, plus a few structured ones. +/// Random graphs across a range of densities, plus a few structured ones. fn small_graphs(n: usize, count: usize, seed: u64) -> Vec<(String, CSRNetwork)> { let mut rng = ChaCha8Rng::seed_from_u64(seed); let mut out = Vec::new(); @@ -86,7 +82,7 @@ fn small_graphs(n: usize, count: usize, seed: u64) -> Vec<(String, CSRNetwork)> )); } - // two cliques joined by one edge: an unambiguous optimum + // two cliques joined by one edge: unambiguous optimum if n >= 6 { let half = n / 2; let mut edges = Vec::new(); @@ -121,7 +117,7 @@ fn check_optimality(sizes: &[usize], graphs_per_size: usize, resolutions: &[f64] for &resolution in resolutions { let best = brute_force_optimum(&graph, resolution); - // Give the optimizer the same budget a user would. + // same budget a user would give it let clustering = leiden( &graph, &LeidenConfig { @@ -143,8 +139,7 @@ fn check_optimality(sizes: &[usize], graphs_per_size: usize, resolutions: &[f64] if ours >= best - 1e-9 { optimal += 1; } else { - // absolute, not relative: modularity is in [-1, 1] and these optima sit - // near zero, where relative error explodes meaninglessly — -0.034 vs + // absolute, not relative: these optima sit near zero, where -0.034 vs // -0.018 is "87% worse" relatively but 0.016 absolutely let gap = best - ours; if gap > worst_gap { @@ -168,12 +163,9 @@ fn check_optimality(sizes: &[usize], graphs_per_size: usize, resolutions: &[f64] modularity ({worst_case})" ); - // Measured on these fixtures: the true optimum is found on 93.5% of 108 cases, worst gap - // 0.027 modularity (0.050 for the n=10..12 variant). `leidenalg` on the identical graphs gets 95.4% at its default budget - // and 96.3% at 10x that, hitting the same hardest instance — it defeats both. These are - // small dense random graphs with no community structure, i.e. a deliberately flat, - // adversarial landscape; the bounds below sit just outside the measured values so a - // genuine regression trips them. + // Measured: optimal on 93.5% of 108 cases, worst gap 0.027 (0.050 for n=10..12). + // `leidenalg` gets 95.4-96.3% on the same graphs and loses the same hardest instance. + // Bounds sit just outside the measured values, so a real regression trips them. assert!( rate >= 90.0, "found the true optimum in only {rate:.1}% of {checked} cases (expected ~93.5%)" @@ -190,14 +182,14 @@ fn finds_the_true_optimum_on_small_graphs() { check_optimality(&[6, 7, 8, 9], 8, &[0.5, 1.0, 2.0]); } -/// Same, for n = 10..12. Slow (Bell(12) = 4.2M partitions per graph per resolution). +/// Same for n = 10..12. Slow: Bell(12) = 4.2M partitions per graph per resolution. #[test] #[ignore = "exhaustive over Bell(12); run with --ignored"] fn exhaustive_optimality_larger() { check_optimality(&[10, 11, 12], 6, &[0.5, 1.0, 2.0]); } -/// The enumerator itself must be right, or the whole test is worthless. +/// The enumerator itself must be right, or none of this means anything. #[test] fn partition_enumerator_is_correct() { // Bell numbers @@ -215,8 +207,7 @@ fn partition_enumerator_is_correct() { let mut seen = std::collections::HashSet::new(); for_each_partition(n, |labels| { count += 1; - // canonical form: labels are already a restricted growth string, so they are a - // unique representative of the set partition + // a restricted growth string is already a unique representative seen.insert(labels.to_vec()); assert_eq!(labels.len(), n); assert_eq!(labels[0], 0, "restricted growth strings start at 0"); diff --git a/tests/properties.rs b/tests/properties.rs index 985b090..0995097 100644 --- a/tests/properties.rs +++ b/tests/properties.rs @@ -1,10 +1,8 @@ //! Randomised property tests. //! -//! The rest of the suite uses hand-picked graphs, which only covers what somebody thought to -//! write down. This generates graphs and configs at random and checks the invariants hold — -//! that's what catches the combination nobody considered. -//! -//! Failures print the seed, so counterexamples are reproducible. +//! Hand-picked graphs only cover what somebody thought to write down. These generate graphs +//! and configs at random, which is what catches the combination nobody considered. Failures +//! print the seed. use single_clustering::community_search::leiden::{ Cpm, LeidenConfig, Objective, ObjectiveKind, Partition, Rb, leiden, modularity, diff --git a/tests/reference.rs b/tests/reference.rs index ee925d9..6936423 100644 --- a/tests/reference.rs +++ b/tests/reference.rs @@ -1,21 +1,16 @@ //! Differential tests against `leidenalg`. //! -//! Fixtures are generated once by `tools/gen_fixtures.py` and committed, so this needs no -//! Python. Two separate things, which fail for different reasons: -//! -//! 1. **Definition** — on the *same membership*, our objective must give exactly -//! `leidenalg`'s value (up to the documented factor of 2). Pins the quality functions, and -//! would have caught the 2x resolution bug. -//! 2. **Optimization** — our algorithm must reach a partition at least as good as theirs. -//! Checked on quality and agreement, never exact labels — different RNGs, so identical -//! partitions aren't an achievable bar. +//! Fixtures come from `tools/gen_fixtures.py` and are committed, so this needs no Python. Two +//! separate things: on the same membership our objective must give exactly `leidenalg`'s +//! value, and our algorithm must reach a partition at least as good as theirs. The second is +//! checked on quality and agreement, never exact labels — different RNGs. use single_clustering::community_search::leiden::{ Cpm, LeidenConfig, Objective, ObjectiveKind, Partition, Rb, leiden, modularity, }; use single_clustering::network::CSRNetwork; -/// `leidenalg` multiplies its quality by `(2 - is_directed)`; ours omits that factor. +/// `leidenalg` multiplies quality by `(2 - is_directed)`; we don't. const LEIDENALG_SCALE: f64 = 2.0; struct Case { @@ -125,7 +120,7 @@ fn nmi(a: &[usize], b: &[usize]) -> f64 { } } -/// Runs our algorithm with `n_iterations = 5`, matching how the fixtures were generated. +/// `n_iterations = 5`, matching how the fixtures were generated. fn run(case: &Case, seed: u64) -> Vec { let config = LeidenConfig { objective: case.objective, @@ -136,9 +131,8 @@ fn run(case: &Case, seed: u64) -> Vec { leiden(&case.graph, &config).unwrap().into_labels() } -/// Best of `seeds` runs. Both are stochastic heuristics over the same landscape — -/// `leidenalg`'s own two fixture seeds differ by up to 3.5% on the hard instances, so one run -/// of ours against whichever run it recorded is noise. +/// Best of `seeds` runs. `leidenalg`'s own two fixture seeds differ by up to 3.5% on the hard +/// instances, so a single-run comparison is noise. fn run_best(case: &Case, seeds: u64) -> Vec { (0..seeds) .map(|s| run(case, 42 + s)) @@ -156,10 +150,8 @@ fn fixtures_are_present() { assert!(cases.len() >= 100, "only {} cases loaded", cases.len()); } -/// Our quality function must agree with `leidenalg`'s exactly, on the same membership. -/// -/// Pins the definitions — fails if a resolution is scaled wrong or a constant convention -/// drifts, no matter how good either optimizer is. +/// Our quality function must match `leidenalg`'s exactly on the same membership. Pins the +/// definitions regardless of how good either optimizer is. #[test] fn quality_definitions_match_leidenalg() { let mut failures = Vec::new(); @@ -181,12 +173,10 @@ fn quality_definitions_match_leidenalg() { ); } -/// Our modularity must agree with igraph's on the same membership. +/// Our modularity must match igraph's on the same membership. /// -/// To `1e-7`, not to the last bit: adjacency is stored as `f32`, so a weight like `0.2531` -/// from the fixtures is rounded on the way in. Modularity is bounded by 1, and f32 epsilon is -/// 1.2e-7, so that is the best agreement the storage can support. The arithmetic itself is -/// f64 throughout. +/// To `1e-7`, not the last bit: adjacency is stored as `f32`, so fixture weights round on the +/// way in, and f32 epsilon is 1.2e-7. The arithmetic itself is f64. #[test] fn modularity_matches_igraph() { let mut failures = Vec::new(); @@ -210,12 +200,9 @@ fn modularity_matches_igraph() { /// No single case may fall grossly short of `leidenalg`. /// -/// The bound is deliberately loose — its job is to catch a systematic defect, like a -/// misscaled resolution, not to police heuristic noise. Aggregate parity is checked by -/// [`optimizer_is_not_systematically_worse`], which is the tight test. -/// -/// Known residual: high-resolution RB on the medium SBM sits ~6% below `leidenalg`, on an -/// instance where `leidenalg`'s own two seeds differ by 3.5%. +/// Loose on purpose — it catches a systematic defect, not heuristic noise. +/// [`optimizer_is_not_systematically_worse`] is the tight one. Known residual: high-resolution +/// RB on the medium SBM sits ~6% below, on an instance where their own seeds differ by 3.5%. #[test] fn no_case_falls_grossly_short() { let mut failures = Vec::new(); @@ -240,10 +227,8 @@ fn no_case_falls_grossly_short() { ); } -/// Across the whole fixture set, a single run of ours must be level with `leidenalg`. -/// -/// At the time of writing this is -0.11%: 33 cases better, 107 equal, 20 worse. The bound -/// leaves room for heuristic noise while still failing loudly on a real regression. +/// Across the whole fixture set a single run must be level with `leidenalg`. Currently +/// -0.11%: 33 better, 107 equal, 20 worse. #[test] fn optimizer_is_not_systematically_worse() { let cases = load_cases(); @@ -279,7 +264,7 @@ fn optimizer_is_not_systematically_worse() { ); } -/// Given the same budget `leidenalg` had, we should come out ahead on aggregate. +/// Same budget as `leidenalg`, and we should come out ahead on aggregate. #[test] fn two_seeds_beat_leidenalg_on_aggregate() { let cases = load_cases(); @@ -310,13 +295,9 @@ fn two_seeds_beat_leidenalg_on_aggregate() { ); } -/// Where the answer is unambiguous, we find the *same* communities, not merely ones scoring -/// as well. -/// -/// Restricted on purpose. Agreement is only a meaningful signal when the instance has one -/// clearly right answer: `sbm_hard` (p_in 0.18 vs p_out 0.07) and resolutions far from an -/// instance's natural granularity admit many near-equal partitions, so two good optimizers -/// legitimately disagree there. Quality, checked above, is the right measure for those. +/// Where the answer is unambiguous, we find the *same* communities, not just ones scoring as +/// well. Restricted on purpose: `sbm_hard` and off-granularity resolutions admit many +/// near-equal partitions, where quality is the right measure instead. #[test] fn partitions_agree_where_structure_is_unambiguous() { let mut failures = Vec::new(); @@ -332,7 +313,7 @@ fn partitions_agree_where_structure_is_unambiguous() { if !strong_structure || !natural_resolution { continue; } - // Degenerate references make NMI uninformative. + // degenerate references make NMI uninformative if case.reference_n_clusters <= 1 || case.reference_n_clusters >= case.reference_membership.len() { @@ -361,8 +342,8 @@ fn partitions_agree_where_structure_is_unambiguous() { ); } -/// Cluster counts should track `leidenalg`'s. This is the user-visible consequence of the -/// resolution parameter meaning the same thing in both libraries. +/// Cluster counts should track `leidenalg`'s — the user-visible consequence of resolution +/// meaning the same thing in both. #[test] fn cluster_counts_track_leidenalg() { let mut failures = Vec::new(); @@ -370,8 +351,7 @@ fn cluster_counts_track_leidenalg() { let labels = run_best(&case, 2); let ours = labels.iter().max().map_or(0, |m| m + 1); let theirs = case.reference_n_clusters; - // Allow a little slack for genuinely ambiguous granularity, but not a factor of two, - // which is exactly what the old resolution bug produced. + // slack for ambiguous granularity, but not the factor of two the old bug gave let tol = 2 + theirs / 5; if ours.abs_diff(theirs) > tol { failures.push(format!("{}: ours {ours}, leidenalg {theirs}", case.name)); diff --git a/tests/spatial_stability.rs b/tests/spatial_stability.rs index 5df7d70..2c64203 100644 --- a/tests/spatial_stability.rs +++ b/tests/spatial_stability.rs @@ -1,28 +1,14 @@ //! Stability and validity of the spatial neighbour graphs. //! -//! The unit tests prove each builder produces the graph it claims to. That is necessary but -//! not sufficient: what matters on real data is whether what you get out survives what real -//! data does to you — cells missed by segmentation, coordinates off by a fraction of a cell, -//! a parameter chosen slightly differently. +//! The unit tests prove each builder makes the graph it claims to. These check the result +//! survives what real data does to you: missed cells, jittered coordinates, a parameter +//! chosen slightly differently. //! -//! # What a bare spatial graph can and cannot do -//! -//! It carries no expression, so the only structure it encodes is spatial: which cells are -//! near which. Two consequences, and both are asserted here. -//! -//! It reliably recovers **physical separation** — detached fragments, tissue masked apart, -//! anything with a real gap. That shows up as connected components, needs no resolution -//! choice, and is stable under every perturbation tried below. -//! -//! It does **not** find boundaries inside continuous tissue. There is nothing for the -//! objective to anchor to, so it returns a tiling whose blob size is set by the resolution. -//! The tiling is spatially contiguous and looks exactly like a result, but it is arbitrary, -//! and therefore unstable: resample and the boundaries move. That is asserted too, so the -//! limitation cannot quietly stop being true. -//! -//! So the resolution-free question — "which cells could possibly be in the same domain" — is -//! the one a spatial graph answers. Choosing among the domains inside a connected region -//! needs expression, which arrives with neighbourhood feature averaging. +//! A bare spatial graph carries no expression, so it recovers **physical separation** — +//! detached fragments, masked tissue, anything with a real gap — as connected components, with +//! no resolution to choose. It does **not** find boundaries inside continuous tissue: there's +//! nothing to anchor to, so you get an arbitrary tiling that looks like a result and moves +//! when you resample. Both are asserted here. mod common; @@ -55,7 +41,7 @@ fn separated_tissue(seed: u64) -> (Vec<[f64; 2]>, Vec) { (pts, truth) } -/// Featureless tissue at one density — nothing for a spatial objective to find. +/// Featureless tissue at one density, so nothing to find. fn homogeneous_tissue(seed: u64) -> Vec<[f64; 2]> { let mut rng = ChaCha8Rng::seed_from_u64(seed); (0..2500) @@ -63,7 +49,7 @@ fn homogeneous_tissue(seed: u64) -> Vec<[f64; 2]> { .collect() } -/// Connected component of each node — the resolution-free structure a spatial graph encodes. +/// Connected component per node — the resolution-free structure a spatial graph encodes. fn components(graph: &CSRNetwork) -> Vec { let n = graph.node_count(); let mut label = vec![usize::MAX; n]; @@ -105,8 +91,7 @@ fn build(name: &str, pts: &[[f64; 2]]) -> CSRNetwork { } } -/// Validity: separated tissue must come back as separate components — exactly, and with no -/// resolution to choose. +/// Separated tissue comes back as separate components, with no resolution to choose. #[test] fn every_builder_separates_disconnected_tissue() { let (pts, truth) = separated_tissue(1); @@ -119,8 +104,7 @@ fn every_builder_separates_disconnected_tissue() { } } -/// Validity: a domain may subdivide an island, but must never span two. That holds at every -/// resolution, which is what makes it the meaningful guarantee. +/// A domain may subdivide an island but must never span two, at any resolution. #[test] fn no_domain_ever_spans_separated_tissue() { let (pts, truth) = separated_tissue(7); @@ -140,7 +124,7 @@ fn no_domain_ever_spans_separated_tissue() { } } -/// Stability: segmentation misses cells, so dropping some must not change the structure. +/// Segmentation misses cells, so dropping some must not change the structure. #[test] fn structure_survives_subsampling() { let (pts, _) = separated_tissue(2); @@ -165,8 +149,7 @@ fn structure_survives_subsampling() { } } -/// Stability: segmentation centroids are not exact, so jitter below cell spacing must not -/// move anything. +/// Centroids aren't exact, so jitter below cell spacing must not move anything. #[test] fn structure_survives_coordinate_jitter() { let (pts, _) = separated_tissue(3); @@ -192,7 +175,7 @@ fn structure_survives_coordinate_jitter() { } } -/// The builders define "neighbour" differently, but must agree about real structure. +/// The builders define "neighbour" differently but must agree about real structure. #[test] fn builders_agree_on_real_structure() { let (pts, _) = separated_tissue(5); @@ -214,8 +197,7 @@ fn builders_agree_on_real_structure() { } } -/// Stability: neighbouring parameter values must give the same structure. A cliff would mean -/// the parameter is load-bearing in a way users cannot reason about. +/// Neighbouring parameter values must give the same structure — no cliffs. #[test] fn parameters_do_not_change_the_structure() { let (pts, truth) = separated_tissue(4); @@ -251,11 +233,8 @@ fn parameters_do_not_change_the_structure() { } } -/// The documented limitation, asserted so it cannot quietly stop being true. -/// -/// On uniform tissue there is nothing spatial to find, so the result is an arbitrary tiling: -/// contiguous, plausible-looking, and not reproducible under resampling. Anyone clustering a -/// bare spatial graph on continuous tissue is reading tea leaves, and this is the evidence. +/// The documented limitation, asserted so it can't quietly stop being true: on uniform tissue +/// the result is an arbitrary tiling that doesn't survive resampling. #[test] fn homogeneous_tissue_gives_an_arbitrary_unstable_tiling() { let pts = homogeneous_tissue(4); @@ -293,7 +272,7 @@ fn homogeneous_tissue_gives_an_arbitrary_unstable_tiling() { ); } -/// Whatever the builder or resolution, a domain must be one connected region of tissue. +/// A domain must be one connected region, whatever the builder or resolution. #[test] fn domains_are_always_spatially_contiguous() { let (pts, _) = separated_tissue(6); @@ -310,7 +289,7 @@ fn domains_are_always_spatially_contiguous() { } } -/// The lattice path: tissue detection masking a band must split the capture area. +/// Masking a band must split the capture area. #[test] fn lattice_masking_splits_the_capture_area_cleanly() { let (mut rows, mut cols, mut truth) = (Vec::new(), Vec::new(), Vec::new()); diff --git a/tests/thread_invariance.rs b/tests/thread_invariance.rs index 485b6a6..3873013 100644 --- a/tests/thread_invariance.rs +++ b/tests/thread_invariance.rs @@ -1,13 +1,11 @@ //! Results must not depend on how the work was divided. //! -//! The single most important test for the parallel path. A staleness bug — a thread reading a -//! community aggregate another thread has already changed — does not crash or produce an -//! obviously wrong answer. It produces a *slightly different* clustering, which looks entirely -//! plausible. Comparing across thread counts is what makes that visible. +//! The one test the parallel path really needs. A staleness bug doesn't crash — it returns a +//! slightly different, entirely plausible clustering, and comparing across thread counts is +//! what makes that visible. //! -//! Runs the same inputs under 1, 2, 4, 8 and 16 rayon threads and demands byte-identical -//! labels. Requires the `parallel` feature to be meaningful, but is written to pass either -//! way so a default build still exercises the comparison logic. +//! Same inputs under 1, 2, 4, 8 and 16 rayon threads, demanding byte-identical labels. Only +//! meaningful with the `parallel` feature, but passes either way. mod common; From bf32d64bad45e9ea52b04f421e1d84be6d3e15bd Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 24 Aug 2026 02:05:15 +0200 Subject: [PATCH 20/20] refactor: one switch for every rayon call `parallel` gated refinement only, while the spatial builders threaded unconditionally - so a default build was parallel for graph construction and sequential for clustering, and there was no way to turn the former off. Now all eight rayon call sites go through `src/par.rs`, and `parallel` is default-on. Nothing regresses: gating spatial behind an off-by-default flag would have cost 2.6-3.2x on construction that users already get. 500k cells default single-threaded knn(6) 271ms 766ms radius(30) 72ms 233ms `default-features = false` now gives a build with no rayon in the tree at all, which wasn't possible before. Caveat: `knn` pulls in hnsw_rs, which threads on its own. Also dropped ndarray's `rayon` feature - nothing used its parallel iterators. The feature must change speed and nothing else, so `examples/feature_parity.rs` fingerprints clustering labels, modularity, and both spatial builders' full CSR including f32 weight bits. CI diffs a sequential run against a parallel one. Currently identical. --- .github/workflows/ci.yml | 9 ++- Cargo.lock | 1 - Cargo.toml | 16 ++--- README.md | 35 ++++++----- examples/feature_parity.rs | 88 ++++++++++++++++++++++++++ src/community_search/leiden/refine.rs | 15 +---- src/lib.rs | 1 + src/neighborhood/mod.rs | 89 +++++++++++++-------------- src/par.rs | 43 +++++++++++++ src/spatial/banksy.rs | 21 +++---- src/spatial/points.rs | 24 +++----- tests/thread_invariance.rs | 3 +- 12 files changed, 233 insertions(+), 112 deletions(-) create mode 100644 examples/feature_parity.rs create mode 100644 src/par.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed73d7f..74d1cf3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,12 +36,19 @@ jobs: - name: Test (release) run: cargo test --no-default-features --release - # must give byte-identical results, so it needs its own run + # `parallel` is on by default, so both halves need their own run - name: Clippy (parallel) run: cargo clippy --no-default-features --features parallel --all-targets -- -D warnings - name: Test (parallel) run: cargo test --no-default-features --features parallel --release + # and the two must agree exactly, or the feature is changing more than speed + - name: Feature parity + run: | + cargo run -q --release --no-default-features --example feature_parity > seq.txt + cargo run -q --release --no-default-features --features parallel --example feature_parity > par.txt + diff seq.txt par.txt + # the #[ignore]d tests: scale runs and the exhaustive optimality sweep, ~11s. Without this # the HD-scale path and the Bell(12) check never run anywhere. scale: diff --git a/Cargo.lock b/Cargo.lock index 4809e56..5ba7955 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -788,7 +788,6 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "rawpointer", - "rayon", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 163998e..d27c446 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,30 +10,32 @@ readme = "README.md" description = "A high-performance network clustering library implementing community detection algorithms like Louvain and Leiden. Features efficient graph representation, abstract grouping systems, and K-NN graph creation from high-dimensional data. Provides parallel computation support via Rayon for handling large networks." [features] -default = ["knn"] +default = ["knn", "parallel"] # kNN graph construction. Split out so the clustering core builds without the HNSW/kd-tree -# stack. Spatial graphs need no feature - the uniform-grid index has no dependencies. +# stack. Spatial graphs need no feature of their own - the grid index has no dependencies. knn = ["dep:hnsw_rs", "dep:kiddo", "dep:ndarray"] -# Multi-threaded refinement. Off until local moving is parallel too, since refinement alone is -# worth about 1.25x. -parallel = [] +# Every rayon call in the crate, behind one switch. Off gives a genuinely single-threaded +# build - except that `knn` drags in hnsw_rs, which threads internally either way. +parallel = ["dep:rayon"] # Shared test fixtures, so unit and integration tests use one copy. Not public API. testdata = [] [dependencies] anyhow = "1.0.100" nalgebra-sparse = "0.10.0" -rayon = "1.10.0" +rayon = { version = "1.10.0", optional = true } single-utilities = "0.8.6" rand = "0.9.0" rand_chacha = { version = "0.9.0" } kiddo = { version = "5.2.2", optional = true } -ndarray = { version = "0.16.1", features = ["rayon"], optional = true } +ndarray = { version = "0.16.1", optional = true } delaunator = "1.1.0" [dev-dependencies] single-clustering = { path = ".", default-features = false, features = ["testdata"] } +# thread_invariance builds its own pools, so it needs rayon even when `parallel` is off +rayon = "1.10.0" serde_json = "1.0" criterion = { version = "0.5", features = ["html_reports"] } diff --git a/README.md b/README.md index f6d43c3..7bedb9f 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,8 @@ pipeline rather than the algorithm. | 500k | 4.0M | 1.113 s | 0.912 s | 1.469 s | 1.32× / **1.61×** | | 1M | 8.0M | 2.568 s | 2.202 s | 3.410 s | 1.33× / **1.55×** | -Single-threaded it is a consistent **1.33×**; with the `parallel` feature, which multi-threads -refinement, **1.55–1.70×**. Modularity is identical to four decimals throughout — the same +Single-threaded it is a consistent **1.33×**; with `parallel` — on by default, and what +multi-threads refinement — **1.55–1.70×**. Modularity is identical to four decimals throughout — the same answer computed faster, not a different tradeoff. Reproduce with `examples/vs_igraph.rs` and `tools/igraph_bench.py`. @@ -112,13 +112,13 @@ Single-threaded scaling on synthetic k-NN graphs: | 3M | 25M | 6.8 s | | 8M | 57M | 20.1 s | -Spatial graph construction: +Spatial graph construction, which `parallel` also covers: -| | | -|---|---| -| Visium HD lattice, 10.5M bins / 21.1M edges | 954 ms, 591 MB | -| 500k cells, k-NN (k=6) | 299 ms | -| 500k cells, radius | 80 ms | +| | default | single-threaded | +|---|---|---| +| Visium HD lattice, 10.5M bins / 21.1M edges | 954 ms, 591 MB | — | +| 500k cells, k-NN (k=6) | 283 ms | 731 ms | +| 500k cells, radius | 73 ms | 233 ms | ## Usage @@ -206,16 +206,19 @@ clustering core: single-clustering = { version = "1.0", default-features = false } ``` -Multi-threaded refinement is behind an off-by-default `parallel` feature. It is off because -local moving — the larger half of the work — is still sequential, so the gain is 1.2-1.3x -rather than the several-x a fully parallel implementation would give: +The default-on `parallel` feature is the single switch for every rayon call in the crate — +refinement, and the spatial graph builders. Turning it off gives a single-threaded build: ```toml -single-clustering = { version = "1.0", features = ["parallel"] } +single-clustering = { version = "1.0", default-features = false, features = ["knn"] } ``` -Results are byte-identical regardless of thread count; `tests/thread_invariance.rs` asserts it -across thread counts, objectives and seeds. +The one caveat is that `knn` pulls in `hnsw_rs`, which threads internally either way. + +Results do not depend on it. `tests/thread_invariance.rs` asserts byte-identical labels across +thread counts, objectives and seeds, and `examples/feature_parity.rs` fingerprints clustering +and both spatial builders so CI can diff a sequential build against a parallel one. The feature +changes speed and nothing else. ## Current status @@ -229,8 +232,8 @@ across thread counts, objectives and seeds. Leiden finds spatial domains - 🚧 **Louvain**: available as `LeidenConfig { refine: false, .. }`; no separate entry point - 🚧 **Benchmarks**: `cargo run --release --example scaling` -- ✅ **Parallel refinement** (`parallel` feature): communities refine independently, so there - is no shared state to race on. 1.2-1.3x, and byte-identical across thread counts +- ✅ **Parallel refinement** (`parallel` feature, on by default): communities refine + independently, so there is no shared state to race on. 1.2-1.3x, byte-identical - ❌ **Parallel local moving**: the other 65% of a pass, and the harder half — it mutates shared community aggregates, which is what the pre-0.7 parallel path got wrong - ❌ **DBSCAN / HDBSCAN**: planned diff --git a/examples/feature_parity.rs b/examples/feature_parity.rs new file mode 100644 index 0000000..077f3f3 --- /dev/null +++ b/examples/feature_parity.rs @@ -0,0 +1,88 @@ +//! Prints a fingerprint of everything the `parallel` feature touches. +//! +//! Run it both ways and diff. Same numbers means the feature changes speed and nothing else. +//! +//! ```text +//! cargo run -q --release --no-default-features --example feature_parity > seq.txt +//! cargo run -q --release --no-default-features --features parallel --example feature_parity > par.txt +//! diff seq.txt par.txt +//! ``` + +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use single_clustering::community_search::leiden::{ + LeidenConfig, ObjectiveKind, leiden, modularity, +}; +use single_clustering::network::CSRNetwork; +use single_clustering::spatial::{SpatialWeight, Symmetry, knn_graph, radius_graph}; + +fn hash(vals: impl Iterator) -> u64 { + let mut h = 0xcbf29ce484222325u64; + for v in vals { + h = (h ^ v).wrapping_mul(0x100000001b3); + } + h +} + +fn main() { + let mut rng = ChaCha8Rng::seed_from_u64(11); + + // clustering: ring lattice + noise + let n = 60_000usize; + let mut edges = Vec::new(); + for v in 0..n { + for d in 1..=5 { + edges.push((v, (v + d) % n, 1.0)); + } + for _ in 0..2 { + edges.push((v, rng.random_range(0..n), 1.0)); + } + } + let g = CSRNetwork::from_edges(n, &edges).unwrap(); + for obj in [ + ObjectiveKind::Rb { resolution: 1.0 }, + ObjectiveKind::Cpm { resolution: 0.05 }, + ] { + for seed in [1u64, 7] { + let c = leiden( + &g, + &LeidenConfig { + objective: obj, + seed: Some(seed), + ..Default::default() + }, + ) + .unwrap(); + println!( + "leiden {obj:?} seed={seed}: k={} labels={:016x} q={:.12}", + c.n_clusters(), + hash(c.labels().iter().map(|&l| l as u64)), + modularity(&g, c.labels(), 1.0) + ); + } + } + + // spatial builders + let pts: Vec<[f64; 2]> = (0..40_000) + .map(|_| [rng.random::() * 500.0, rng.random::() * 500.0]) + .collect(); + for (name, gr) in [ + ( + "knn", + knn_graph(&pts, 8, Symmetry::Union, SpatialWeight::Uniform).unwrap(), + ), + ( + "radius", + radius_graph(&pts, 6.0, SpatialWeight::Gaussian { sigma: 3.0 }, None).unwrap(), + ), + ] { + let (ptrs, nb, w) = gr.to_csr_parts(); + println!( + "{name}: e={} ptrs={:016x} nb={:016x} w={:016x}", + gr.edge_count(), + hash(ptrs.iter().map(|&p| p as u64)), + hash(nb.iter().map(|&x| x as u64)), + hash(w.iter().map(|&x| x.to_bits() as u64)), + ); + } +} diff --git a/src/community_search/leiden/refine.rs b/src/community_search/leiden/refine.rs index c449453..ab779b7 100644 --- a/src/community_search/leiden/refine.rs +++ b/src/community_search/leiden/refine.rs @@ -86,19 +86,8 @@ pub fn refine( ); (sorted, out) }; - let nonempty = members.iter().filter(|m| !m.is_empty()); - - #[cfg(feature = "parallel")] - let refined: Vec<(Vec, Vec)> = { - use rayon::prelude::*; - nonempty - .collect::>() - .into_par_iter() - .map(refine_one) - .collect() - }; - #[cfg(not(feature = "parallel"))] - let refined: Vec<(Vec, Vec)> = nonempty.map(refine_one).collect(); + let nonempty: Vec<&Vec> = members.iter().filter(|m| !m.is_empty()).collect(); + let refined = crate::par::map_range(nonempty.len(), |i| refine_one(nonempty[i])); let mut labels = vec![0u32; n]; for (sorted, out) in refined { diff --git a/src/lib.rs b/src/lib.rs index 9955aba..af541a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub mod error; #[cfg(feature = "knn")] pub mod neighborhood; pub mod network; +pub(crate) mod par; pub mod spatial; #[cfg(any(test, feature = "testdata"))] #[doc(hidden)] diff --git a/src/neighborhood/mod.rs b/src/neighborhood/mod.rs index 2994381..f37e9d4 100644 --- a/src/neighborhood/mod.rs +++ b/src/neighborhood/mod.rs @@ -11,7 +11,6 @@ use hnsw_rs::{ use kiddo::traits::DistanceMetric; use nalgebra_sparse::{CooMatrix, CsrMatrix}; use ndarray::ArrayViewD; -use rayon::prelude::*; use single_utilities::traits::FloatOpsTS; /// Distance and connectivity matrices from a kNN search. @@ -42,15 +41,15 @@ where } // kd-tree hands back squared distances; everything downstream wants real ones - let (indices, distances): (Vec>, Vec>) = (0..n_samples) - .into_par_iter() - .map(|i| { + let (indices, distances): (Vec>, Vec>) = + crate::par::map_range(n_samples, |i| { kdtree .nearest_n::(&point_at::(&data, i), (k + 1) as usize) .into_iter() .map(|h| (h.item as usize, h.distance.sqrt())) .unzip() }) + .into_iter() .unzip(); gaussian_result(n_samples, k, &indices, &distances) @@ -80,10 +79,9 @@ where hnsw.set_extend_candidates(false); hnsw.modify_level_scale(0.5); - let rows: Vec> = (0..n_samples) - .into_par_iter() - .map(|i| (0..n_features).map(|j| data[[i, j]]).collect()) - .collect(); + let rows: Vec> = crate::par::map_range(n_samples, |i| { + (0..n_features).map(|j| data[[i, j]]).collect() + }); let slices: Vec<(&[T], usize)> = rows .iter() .enumerate() @@ -189,50 +187,47 @@ where } } - let sigmas: Vec = distances - .par_iter() - .map(|row| { - let mut nonzero: Vec = row.iter().filter(|&&d| d > T::zero()).copied().collect(); - if nonzero.is_empty() { - return T::one(); - } - let mid = nonzero.len() / 2; - nonzero.select_nth_unstable_by(mid, |a, b| { - a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal) - }); - nonzero[mid] - }) - .collect(); + let sigmas: Vec = crate::par::map_range(distances.len(), |i| { + let mut nonzero: Vec = distances[i] + .iter() + .filter(|&&d| d > T::zero()) + .copied() + .collect(); + if nonzero.is_empty() { + return T::one(); + } + let mid = nonzero.len() / 2; + nonzero.select_nth_unstable_by(mid, |a, b| { + a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal) + }); + nonzero[mid] + }); let min_weight = T::from_f64(1e-14).unwrap(); let two = T::from(2).unwrap(); - let connectivity_triplets: Vec<(usize, usize, T)> = (0..n_samples) - .into_par_iter() - .fold(Vec::new, |mut acc, i| { - // skip(1) drops the self hit; `i <= j` keeps each pair once - for (slot, &j) in indices[i].iter().enumerate().skip(1) { - if i > j { - continue; - } - let d = distances[i][slot]; - let den = sigmas[i] * sigmas[i] + sigmas[j] * sigmas[j]; - if den <= T::zero() { - continue; - } - let weight = (two * sigmas[i] * sigmas[j] / den).sqrt() * (-(d * d) / den).exp(); - if weight > min_weight { - acc.push((i, j, weight)); - if i != j { - acc.push((j, i, weight)); - } + let connectivity_triplets: Vec<(usize, usize, T)> = crate::par::map_range(n_samples, |i| { + let mut out = Vec::new(); + // skip(1) drops the self hit; `i <= j` keeps each pair once + for (slot, &j) in indices[i].iter().enumerate().skip(1) { + if i > j { + continue; + } + let d = distances[i][slot]; + let den = sigmas[i] * sigmas[i] + sigmas[j] * sigmas[j]; + if den <= T::zero() { + continue; + } + let weight = (two * sigmas[i] * sigmas[j] / den).sqrt() * (-(d * d) / den).exp(); + if weight > min_weight { + out.push((i, j, weight)); + if i != j { + out.push((j, i, weight)); } } - acc - }) - .reduce(Vec::new, |mut a, b| { - a.extend(b); - a - }); + } + out + }) + .concat(); Ok(NeighborResult { distances: csr_from_triplets(n_samples, distance_triplets)?, diff --git a/src/par.rs b/src/par.rs new file mode 100644 index 0000000..733f793 --- /dev/null +++ b/src/par.rs @@ -0,0 +1,43 @@ +//! One switch for every rayon call in the crate. +//! +//! Order-preserving either way, so results don't depend on the `parallel` feature or on how +//! many threads it uses. `hnsw_rs` threads internally regardless; that one isn't ours. + +#[cfg(feature = "parallel")] +use rayon::prelude::*; + +/// Maps `0..n`, in parallel when `parallel` is on. +pub(crate) fn map_range(n: usize, f: F) -> Vec +where + U: Send, + F: Fn(usize) -> U + Sync + Send, +{ + #[cfg(feature = "parallel")] + { + (0..n).into_par_iter().map(f).collect() + } + #[cfg(not(feature = "parallel"))] + { + (0..n).map(f).collect() + } +} + +/// Fills `out` one `chunk`-sized row at a time, in parallel when `parallel` is on. +pub(crate) fn fill_chunks(out: &mut [T], chunk: usize, f: F) +where + T: Send, + F: Fn(usize, &mut [T]) + Sync + Send, +{ + #[cfg(feature = "parallel")] + { + out.par_chunks_mut(chunk) + .enumerate() + .for_each(|(i, row)| f(i, row)); + } + #[cfg(not(feature = "parallel"))] + { + out.chunks_mut(chunk) + .enumerate() + .for_each(|(i, row)| f(i, row)); + } +} diff --git a/src/spatial/banksy.rs b/src/spatial/banksy.rs index d2a49d2..fcc4d59 100644 --- a/src/spatial/banksy.rs +++ b/src/spatial/banksy.rs @@ -10,8 +10,6 @@ //! //! The weight matrix is row-normalised and so asymmetric — an operator, not a graph. -use rayon::prelude::*; - use crate::error::{ClusteringError, Result}; use crate::spatial::grid::{Grid, distance_sq}; @@ -91,10 +89,9 @@ impl NeighbourhoodOperator { let grid = Grid::new(coords, typical_spacing(coords, want.max(1))); // sorted by (distance, id) so ties don't depend on visit order - let found: Vec> = coords - .par_iter() - .enumerate() - .map(|(i, p)| { + let found: Vec> = crate::par::map_range(coords.len(), |i| { + let p = &coords[i]; + { let centre = grid.cell_of(p); let mut cand: Vec<(u32, f64)> = Vec::with_capacity(want * 2); for ring in 0..=grid.max_ring(¢re) { @@ -117,8 +114,8 @@ impl NeighbourhoodOperator { cand.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0))); cand.truncate(want); cand - }) - .collect(); + } + }); let mut node_ptrs = Vec::with_capacity(n + 1); node_ptrs.push(0usize); @@ -199,9 +196,8 @@ impl NeighbourhoodOperator { } let mut out = vec![0.0f64; self.n_cells * n_features]; - out.par_chunks_mut(n_features) - .enumerate() - .for_each(|(i, row)| { + crate::par::fill_chunks(&mut out, n_features, |i, row| { + { let span = self.node_ptrs[i]..self.node_ptrs[i + 1]; #[allow(clippy::reversed_empty_ranges)] if m == 0 { @@ -245,7 +241,8 @@ impl NeighbourhoodOperator { *o = (*o * *o + i_acc * i_acc).sqrt(); } } - }); + } + }); Ok(out) } } diff --git a/src/spatial/points.rs b/src/spatial/points.rs index 84bf309..1dc6c0b 100644 --- a/src/spatial/points.rs +++ b/src/spatial/points.rs @@ -7,8 +7,6 @@ //! On Visium, pass [`visium_isometric_coords`](super::visium_isometric_coords) instead of raw //! lattice coordinates. -use rayon::prelude::*; - use crate::error::{ClusteringError, Result}; use crate::network::{CSRNetwork, MAX_NODES}; use crate::spatial::grid::{Grid, distance_sq}; @@ -119,10 +117,9 @@ pub fn radius_graph( let grid = Grid::new(points, radius); let r2 = radius * radius; - let mut adjacency: Vec> = points - .par_iter() - .enumerate() - .map(|(i, p)| { + let mut adjacency: Vec> = crate::par::map_range(points.len(), |i| { + let p = &points[i]; + { let centre = grid.cell_of(p); let reach = (radius / grid.cell_size()).ceil() as usize; let mut found: Vec = Vec::new(); @@ -142,8 +139,8 @@ pub fn radius_graph( found.truncate(cap); } found - }) - .collect(); + } + }); // capping breaks symmetry; without a cap this is a no-op if max_degree.is_some() { @@ -181,10 +178,9 @@ pub fn knn_graph( // a handful of points per cell, so one or two rings usually suffice let grid = Grid::new(points, typical_spacing(points, k)); - let mut adjacency: Vec> = points - .par_iter() - .enumerate() - .map(|(i, p)| { + let mut adjacency: Vec> = crate::par::map_range(points.len(), |i| { + let p = &points[i]; + { let centre = grid.cell_of(p); let limit = grid.max_ring(¢re); let mut found: Vec = Vec::with_capacity(k * 2); @@ -212,8 +208,8 @@ pub fn knn_graph( found.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap().then(a.0.cmp(&b.0))); found.truncate(k); found - }) - .collect(); + } + }); symmetrise(&mut adjacency, symmetry); assemble(adjacency, weight) diff --git a/tests/thread_invariance.rs b/tests/thread_invariance.rs index 3873013..141471a 100644 --- a/tests/thread_invariance.rs +++ b/tests/thread_invariance.rs @@ -5,7 +5,8 @@ //! what makes that visible. //! //! Same inputs under 1, 2, 4, 8 and 16 rayon threads, demanding byte-identical labels. Only -//! meaningful with the `parallel` feature, but passes either way. +//! meaningful with the `parallel` feature, which is on by default; without it the crate +//! ignores thread count entirely and this passes trivially. mod common;